1const rtf = new Intl.RelativeTimeFormat(navigator.language, { numeric: 'auto' }); 2 3const dateFormatterSameYear = new Intl.DateTimeFormat(navigator.language, { 4 month: 'long', 5 day: 'numeric' 6}); 7 8const dateFormatterOtherYear = new Intl.DateTimeFormat(navigator.language, { 9 month: 'long', 10 day: 'numeric', 11 year: 'numeric' 12}); 13 14/** 15 * Classify a timestamp into today / yesterday / older, 16 * using the browser's local timezone for day boundaries. 17 */ 18export function classifyConversation(isoTimestamp) { 19 const then = new Date(isoTimestamp); 20 const now = new Date(); 21 22 // Midnight local time today 23 const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()); 24 const startOfYesterday = new Date(startOfToday); 25 startOfYesterday.setDate(startOfYesterday.getDate() - 1); 26 27 if (then >= startOfToday) return 'today'; 28 if (then >= startOfYesterday) return 'yesterday'; 29 return 'older'; 30} 31 32/** 33 * Format a timestamp for display in the conversation list. 34 * - today/yesterday â relative ("5 minutes ago", "3 hours ago") 35 * - older â localized date ("Mar 15" or "Mar 15, 2024") 36 */ 37export function formatConversationTime(isoTimestamp) { 38 const then = new Date(isoTimestamp); 39 const bucket = classifyConversation(isoTimestamp); 40 41 if (bucket === 'older') { 42 const now = new Date(); 43 const formatter = then.getFullYear() === now.getFullYear() 44 ? dateFormatterSameYear 45 : dateFormatterOtherYear; 46 return formatter.format(then); 47 } 48 49 // today or yesterday â relative time 50 const diffSec = (then - Date.now()) / 1000; // negative for past 51 const absSec = Math.abs(diffSec); 52 53 if (absSec < 45) return rtf.format(Math.round(diffSec), 'second'); 54 if (absSec < 3600) return rtf.format(Math.round(diffSec / 60), 'minute'); 55 if (absSec < 86400) return rtf.format(Math.round(diffSec / 3600), 'hour'); 56 // yesterday bucket, more than 24h ago 57 return rtf.format(Math.round(diffSec / 3600), 'hour'); 58} 59 60/** 61 * Group a list of conversations into today/yesterday/older buckets, 62 * preserving order within each bucket. 63 */ 64export function groupConversations(conversations, getTimestamp = c => c.updatedAt) { 65 const groups = { today: [], yesterday: [], older: [] }; 66 for (const conv of conversations) { 67 groups[classifyConversation(getTimestamp(conv))].push(conv); 68 } 69 return groups; 70}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.