-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
Multiple components throughout the codebase duplicate the same relative time formatting logic (e.g., "5m ago", "2h ago", "3d ago"). This logic is copy-pasted across at least 3 files with slight variations, making it:
- Difficult to maintain (bug fixes must be applied in multiple places)
- Inconsistent (different components may show different formats)
- Harder to internationalize (i18n would need to be added 3+ times)
- Error-prone (easy to miss an update when changing the logic)
Current Code Location
- Files affected:
src/components/dashboard/storefront/editor/version-history-panel.tsx(lines 40-50)src/components/integrations/facebook/messenger-inbox.tsx(lines 120-130)src/components/integrations/facebook/message-thread.tsx(lines 85-95)
- Pattern: Each file contains 10-15 lines of duplicated time calculation logic
- Complexity: Low - Simple utility extraction
Proposed Refactoring
Create a centralized time formatting utility that all components can import and use. This provides a single source of truth for time formatting logic across the application.
Benefits
- Single source of truth - Time formatting logic in one place
- Easier to maintain - Bug fixes and improvements happen once
- Consistent UX - All components show times in the same format
- Easier to internationalize - Add i18n support in one place
- Better testability - Utility function can be thoroughly unit tested
- Reduced code - Remove ~30 lines of duplicated code
Suggested Approach
-
Create a shared utility function in
src/lib/utils/time.ts:/** * Format a date into a human-readable relative time string * `@param` date - Date to format (Date object or ISO string) * `@param` options - Formatting options * `@returns` Formatted string like "5m ago", "2h ago", "3d ago" * * `@example` * formatRelativeTime(new Date()) // "Just now" * formatRelativeTime('2024-02-01T10:00:00Z') // "2h ago" */ export function formatRelativeTime( date: Date | string, options: { justNowThreshold?: number; // milliseconds (default: 60000 = 1 min) maxDays?: number; // show actual date after this many days (default: 7) locale?: string; // for future i18n support } = {} ): string { const { justNowThreshold = 60000, maxDays = 7, } = options; const targetDate = typeof date === 'string' ? new Date(date) : date; const now = new Date(); const diffMs = now.getTime() - targetDate.getTime(); // Just now if (diffMs < justNowThreshold) { return 'Just now'; } // Minutes const diffMins = Math.floor(diffMs / 60000); if (diffMins < 60) { return `\$\{diffMins}m ago`; } // Hours const diffHours = Math.floor(diffMs / 3600000); if (diffHours < 24) { return `\$\{diffHours}h ago`; } // Days const diffDays = Math.floor(diffMs / 86400000); if (diffDays < maxDays) { return `\$\{diffDays}d ago`; } // Fallback to formatted date return targetDate.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: targetDate.getFullYear() !== now.getFullYear() ? 'numeric' : undefined, }); } /** * Calculate time remaining in a 24-hour window * Useful for message response windows, etc. * `@param` date - Starting date * `@returns` Remaining hours or 0 if outside window */ export function calculateTimeWindow(date: Date | string): number { const targetDate = typeof date === 'string' ? new Date(date) : date; const diffMs = Date.now() - targetDate.getTime(); const diffHours = diffMs / (1000 * 60 * 60); const isWithinWindow = diffHours < 24; return isWithinWindow ? Math.floor(24 - diffHours) : 0; }
-
Refactor version-history-panel.tsx:
// BEFORE: const formatRelativeTime = (dateStr: string) => { const date = new Date(dateStr); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMin = Math.floor(diffMs / 60000); const diffHour = Math.floor(diffMs / 3600000); const diffDay = Math.floor(diffMs / 86400000); if (diffMin < 1) return 'Just now'; if (diffMin < 60) return `\$\{diffMin}m ago`; if (diffHour < 24) return `\$\{diffHour}h ago`; if (diffDay < 7) return `\$\{diffDay}d ago`; return date.toLocaleDateString(); }; // AFTER: import { formatRelativeTime } from '@/lib/utils/time'; // Use directly: formatRelativeTime(version.publishedAt)
-
Refactor messenger-inbox.tsx:
// BEFORE: const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'Just now'; if (diffMins < 60) return `\$\{diffMins}m ago`; if (diffHours < 24) return `\$\{diffHours}h ago`; if (diffDays < 7) return `\$\{diffDays}d ago`; return date.toLocaleDateString(); // AFTER: import { formatRelativeTime } from '@/lib/utils/time'; // Use directly in render
-
Refactor message-thread.tsx to use
calculateTimeWindow():// BEFORE: const diffHours = diffMs / (1000 * 60 * 60); const isWithinWindow = diffHours < 24; const remaining = isWithinWindow ? Math.floor(24 - diffHours) : 0; // AFTER: import { calculateTimeWindow } from '@/lib/utils/time'; const remaining = calculateTimeWindow(message.createdAt);
Impact Assessment
- Effort: Low (1-2 hours) - Simple utility extraction and imports
- Risk: Very Low - Pure refactoring, easy to test, no logic changes
- Benefit: Medium - Cleaner code, easier maintenance, consistency
- Priority: Medium - Nice improvement but not critical
Related Files
Other components that might display relative times (check for similar patterns):
src/components/user-notification-bell.tsxsrc/components/admin/notifications-list.tsxsrc/components/admin/notification-bell.tsx- Any audit log or activity feed components
Testing Strategy
-
Create unit tests for
formatRelativeTime():describe('formatRelativeTime', () => { it('shows "Just now" for very recent times', () => { const now = new Date(); expect(formatRelativeTime(now)).toBe('Just now'); }); it('shows minutes for times < 1 hour ago', () => { const date = new Date(Date.now() - 30 * 60000); expect(formatRelativeTime(date)).toBe('30m ago'); }); it('shows hours for times < 24 hours ago', () => { const date = new Date(Date.now() - 5 * 3600000); expect(formatRelativeTime(date)).toBe('5h ago'); }); it('shows days for times < 7 days ago', () => { const date = new Date(Date.now() - 3 * 86400000); expect(formatRelativeTime(date)).toBe('3d ago'); }); it('shows formatted date for times > 7 days ago', () => { const date = new Date(Date.now() - 10 * 86400000); expect(formatRelativeTime(date)).toMatch(/[A-Z][a-z]{2} \d{1,2}/); }); });
-
Visual regression testing:
- Version history panel shows correct relative times
- Messenger inbox shows correct message times
- Message thread shows correct response window
-
Manual testing:
- Check all affected components render correctly
- Verify time formats are consistent across the app
Success Metrics
- ✅ Time formatting logic centralized in
src/lib/utils/time.ts - ✅ All 3+ affected components use the shared utility
- ✅ ~30 lines of duplicated code removed
- ✅ Unit tests achieve 100% coverage of time utility
- ✅ Consistent time formatting across all components
- ✅ Future i18n support is easier to implement
AI generated by Daily Codebase Analyzer - Semantic Function Extraction & Refactoring
- expires on Feb 28, 2026, 1:41 PM UTC
Metadata
Metadata
Assignees
Type
Projects
Status