diff --git a/apps/back-office/.storybook/preview-head.html b/apps/back-office/.storybook/preview-head.html deleted file mode 100644 index 6f789ce0d..000000000 --- a/apps/back-office/.storybook/preview-head.html +++ /dev/null @@ -1,5 +0,0 @@ - - diff --git a/apps/back-office/.storybook/preview.tsx b/apps/back-office/.storybook/preview.tsx index 9913e8f12..0b1734f9b 100644 --- a/apps/back-office/.storybook/preview.tsx +++ b/apps/back-office/.storybook/preview.tsx @@ -31,9 +31,6 @@ export const globalTypes = { }, }; -document.body.style.fontFamily = - '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"'; - const preview: Preview = { parameters: { ...parameters, diff --git a/apps/back-office/styles/globals.css b/apps/back-office/styles/globals.css index 596256fcc..2e9afb0c1 100644 --- a/apps/back-office/styles/globals.css +++ b/apps/back-office/styles/globals.css @@ -4,6 +4,11 @@ @layer base { :root { + --default-font-stack: -apple-system, system-ui, BlinkMacSystemFont, + 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; @@ -236,7 +241,7 @@ } body { - @apply h-full font-sans antialiased; + font-family: var(--font-sans, var(--default-font-stack)); } body, diff --git a/apps/unlock/.storybook/preview-head.html b/apps/unlock/.storybook/preview-head.html deleted file mode 100644 index 6f789ce0d..000000000 --- a/apps/unlock/.storybook/preview-head.html +++ /dev/null @@ -1,5 +0,0 @@ - - diff --git a/apps/unlock/.storybook/preview.tsx b/apps/unlock/.storybook/preview.tsx index 8eee57373..8db2248b6 100644 --- a/apps/unlock/.storybook/preview.tsx +++ b/apps/unlock/.storybook/preview.tsx @@ -30,8 +30,6 @@ export const globalTypes = { }, }; -document.body.classList.add('font-sans'); - const preview: Preview = { parameters: { ...parameters, diff --git a/apps/web/.storybook/preview-head.html b/apps/web/.storybook/preview-head.html deleted file mode 100644 index 6f789ce0d..000000000 --- a/apps/web/.storybook/preview-head.html +++ /dev/null @@ -1,5 +0,0 @@ - - diff --git a/apps/web/.storybook/preview.tsx b/apps/web/.storybook/preview.tsx index 6fc908aac..fe18d2724 100644 --- a/apps/web/.storybook/preview.tsx +++ b/apps/web/.storybook/preview.tsx @@ -29,10 +29,6 @@ export const globalTypes = { }, }, }; - -document.body.style.fontFamily = - '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"'; - const preview: Preview = { parameters: { ...parameters, diff --git a/apps/web/styles/globals.css b/apps/web/styles/globals.css index fc3d48954..64a7fd5e6 100644 --- a/apps/web/styles/globals.css +++ b/apps/web/styles/globals.css @@ -4,6 +4,11 @@ @layer base { :root { + --default-font-stack: -apple-system, system-ui, BlinkMacSystemFont, + 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; @@ -197,7 +202,7 @@ } body { - @apply h-full font-sans antialiased; + font-family: var(--font-sans, var(--default-font-stack)); } body, diff --git a/libs/gql/admin/api/src/queries/organizer/event/eventParameters.spec.ts b/libs/gql/admin/api/src/queries/organizer/event/eventParameters.spec.ts index f2b0dd3f5..9405bb5de 100644 --- a/libs/gql/admin/api/src/queries/organizer/event/eventParameters.spec.ts +++ b/libs/gql/admin/api/src/queries/organizer/event/eventParameters.spec.ts @@ -7,6 +7,9 @@ import { } from '@test-utils/db'; import { adminSdk } from '../../../generated'; +import { addHoursInTimeZone, subHoursInTimeZone } from '@time'; +import { toZonedTime } from 'date-fns-tz'; + describe('eventParameters integration tests', () => { process.env.TZ = 'Europe/London'; let client: PgClient; @@ -27,6 +30,9 @@ describe('eventParameters integration tests', () => { jest.resetAllMocks(); }); + const timeZone = 'Europe/London'; + const currentDate = new Date(); + it('should not access eventParameters not PUBLISHED', async () => { const res = await adminSdk.GetEventParameters({ eventId: 'clocula4d04g40bw1t9zefsuc', @@ -35,15 +41,14 @@ describe('eventParameters integration tests', () => { }); describe('eventParameters for event with timezone Europe/London, same as the one in test', () => { it('should return isOngoing true if event is ongoing', async () => { - const currentDate = new Date(); await updateObjects( client, 'eventParameters', { - dateStart: new Date(currentDate.getTime() - 1000 * 60 * 60), // 1 hour before - dateEnd: new Date(currentDate.getTime() + 1000 * 60 * 60), // 1 hour after - dateSaleStart: new Date(currentDate.getTime() - 2000 * 60 * 60), // 2 hours before - dateSaleEnd: new Date(currentDate.getTime() + 2000 * 60 * 60), // 2 hours after + dateStart: subHoursInTimeZone(currentDate, 2, timeZone), + dateEnd: addHoursInTimeZone(currentDate, 2, timeZone), + dateSaleStart: subHoursInTimeZone(currentDate, 2, timeZone), + dateSaleEnd: addHoursInTimeZone(currentDate, 2, timeZone), }, { eventId: 'clizzpvidao620buvxit1ynko' }, ); @@ -55,15 +60,14 @@ describe('eventParameters integration tests', () => { }); it('should return isOngoing false if event is not ongoing', async () => { - const currentDate = new Date(); await updateObjects( client, 'eventParameters', { - dateStart: new Date(currentDate.getTime() + 1000 * 60 * 60), // 1 hour after - dateEnd: new Date(currentDate.getTime() + 2000 * 60 * 60), // 2 hours after - dateSaleStart: new Date(currentDate.getTime() - 2000 * 60 * 60), // 2 hours before - dateSaleEnd: new Date(currentDate.getTime() - 1000 * 60 * 60), // 1 hour before + dateStart: subHoursInTimeZone(currentDate, 6, timeZone), // 6 hours before + dateEnd: subHoursInTimeZone(currentDate, 1, timeZone), // 1 hour before + dateSaleStart: subHoursInTimeZone(currentDate, 2, timeZone), // 2 hours before + dateSaleEnd: subHoursInTimeZone(currentDate, 1, timeZone), // 1 hour before }, { eventId: 'clizzpvidao620buvxit1ynko' }, ); @@ -75,15 +79,14 @@ describe('eventParameters integration tests', () => { }); it('should return isSaleOngoing true if sale is ongoing', async () => { - const currentDate = new Date(); await updateObjects( client, 'eventParameters', { - dateStart: new Date(currentDate.getTime() - 2000 * 60 * 60), // 2 hours before - dateEnd: new Date(currentDate.getTime() + 2000 * 60 * 60), // 2 hours after - dateSaleStart: new Date(currentDate.getTime() - 1000 * 60 * 60), // 1 hour before - dateSaleEnd: new Date(currentDate.getTime() + 1000 * 60 * 60), // 1 hour after + dateStart: subHoursInTimeZone(currentDate, 2, timeZone), // 2 hours before + dateEnd: addHoursInTimeZone(currentDate, 2, timeZone), // 2 hours after + dateSaleStart: subHoursInTimeZone(currentDate, 1, timeZone), // 1 hour before + dateSaleEnd: addHoursInTimeZone(currentDate, 1, timeZone), // 1 hour after }, { eventId: 'clizzpvidao620buvxit1ynko' }, ); @@ -95,15 +98,14 @@ describe('eventParameters integration tests', () => { }); it('should return isSaleOngoing false if sale is not ongoing', async () => { - const currentDate = new Date(); await updateObjects( client, 'eventParameters', { - dateStart: new Date(currentDate.getTime() - 2000 * 60 * 60), // 2 hours before - dateEnd: new Date(currentDate.getTime() + 2000 * 60 * 60), // 2 hours after - dateSaleStart: new Date(currentDate.getTime() + 1000 * 60 * 60), // 1 hour after - dateSaleEnd: new Date(currentDate.getTime() + 2000 * 60 * 60), // 2 hours after + dateStart: subHoursInTimeZone(currentDate, 2, timeZone), // 2 hours before + dateEnd: addHoursInTimeZone(currentDate, 2, timeZone), // 2 hours after + dateSaleStart: subHoursInTimeZone(currentDate, 4, timeZone), // 4 hours before + dateSaleEnd: subHoursInTimeZone(currentDate, 1, timeZone), // 1 hour before }, { eventId: 'clizzpvidao620buvxit1ynko' }, ); @@ -119,7 +121,7 @@ describe('eventParameters integration tests', () => { // Adjust for the timezone difference between New York and London const timezoneOffset = 1000 * 60 * 60 * 5; // 5 hours it('should return isOngoing true if event is ongoing', async () => { - const currentDate = new Date(); + const currentDate = toZonedTime(new Date(), 'Europe/London'); await updateObjects( client, 'eventParameters', @@ -147,7 +149,7 @@ describe('eventParameters integration tests', () => { }); it('should return isOngoing false if event is not ongoing', async () => { - const currentDate = new Date(); + const currentDate = toZonedTime(new Date(), 'Europe/London'); await updateObjects( client, 'eventParameters', @@ -175,7 +177,7 @@ describe('eventParameters integration tests', () => { }); it('should return isSaleOngoing true if sale is ongoing', async () => { - const currentDate = new Date(); + const currentDate = toZonedTime(new Date(), 'Europe/London'); await updateObjects( client, 'eventParameters', @@ -203,7 +205,7 @@ describe('eventParameters integration tests', () => { }); it('should return isSaleOngoing false if sale is not ongoing', async () => { - const currentDate = new Date(); + const currentDate = toZonedTime(new Date(), 'Europe/London'); await updateObjects( client, 'eventParameters', diff --git a/libs/time/src/index.ts b/libs/time/src/index.ts index 7431343e5..8cdc9042e 100644 --- a/libs/time/src/index.ts +++ b/libs/time/src/index.ts @@ -2,3 +2,4 @@ export * from './lib/UTCDate'; export * from './lib/UTCDateMini'; export * from './lib/getSteppedIntervalTime'; export * from './lib/useNow'; +export * from './lib/utils'; diff --git a/libs/time/src/lib/utils.ts b/libs/time/src/lib/utils.ts new file mode 100644 index 000000000..07c1fbbcf --- /dev/null +++ b/libs/time/src/lib/utils.ts @@ -0,0 +1,47 @@ +import { addHours, subHours } from 'date-fns'; +import { format, toZonedTime } from 'date-fns-tz'; + +/** + * Converts a date to a specified time zone and formats it for display or further processing. + * @param {Date} date - The date to convert. + * @param {string} timeZone - The IANA time zone name. + * @returns {string} - The formatted date string in the specified time zone. + */ +export const convertDateToTimeZone = (date: Date, timeZone: string): string => { + const zonedDate = toZonedTime(date, timeZone); + return format(zonedDate, 'yyyy-MM-dd HH:mm:ssXXX', { timeZone }); +}; + +/** + * Adds hours to a date in a specific time zone. + * @param {Date} date - The original date. + * @param {number} hours - The number of hours to add. + * @param {string} timeZone - The IANA time zone name. + * @returns {Date} - The new date with added hours, considered in the specified time zone. + */ +export const addHoursInTimeZone = ( + date: Date, + hours: number, + timeZone: string, +): Date => { + const zonedDate = toZonedTime(date, timeZone); + const newDate = addHours(zonedDate, hours); + return toZonedTime(newDate, timeZone); // Convert back if needed, or adjust as per use case +}; + +/** + * Subtracts hours from a date in a specific time zone. + * @param {Date} date - The original date. + * @param {number} hours - The number of hours to subtract. + * @param {string} timeZone - The IANA time zone name. + * @returns {Date} - The new date with subtracted hours, considered in the specified time zone. + */ +export const subHoursInTimeZone = ( + date: Date, + hours: number, + timeZone: string, +): Date => { + const zonedDate = toZonedTime(date, timeZone); + const newDate = subHours(zonedDate, hours); + return toZonedTime(newDate, timeZone); // Convert back if needed, or adjust as per use case +}; diff --git a/libs/ui/components/.storybook/globals.css b/libs/ui/components/.storybook/globals.css index ad37dc451..4d39dd218 100644 --- a/libs/ui/components/.storybook/globals.css +++ b/libs/ui/components/.storybook/globals.css @@ -4,6 +4,11 @@ @layer base { :root { + --default-font-stack: -apple-system, system-ui, BlinkMacSystemFont, + 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', + 'Noto Color Emoji'; + --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; @@ -236,8 +241,8 @@ } body { - font-family: 'Inter', sans-serif; - @apply h-full font-sans antialiased; + font-family: var(--font-sans, var(--default-font-stack)); + @apply h-full antialiased; } .pt-square { diff --git a/libs/ui/components/.storybook/preview-head.html b/libs/ui/components/.storybook/preview-head.html deleted file mode 100644 index 11b17fd16..000000000 --- a/libs/ui/components/.storybook/preview-head.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - diff --git a/libs/ui/components/.storybook/preview.tsx b/libs/ui/components/.storybook/preview.tsx index 55303e0d0..30b1d114f 100644 --- a/libs/ui/components/.storybook/preview.tsx +++ b/libs/ui/components/.storybook/preview.tsx @@ -20,9 +20,6 @@ export const DarkModeDecorator: Decorator = (Story: any, context: any = {}) => { return dark ? : ; }; -document.body.style.fontFamily = - '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"'; - const preview: Preview = { parameters: { ...parameters,