Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ moment.relativeTimeThreshold('h', 24);
moment.relativeTimeThreshold('d', 30);
moment.relativeTimeThreshold('M', 12);

const sanitiseDuration = (duration: ISODuration) => {
const durationApi = globalThis.Temporal?.Duration;

if (!durationApi) {
return { total: () => 0 };
}

try {
return durationApi.from(duration);
} catch {
return durationApi.from('PT0S'); // fallback to 0 seconds if the duration is invalid
}
};

// Extra confirmation
// const normaliseLocale = (locale?: string): string | undefined => {
// if (!locale) return undefined;
// const transformedLocaleToBCP47LangTag = locale.replace(/_/g, '-');
// try {
// return Intl.getCanonicalLocales(transformedLocaleToBCP47LangTag)[0];
// } catch {
// return undefined;
// }
// };

const transformLocaleToBCP47LangTag = (locale: Locale) =>
locale.replace(/_/g, '-');

export const formatDuration = ({
duration,
format,
Expand All @@ -31,12 +59,45 @@ export const formatDuration = ({
format?: string;
locale?: Locale;
}): string => {
const defaultDurationFormat = duration?.includes('H') ? 'h:mm:ss' : 'mm:ss';
const durationInMilliseconds = moment.duration(duration).asMilliseconds();
return moment
.utc(durationInMilliseconds)
.locale(locale)
.format(format || defaultDurationFormat);
const formattedLocale = transformLocaleToBCP47LangTag(locale) || undefined;

const totalSeconds = sanitiseDuration(duration).total({
unit: 'seconds',
});
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = Math.floor(totalSeconds % 60);

// note, using Intl.NumberFormat and Intl.Locale does not take into account overrides in psammead-locales/moment
const translateDigits = (timeValueAsNumber: number, minDigits: number) =>
// Using this instead of src/app/legacy/psammead/psammead-locales/src/numerals/index.js since this is a safe usecase.
new Intl.NumberFormat(formattedLocale, {
minimumIntegerDigits: minDigits,
useGrouping: false,
}).format(timeValueAsNumber);

const withArabicComma = (str: string) => {
if (!formattedLocale) return str;
return new Intl.Locale(formattedLocale).maximize().script === 'Arab'
? str.replace(/,/g, '\u060C')
: str;
};

if (format) {
return withArabicComma(
format
.replace('h', translateDigits(hours, 1))
.replace('mm', translateDigits(minutes, 2))
.replace('ss', translateDigits(seconds, 2))
.replace('m', translateDigits(minutes, 1)),
);
}

return withArabicComma(
hours > 0
? `${translateDigits(hours, 1)}:${translateDigits(minutes, 2)}:${translateDigits(seconds, 2)}`
: `${translateDigits(minutes, 2)}:${translateDigits(seconds, 2)}`,
);
};

// if the date is invalid return false - https://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript#answer-1353711
Expand Down
1 change: 1 addition & 0 deletions src/testHelpers/jest-setup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable max-classes-per-file */
import { jest } from '@jest/globals';
import 'temporal-polyfill/global';
import path from 'path';
import { TextEncoder, TextDecoder } from 'util';
import { ReadableStream } from 'node:stream/web';
Expand Down
1 change: 1 addition & 0 deletions ws-nextjs-app/setupTests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import '@testing-library/jest-dom';
import 'temporal-polyfill/global';
import { TextEncoder, TextDecoder } from 'node:util';
import { ReadableStream } from 'node:stream/web';
import { MessageChannel, MessagePort } from 'node:worker_threads';
Expand Down
Loading