Skip to content

Commit

Permalink
Enhance/collection alphabetical sorting (#1140)
Browse files Browse the repository at this point in the history
* refactor: extract getCollectionItems to separate utility file

* fix: use getTime() for comparison

* improve title sorting with localeCompare

* test: update expected number of occurrences in Collection story

* add check for both date undefined

* fix test: Update expected number of occurrences in Collection story
  • Loading branch information
adriangohjw authored Feb 26, 2025
1 parent b901e38 commit b384d04
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 104 deletions.
Original file line number Diff line number Diff line change
@@ -1,117 +1,19 @@
import type { Exact } from "type-fest"
import capitalize from "lodash/capitalize"

import type { CollectionPageSchemaType, IsomerSiteProps } from "~/engine"
import type { CollectionPageSchemaType } from "~/engine"
import type { AllCardProps, ProcessedCollectionCardProps } from "~/interfaces"
import {
getBreadcrumbFromSiteMap,
getParsedDate,
getReferenceLinkHref,
getSitemapAsArray,
isExternalUrl,
} from "~/utils"
import { Skeleton } from "../Skeleton"
import CollectionClient from "./CollectionClient"
import { getAvailableFilters, shouldShowDate } from "./utils"

const CATEGORY_OTHERS = "Others"

const getCollectionItems = (
site: IsomerSiteProps,
permalink: string,
): AllCardProps[] => {
let currSitemap = site.siteMap
const permalinkParts = permalink.split("/")

for (let i = 2; i <= permalinkParts.length; i++) {
const currPermalink = permalinkParts.slice(0, i).join("/")

if (!currSitemap.children) {
return []
}

const child = currSitemap.children.find(
(child) => child.permalink === currPermalink,
)

if (!child) {
return []
}

currSitemap = child
}

if (!currSitemap.children) {
return []
}

const items = currSitemap.children.flatMap((child) =>
getSitemapAsArray(child),
)

const transformedItems = items
.filter(
(item) =>
item.layout === "file" ||
item.layout === "link" ||
item.layout === "article",
)
.map((item) => {
const date =
item.date !== undefined ? getParsedDate(item.date) : undefined

const baseItem = {
type: "collectionCard" as const,
rawDate: date,
lastUpdated: date?.toISOString(),
category: item.category || CATEGORY_OTHERS,
title: item.title,
description: item.summary,
image: item.image,
site,
tags: item.tags,
}

if (item.layout === "file") {
return {
...baseItem,
variant: "file",
url: item.ref,
fileDetails: item.fileDetails,
}
} else if (item.layout === "link") {
return {
...baseItem,
variant: "link",
url: item.ref,
}
}

return {
...baseItem,
variant: "article",
url: item.permalink,
}
}) satisfies AllCardProps[]

return transformedItems.sort((a, b) => {
// Sort by last updated date, tiebreaker by title
if (a.rawDate === b.rawDate) {
return a.title > b.title ? 1 : -1
}

// Rank items with no dates last
if (a.rawDate === undefined) {
return 1
}

if (b.rawDate === undefined) {
return -1
}

return a.rawDate < b.rawDate ? 1 : -1
}) as AllCardProps[]
}
import {
getAvailableFilters,
getCollectionItems,
shouldShowDate,
} from "./utils"

const processedCollectionItems = (
items: AllCardProps[],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import type { IsomerSiteProps } from "~/engine"
import type { AllCardProps } from "~/interfaces"
import { getParsedDate, getSitemapAsArray } from "~/utils"

const CATEGORY_OTHERS = "Others"

export const getCollectionItems = (
site: IsomerSiteProps,
permalink: string,
): AllCardProps[] => {
let currSitemap = site.siteMap
const permalinkParts = permalink.split("/")

for (let i = 2; i <= permalinkParts.length; i++) {
const currPermalink = permalinkParts.slice(0, i).join("/")

if (!currSitemap.children) {
return []
}

const child = currSitemap.children.find(
(child) => child.permalink === currPermalink,
)

if (!child) {
return []
}

currSitemap = child
}

if (!currSitemap.children) {
return []
}

const items = currSitemap.children.flatMap((child) =>
getSitemapAsArray(child),
)

const transformedItems = items
.filter(
(item) =>
item.layout === "file" ||
item.layout === "link" ||
item.layout === "article",
)
.map((item) => {
const date =
item.date !== undefined ? getParsedDate(item.date) : undefined

const baseItem = {
type: "collectionCard" as const,
rawDate: date,
lastUpdated: date?.toISOString(),
category: item.category || CATEGORY_OTHERS,
title: item.title,
description: item.summary,
image: item.image,
site,
tags: item.tags,
}

if (item.layout === "file") {
return {
...baseItem,
variant: "file",
url: item.ref,
fileDetails: item.fileDetails,
}
} else if (item.layout === "link") {
return {
...baseItem,
variant: "link",
url: item.ref,
}
}

return {
...baseItem,
variant: "article",
url: item.permalink,
}
}) satisfies AllCardProps[]

return transformedItems.sort((a, b) => {
// Sort by last updated date, tiebreaker by title
if (a.rawDate && b.rawDate && a.rawDate.getTime() === b.rawDate.getTime()) {
// localeCompare better than > operator as
// it properly handles international and special characters
return a.title.localeCompare(b.title)
}

// If both items have no dates, sort by title
if (a.rawDate === undefined && b.rawDate === undefined) {
return a.title.localeCompare(b.title)
}

// Rank items with no dates last
if (a.rawDate === undefined) {
return 1
}

if (b.rawDate === undefined) {
return -1
}

return a.rawDate.getTime() < b.rawDate.getTime() ? 1 : -1
}) as AllCardProps[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./getFilteredItems"
export * from "./getPaginatedItems"
export * from "./updateAppliedFilters"
export * from "./shouldShowDate"
export * from "./getCollectionItems"

0 comments on commit b384d04

Please sign in to comment.