From 0265b0e350894b248627bf73426935bb9129d41f Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Fri, 18 Oct 2024 07:19:16 +0200 Subject: [PATCH 1/5] Draft: try with and without locale. --- ui/helpers/countdown.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/ui/helpers/countdown.ts b/ui/helpers/countdown.ts index 62d86f77..b4a35d01 100644 --- a/ui/helpers/countdown.ts +++ b/ui/helpers/countdown.ts @@ -10,14 +10,21 @@ export const formatDeadline = (time: number): string => { unit = "hour"; } const isLastMinute = unit === "minute" && timeLeft < 2; - const formattedTimeLeft = new Intl.NumberFormat(LOCALE, { - style: "unit", - unitDisplay: "long", - minimumFractionDigits: isLastMinute ? 1 : 0, - maximumFractionDigits: isLastMinute ? 1 : 0, - unit, - }).format(Math.max(0, timeLeft)); - return `in ${formattedTimeLeft}`; + for (const locale of [LOCALE, undefined]) { + try { + const formattedTimeLeft = new Intl.NumberFormat(locale, { + style: "unit", + unitDisplay: "long", + minimumFractionDigits: isLastMinute ? 1 : 0, + maximumFractionDigits: isLastMinute ? 1 : 0, + unit, + }).format(Math.max(0, timeLeft)); + return `in ${formattedTimeLeft}`; + } catch (error) { + console.warn(`Failed to format time using ${locale} locale`, error); + } + } + return `in ${time} seconds`; }; export const getCountdownDelay = (deadline: number): number => From f9a26f594fa12b0a50345186d7eb24ca61b6636d Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Fri, 18 Oct 2024 07:40:13 +0200 Subject: [PATCH 2/5] Adjusting implementation and testing it. --- ui/helpers/countdown.spec.ts | 24 ++++++++++++++++++++++++ ui/helpers/countdown.ts | 9 ++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/ui/helpers/countdown.spec.ts b/ui/helpers/countdown.spec.ts index cf0c7dd3..5d33e9da 100644 --- a/ui/helpers/countdown.spec.ts +++ b/ui/helpers/countdown.spec.ts @@ -46,6 +46,30 @@ describe("Countdown helpers", () => { expect(formatDeadline(Date.now() + offset * 1000)).toMatchSnapshot(); }, ); + + test.each([ + [10000, "10 seconds"], + [60000, "1 minute"], + ])(`should handle invalid locales %#`, (offset, label) => { + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + expect( + formatDeadline(Date.now() + offset, [ + "invalid_locale_id", + "another_invalid_one", + ]), + ).toBe(`in ${label}`); + expect(warnSpy).toHaveBeenCalledTimes(2); + expect(warnSpy.mock.calls).toEqual([ + [ + "Failed to format time using invalid_locale_id locale", + expect.any(Error), + ], + [ + "Failed to format time using another_invalid_one locale", + expect.any(Error), + ], + ]); + }); }); describe("getCountdownDelay() helper", () => { diff --git a/ui/helpers/countdown.ts b/ui/helpers/countdown.ts index b4a35d01..d7eebf8e 100644 --- a/ui/helpers/countdown.ts +++ b/ui/helpers/countdown.ts @@ -1,4 +1,7 @@ -export const formatDeadline = (time: number): string => { +export const formatDeadline = ( + time: number, + locales = [LOCALE, undefined], +): string => { let unit: "second" | "minute" | "hour" = "second"; let timeLeft = (time - Date.now()) / 1000; if (timeLeft >= 60) { @@ -10,7 +13,7 @@ export const formatDeadline = (time: number): string => { unit = "hour"; } const isLastMinute = unit === "minute" && timeLeft < 2; - for (const locale of [LOCALE, undefined]) { + for (const locale of locales) { try { const formattedTimeLeft = new Intl.NumberFormat(locale, { style: "unit", @@ -24,7 +27,7 @@ export const formatDeadline = (time: number): string => { console.warn(`Failed to format time using ${locale} locale`, error); } } - return `in ${time} seconds`; + return `in ${timeLeft} ${unit}${timeLeft > 1 ? "s" : ""}`; }; export const getCountdownDelay = (deadline: number): number => From daa67261890ad71352090ff905a6631285cc30c7 Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Fri, 18 Oct 2024 07:42:17 +0200 Subject: [PATCH 3/5] Updating QA snapshot. --- ui/__snapshots__/qa.spec.ts.snap | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ui/__snapshots__/qa.spec.ts.snap b/ui/__snapshots__/qa.spec.ts.snap index a853551a..1883a095 100644 --- a/ui/__snapshots__/qa.spec.ts.snap +++ b/ui/__snapshots__/qa.spec.ts.snap @@ -106,7 +106,7 @@ var closeIconHTML = ''; var closeBtnHTML = \`\`; // helpers/countdown.ts -var formatDeadline = (time) => { +var formatDeadline = (time, locales = [LOCALE, void 0]) => { let unit = "second"; let timeLeft = (time - Date.now()) / 1e3; if (timeLeft >= 60) { @@ -118,14 +118,21 @@ var formatDeadline = (time) => { unit = "hour"; } const isLastMinute = unit === "minute" && timeLeft < 2; - const formattedTimeLeft = new Intl.NumberFormat(LOCALE, { - style: "unit", - unitDisplay: "long", - minimumFractionDigits: isLastMinute ? 1 : 0, - maximumFractionDigits: isLastMinute ? 1 : 0, - unit - }).format(Math.max(0, timeLeft)); - return \`in \${formattedTimeLeft}\`; + for (const locale of locales) { + try { + const formattedTimeLeft = new Intl.NumberFormat(locale, { + style: "unit", + unitDisplay: "long", + minimumFractionDigits: isLastMinute ? 1 : 0, + maximumFractionDigits: isLastMinute ? 1 : 0, + unit + }).format(Math.max(0, timeLeft)); + return \`in \${formattedTimeLeft}\`; + } catch (error) { + console.warn(\`Failed to format time using \${locale} locale\`, error); + } + } + return \`in \${timeLeft} \${unit}\${timeLeft > 1 ? "s" : ""}\`; }; var getCountdownDelay = (deadline) => deadline - Date.now() > 12e4 ? 6e4 : 1e3; var setCountdown = (selector, deadline) => { From f80a1e3ae1c597d42c1f18cf1d9803a3e7c31dda Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Fri, 18 Oct 2024 08:05:25 +0200 Subject: [PATCH 4/5] Handle negative values as well. --- ui/helpers/countdown.spec.ts | 1 + ui/helpers/countdown.ts | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ui/helpers/countdown.spec.ts b/ui/helpers/countdown.spec.ts index 5d33e9da..1389793c 100644 --- a/ui/helpers/countdown.spec.ts +++ b/ui/helpers/countdown.spec.ts @@ -50,6 +50,7 @@ describe("Countdown helpers", () => { test.each([ [10000, "10 seconds"], [60000, "1 minute"], + [-10000, "0 seconds"], ])(`should handle invalid locales %#`, (offset, label) => { const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); expect( diff --git a/ui/helpers/countdown.ts b/ui/helpers/countdown.ts index d7eebf8e..1903a6a8 100644 --- a/ui/helpers/countdown.ts +++ b/ui/helpers/countdown.ts @@ -13,6 +13,7 @@ export const formatDeadline = ( unit = "hour"; } const isLastMinute = unit === "minute" && timeLeft < 2; + const nonNegTimeLeft = Math.max(0, timeLeft); for (const locale of locales) { try { const formattedTimeLeft = new Intl.NumberFormat(locale, { @@ -21,13 +22,13 @@ export const formatDeadline = ( minimumFractionDigits: isLastMinute ? 1 : 0, maximumFractionDigits: isLastMinute ? 1 : 0, unit, - }).format(Math.max(0, timeLeft)); + }).format(nonNegTimeLeft); return `in ${formattedTimeLeft}`; } catch (error) { console.warn(`Failed to format time using ${locale} locale`, error); } } - return `in ${timeLeft} ${unit}${timeLeft > 1 ? "s" : ""}`; + return `in ${nonNegTimeLeft} ${unit}${nonNegTimeLeft === 1 ? "" : "s"}`; }; export const getCountdownDelay = (deadline: number): number => From f947e72f1ae724bdbe5ae2aefcecdd04f9762b7c Mon Sep 17 00:00:00 2001 From: Robin Tail Date: Fri, 18 Oct 2024 11:53:44 +0200 Subject: [PATCH 5/5] Update build snapshot. --- ui/__snapshots__/qa.spec.ts.snap | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/__snapshots__/qa.spec.ts.snap b/ui/__snapshots__/qa.spec.ts.snap index 1883a095..a2779860 100644 --- a/ui/__snapshots__/qa.spec.ts.snap +++ b/ui/__snapshots__/qa.spec.ts.snap @@ -118,6 +118,7 @@ var formatDeadline = (time, locales = [LOCALE, void 0]) => { unit = "hour"; } const isLastMinute = unit === "minute" && timeLeft < 2; + const nonNegTimeLeft = Math.max(0, timeLeft); for (const locale of locales) { try { const formattedTimeLeft = new Intl.NumberFormat(locale, { @@ -126,13 +127,13 @@ var formatDeadline = (time, locales = [LOCALE, void 0]) => { minimumFractionDigits: isLastMinute ? 1 : 0, maximumFractionDigits: isLastMinute ? 1 : 0, unit - }).format(Math.max(0, timeLeft)); + }).format(nonNegTimeLeft); return \`in \${formattedTimeLeft}\`; } catch (error) { console.warn(\`Failed to format time using \${locale} locale\`, error); } } - return \`in \${timeLeft} \${unit}\${timeLeft > 1 ? "s" : ""}\`; + return \`in \${nonNegTimeLeft} \${unit}\${nonNegTimeLeft === 1 ? "" : "s"}\`; }; var getCountdownDelay = (deadline) => deadline - Date.now() > 12e4 ? 6e4 : 1e3; var setCountdown = (selector, deadline) => {