From 92921759764e16f3907bafacfcb313a0fff20cef Mon Sep 17 00:00:00 2001 From: Eugene Toder Date: Wed, 18 Feb 2026 15:35:19 -0500 Subject: [PATCH] Replace moment with date-fns --- package-lock.json | 32 ++++++++++++++++++++------------ package.json | 3 ++- src/components/ElapsedTime.js | 7 +++++-- src/hooks/useMoment.js | 8 ++------ src/util.js | 12 ++++++------ src/util.test.js | 24 ++++++++++++++++++++++-- 6 files changed, 57 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index b7640ab..f0e816b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "setwithfriends", + "name": "setwithforks", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "setwithfriends", + "name": "setwithforks", "version": "1.0.0", "license": "MIT", "dependencies": { @@ -15,8 +15,9 @@ "@stripe/stripe-js": "^1.25.0", "chart.js": "^3.7.1", "clsx": "^1.1.1", + "date-fns": "^4.1.0", "firebase": "^9.6.9", - "moment": "^2.29.1", + "format-duration": "^3.0.2", "obscenity": "^0.4.4", "project-name-generator": "^2.1.9", "react": "^17.0.2", @@ -7604,6 +7605,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.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -9591,6 +9602,12 @@ "node": ">= 6" } }, + "node_modules/format-duration": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/format-duration/-/format-duration-3.0.2.tgz", + "integrity": "sha512-pKzJDSRgK2lqAiPW3uizDaIJaJnataZclsahz25UMwfdryBGDa+1HlbXGjzpMvX/2kMh4O0sNevFXKaEfCjHsA==", + "license": "ISC" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -13147,15 +13164,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 76abe09..e7761ef 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,9 @@ "@stripe/stripe-js": "^1.25.0", "chart.js": "^3.7.1", "clsx": "^1.1.1", + "date-fns": "^4.1.0", "firebase": "^9.6.9", - "moment": "^2.29.1", + "format-duration": "^3.0.2", "obscenity": "^0.4.4", "project-name-generator": "^2.1.9", "react": "^17.0.2", diff --git a/src/components/ElapsedTime.js b/src/components/ElapsedTime.js index b59adbb..87f825a 100644 --- a/src/components/ElapsedTime.js +++ b/src/components/ElapsedTime.js @@ -1,9 +1,12 @@ +import formatDistanceStrict from "date-fns/formatDistanceStrict"; + import useMoment from "../hooks/useMoment"; // Wrapper around useMoment, since state hooks cause rerender of component function ElapsedTime({ value }) { - const time = useMoment(); - return <>{time.to(value)}; + const time = useMoment(5000); + const opts = { addSuffix: true }; + return <>{formatDistanceStrict(value, time, opts)}; } export default ElapsedTime; diff --git a/src/hooks/useMoment.js b/src/hooks/useMoment.js index c3aae4b..0a6e48c 100644 --- a/src/hooks/useMoment.js +++ b/src/hooks/useMoment.js @@ -1,18 +1,14 @@ -import moment from "moment"; import { useEffect, useState } from "react"; import useFirebaseRef from "./useFirebaseRef"; function useMoment(delay = 1000) { - const [time, setTime] = useState(moment()); // Estimated firebase server time + const [time, setTime] = useState(Date.now()); // Estimated firebase server time const [offset] = useFirebaseRef(".info/serverTimeOffset"); useEffect(() => { if (!delay) return; - - const id = setInterval(() => { - setTime(moment(Date.now() + offset)); - }, delay); + const id = setInterval(() => setTime(Date.now() + offset), delay); return () => clearInterval(id); }, [offset, delay]); diff --git a/src/util.js b/src/util.js index 17911be..51b7d27 100644 --- a/src/util.js +++ b/src/util.js @@ -1,4 +1,4 @@ -import moment from "moment"; +import formatDuration from "format-duration"; import { RegExpMatcher, TextCensor, @@ -196,11 +196,11 @@ export function generateName() { } export function formatTime(t, hideSubsecond) { - t = Math.max(t, 0); - const hours = Math.floor(t / (3600 * 1000)); - const rest = t % (3600 * 1000); - const format = hideSubsecond ? "mm:ss" : "mm:ss.SS"; - return (hours ? `${hours}:` : "") + moment.utc(rest).format(format); + const res = formatDuration(Math.max(t, 0), { + leading: true, + ms: !hideSubsecond, + }); + return hideSubsecond ? res : res.slice(0, -1); } export function formatCount(count, singular, plural = null) { diff --git a/src/util.test.js b/src/util.test.js index 2ca54e8..201e0b6 100644 --- a/src/util.test.js +++ b/src/util.test.js @@ -1,4 +1,4 @@ -import { badWords, formatANoun, parseDuration } from "./util"; +import { badWords, formatANoun, formatTime, parseDuration } from "./util"; describe("bad words filter", () => { it("sort of works", () => { @@ -18,7 +18,7 @@ describe("bad words filter", () => { }); }); -it("parseDuration works", () => { +it("formatANoun works", () => { expect(formatANoun("Set")).toBe("a Set"); expect(formatANoun("UltraSet")).toBe("an UltraSet"); expect(formatANoun("GhostSet")).toBe("a GhostSet"); @@ -37,3 +37,23 @@ it("parseDuration works", () => { expect(parseDuration("300")).toBe(null); expect(parseDuration("")).toBe(null); }); + +it("formatTime works", () => { + const check = (ms, expected) => { + expect(formatTime(ms)).toBe(expected); + expect(formatTime(ms, true)).toBe(expected.slice(0, -3)); + }; + check(-12345, "00:00.00"); + check(0, "00:00.00"); + check(999, "00:00.99"); + check(12349, "00:12.34"); + check(59999, "00:59.99"); + check(123000, "02:03.00"); + check(123459, "02:03.45"); + check(1234599, "20:34.59"); + check(3599999, "59:59.99"); + check(3600000, "01:00:00.00"); + check(3725669, "01:02:05.66"); + check(37256699, "10:20:56.69"); + check(372566999, "4:07:29:26.99"); +});