mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-05 08:10:39 +00:00
Rename directories (arc-web → fabro-web, arc-api-client → fabro-api-client), update package names, import paths, TS-only identifiers (theme key, session cookie, demo cookie, OAuth state, db filename, mock data), and supporting files (Dockerfile, docker-compose, entrypoint, CI workflow, CLAUDE.md). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
67 lines
2.1 KiB
TypeScript
67 lines
2.1 KiB
TypeScript
function relativeTime(seconds: number, past: boolean): string {
|
|
if (seconds < 60) return past ? "just now" : "in <1m";
|
|
const minutes = Math.floor(seconds / 60);
|
|
if (minutes < 60) return past ? `${minutes}m ago` : `in ${minutes}m`;
|
|
const hours = Math.floor(minutes / 60);
|
|
if (hours < 24) return past ? `${hours}h ago` : `in ${hours}h`;
|
|
const days = Math.floor(hours / 24);
|
|
return past ? `${days}d ago` : `in ${days}d`;
|
|
}
|
|
|
|
/**
|
|
* Format an ISO 8601 timestamp as a relative past time string (e.g. "2h ago", "3d ago").
|
|
*/
|
|
export function timeAgo(iso: string): string {
|
|
return relativeTime(Math.floor((Date.now() - new Date(iso).getTime()) / 1000), true);
|
|
}
|
|
|
|
/**
|
|
* Format an ISO 8601 timestamp as a relative future time string (e.g. "in 2h", "in 3d").
|
|
*/
|
|
export function timeUntil(iso: string): string {
|
|
return relativeTime(Math.floor((new Date(iso).getTime() - Date.now()) / 1000), false);
|
|
}
|
|
|
|
/**
|
|
* Return a human-readable date label for grouping (e.g. "Today", "Yesterday", "Previous 7 days").
|
|
*/
|
|
function dateLabel(iso: string): string {
|
|
const now = new Date();
|
|
const date = new Date(iso);
|
|
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
const startOfYesterday = new Date(startOfToday.getTime() - 86_400_000);
|
|
const startOf7DaysAgo = new Date(startOfToday.getTime() - 7 * 86_400_000);
|
|
|
|
if (date >= startOfToday) return "Today";
|
|
if (date >= startOfYesterday) return "Yesterday";
|
|
if (date >= startOf7DaysAgo) return "Previous 7 days";
|
|
return "Older";
|
|
}
|
|
|
|
interface SessionItem {
|
|
id: string;
|
|
title: string;
|
|
created_at: string;
|
|
}
|
|
|
|
interface SessionGroup {
|
|
label: string;
|
|
sessions: SessionItem[];
|
|
}
|
|
|
|
/**
|
|
* Group a flat list of sessions (already sorted newest-first) into date-labeled groups.
|
|
*/
|
|
export function groupSessionsByDate(sessions: SessionItem[]): SessionGroup[] {
|
|
const groups: SessionGroup[] = [];
|
|
let current: SessionGroup | undefined;
|
|
for (const s of sessions) {
|
|
const label = dateLabel(s.created_at);
|
|
if (!current || current.label !== label) {
|
|
current = { label, sessions: [] };
|
|
groups.push(current);
|
|
}
|
|
current.sessions.push(s);
|
|
}
|
|
return groups;
|
|
}
|