Description
Two sibling components in the same feature area each implement their own "time ago" formatter instead of sharing one. src/features/maintainers/components/issues/IssuesTab.tsx uses the already-installed date-fns package ("date-fns": "3.6.0" in package.json):
const formatTimeAgo = useCallback((dateString: string | null): string => {
if (!dateString) { ... return 'Unknown' }
try {
const date = new Date(dateString)
if (isNaN(date.getTime())) { ... return 'Unknown' }
return formatDistanceToNow(date, { addSuffix: true })
} catch (err) { ... return 'Unknown' }
}, [])
src/features/maintainers/components/dashboard/DashboardTab.tsx, in the same features/maintainers area, instead hand-rolls the same concept with its own bucket math:
const formatTimeAgo = useCallback((date: Date): string => {
const timeMs = date.getTime()
if (isNaN(timeMs)) { return 'unknown time' }
const now = new Date()
const diffMs = now.getTime() - timeMs
const diffMins = Math.floor(diffMs / 60000)
const diffHours = Math.floor(diffMs / 3600000)
const diffDays = Math.floor(diffMs / 86400000)
const diffMonths = Math.floor(diffDays / 30)
if (diffMins < 1) return 'just now'
if (diffMins < 60) return `${diffMins} minute${diffMins !== 1 ? 's' : ''} ago`
if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`
if (diffDays < 30) return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`
return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`
}, [])
Besides the duplication, DashboardTab's version has no "years ago" bucket at all — diffMonths just keeps growing past 12 (e.g. an 800-day-old activity item renders as "26 months ago" instead of the far more readable "2 years ago" that date-fns's formatDistanceToNow would produce, and which IssuesTab.tsx already gets for free). It also takes a Date while IssuesTab.tsx's version takes a string | null and has its own Unknown/error-handling conventions — two incompatible signatures for the same conceptual helper in the same feature.
Requirements
- Replace
DashboardTab.tsx's hand-rolled formatTimeAgo with date-fns's formatDistanceToNow (matching IssuesTab.tsx's usage), or extract one shared helper both files import.
- Preserve the existing invalid-date fallback behavior (
'unknown time' / 'Unknown' — pick one consistent string) in the consolidated version.
Suggested execution
- Fork the repo and create a branch:
git checkout -b fix/dashboardtab-formattimeago-datefns
- Extract a single shared
formatTimeAgo helper (e.g. under src/shared/utils/) built on date-fns's formatDistanceToNow, accepting the same input shape both call sites need.
- Update
DashboardTab.tsx and IssuesTab.tsx to both import the shared helper, removing their local copies.
- Add a test asserting an ~800-day-old timestamp renders using a "years" bucket rather than an ever-growing months count.
Example commit message
fix: replace DashboardTab's hand-rolled formatTimeAgo with the shared date-fns formatter
Acceptance criteria
Security notes
None; this is a duplication/correctness issue with no security surface.
Guidelines
- Minimum 95% test coverage
- Timeframe: 96 hours
Description
Two sibling components in the same feature area each implement their own "time ago" formatter instead of sharing one.
src/features/maintainers/components/issues/IssuesTab.tsxuses the already-installeddate-fnspackage ("date-fns": "3.6.0"inpackage.json):src/features/maintainers/components/dashboard/DashboardTab.tsx, in the samefeatures/maintainersarea, instead hand-rolls the same concept with its own bucket math:Besides the duplication,
DashboardTab's version has no "years ago" bucket at all —diffMonthsjust keeps growing past 12 (e.g. an 800-day-old activity item renders as"26 months ago"instead of the far more readable"2 years ago"thatdate-fns'sformatDistanceToNowwould produce, and whichIssuesTab.tsxalready gets for free). It also takes aDatewhileIssuesTab.tsx's version takes astring | nulland has its ownUnknown/error-handling conventions — two incompatible signatures for the same conceptual helper in the same feature.Requirements
DashboardTab.tsx's hand-rolledformatTimeAgowithdate-fns'sformatDistanceToNow(matchingIssuesTab.tsx's usage), or extract one shared helper both files import.'unknown time'/'Unknown'— pick one consistent string) in the consolidated version.Suggested execution
git checkout -b fix/dashboardtab-formattimeago-datefnsformatTimeAgohelper (e.g. undersrc/shared/utils/) built ondate-fns'sformatDistanceToNow, accepting the same input shape both call sites need.DashboardTab.tsxandIssuesTab.tsxto both import the shared helper, removing their local copies.Example commit message
Acceptance criteria
DashboardTab.tsxandIssuesTab.tsxshare oneformatTimeAgoimplementation built ondate-fns.Security notes
None; this is a duplication/correctness issue with no security surface.
Guidelines