export type TWUIRecencyGroup = { label: string; items: T[]; }; const DAY = 24 * 60 * 60 * 1000; /** * # Group by recency * Buckets items into "Today", "Yesterday", "Previous 7 days", * "Previous 30 days" and then by month, newest first - the grouping chat * apps use for conversation lists. Empty groups are left out. */ export default function twuiGroupByRecency( items: T[], getTime: (item: T) => number, now: number = Date.now(), ): TWUIRecencyGroup[] { const startOfToday = new Date(now); startOfToday.setHours(0, 0, 0, 0); const today = startOfToday.getTime(); const groups = new Map(); const label = (time: number) => { if (time >= today) return "Today"; if (time >= today - DAY) return "Yesterday"; if (time >= today - 7 * DAY) return "Previous 7 days"; if (time >= today - 30 * DAY) return "Previous 30 days"; return new Date(time).toLocaleDateString(undefined, { month: "long", year: "numeric", }); }; [...items] .sort((a, b) => getTime(b) - getTime(a)) .forEach((item) => { const key = label(getTime(item)); const list = groups.get(key); if (list) list.push(item); else groups.set(key, [item]); }); return Array.from(groups, ([label, items]) => ({ label, items })); }