diff --git a/app/components/ReleaseTable.tsx b/app/components/ReleaseTable.tsx index 7fa48b3..aeef99b 100644 --- a/app/components/ReleaseTable.tsx +++ b/app/components/ReleaseTable.tsx @@ -1,6 +1,7 @@ import { Link } from '@remix-run/react'; +import { formatDistance } from 'date-fns'; import { ElectronRelease } from '~/data/release-data'; -import { humanFriendlyDaysSince, prettyReleaseDate } from '~/helpers/time'; +import { prettyDateString, prettyReleaseDate } from '~/helpers/time'; type ReleaseTableProps = { releases: (ElectronRelease | undefined)[]; @@ -91,10 +92,16 @@ export const ReleaseTable = ({ prefetch="intent" > - {humanFriendlyDaysSince(release)} - + {prettyReleaseDate(release, timeZone)} + + {release.fullDate + ? formatDistance(release.fullDate, Date.now(), { + addSuffix: true, + }) + : ''} + diff --git a/app/helpers/time.test.ts b/app/helpers/time.test.ts index f686e7b..3ccb8f7 100644 --- a/app/helpers/time.test.ts +++ b/app/helpers/time.test.ts @@ -1,73 +1,5 @@ import { describe, expect, test } from 'vitest'; -import { humanFriendlyDaysSince, prettyDateString, prettyReleaseDate } from './time'; - -describe('humanFriendlyDaysSince', () => { - test('should return "Today" for today\'s date', () => { - expect( - humanFriendlyDaysSince( - { fullDate: '2020-02-02T00:00:00Z' }, - new Date('2020-02-02T00:00:00Z'), - ), - ).toBe('Today'); - }); - - test('should return "Yesterday" for yesterday\'s date', () => { - expect( - humanFriendlyDaysSince( - { fullDate: '2020-02-01T00:00:00Z' }, - new Date('2020-02-02T00:00:00Z'), - ), - ).toBe('Yesterday'); - }); - - test('should return "N days ago" for dates in the past', () => { - expect( - humanFriendlyDaysSince( - { fullDate: '2020-01-30T00:00:00Z' }, - new Date('2020-02-02T00:00:00Z'), - ), - ).toBe('3 days ago'); - expect( - humanFriendlyDaysSince( - { fullDate: '2020-01-31T00:00:00Z' }, - new Date('2020-02-02T00:00:00Z'), - ), - ).toBe('2 days ago'); - }); - - test('should return "N days ago" for dates in the past over month boundaries', () => { - expect( - humanFriendlyDaysSince( - { fullDate: '2020-01-30T00:00:00Z' }, - new Date('2020-03-02T00:00:00Z'), - ), - ).toBe('32 days ago'); - expect( - humanFriendlyDaysSince( - { fullDate: '2020-01-31T00:00:00Z' }, - new Date('2020-03-02T00:00:00Z'), - ), - ).toBe('31 days ago'); - }); - - test('should return "Tomorrow" for tomorrow', () => { - expect( - humanFriendlyDaysSince( - { fullDate: '2020-03-04T00:00:00Z' }, - new Date('2020-03-03T00:00:00Z'), - ), - ).toBe('Tomorrow'); - }); - - test('should return "N days in the future" for dates in the future', () => { - expect( - humanFriendlyDaysSince( - { fullDate: '2020-03-04T00:00:00Z' }, - new Date('2020-02-01T00:00:00Z'), - ), - ).toBe('32 days in the future'); - }); -}); +import { prettyDateString, prettyReleaseDate } from './time'; describe('prettyReleaseDate', () => { test('should format date correctly', () => { diff --git a/app/helpers/time.ts b/app/helpers/time.ts index 841ee88..acc3e0a 100644 --- a/app/helpers/time.ts +++ b/app/helpers/time.ts @@ -1,25 +1,5 @@ import { ElectronRelease } from '~/data/release-data'; -/** - * @param date A date string from an ElectronRelease, or any date string in the format - * YYYY-MM-DD - * @returns A human friendly string describing how many days ago the date was - */ -export const humanFriendlyDaysSince = ( - release: Pick, - currentDate = new Date(), -) => { - const releaseDate = new Date(release.fullDate); - const daysAgo = Math.floor( - (currentDate.getTime() - releaseDate.getTime()) / (1_000 * 60 * 60 * 24), - ); - if (daysAgo === 0) return 'Today'; - if (daysAgo === 1) return 'Yesterday'; - if (daysAgo === -1) return 'Tomorrow'; - if (daysAgo < 0) return `${-daysAgo} days in the future`; - return `${daysAgo} days ago`; -}; - /** * This function requires a timezone, do not call it from inside a memoized or cached * data function. Return a date string from those functions and in the loader apply diff --git a/package-lock.json b/package-lock.json index 6a28fd4..a7247f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@remix-run/serve": "^2.16.5", "cookie": "^1.0.2", "cross-env": "^7.0.3", + "date-fns": "^4.1.0", "dompurify": "^3.2.5", "geoip-lite": "^1.4.10", "isbot": "^5.1.26", @@ -5574,6 +5575,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", diff --git a/package.json b/package.json index 79af1bb..0d0d927 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@remix-run/serve": "^2.16.5", "cookie": "^1.0.2", "cross-env": "^7.0.3", + "date-fns": "^4.1.0", "dompurify": "^3.2.5", "geoip-lite": "^1.4.10", "isbot": "^5.1.26",