Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

III-6151 fix timezone issues latest #946

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"bootstrap": "^4.5.3",
"clipboard-copy": "^4.0.1",
"crypto-browserify": "^3.12.0",
"date-fns": "^2.16.1",
"date-fns": "^3.6",
"date-fns-tz": "^3.2.0",
"deep-object-diff": "^1.1.0",
"draft-js": "^0.11.7",
"draftjs-to-html": "^0.9.1",
Expand All @@ -62,7 +63,7 @@
"react-bootstrap": "^1.4.0",
"react-bootstrap-typeahead": "^5.1.2",
"react-cookie": "^4.0.3",
"react-datepicker": "^4.8.0",
"react-datepicker": "^7.5.0",
"react-dom": "^17.0.2",
"react-draft-wysiwyg": "^1.15.0",
"react-gauge-component": "^1.2.0",
Expand Down Expand Up @@ -97,7 +98,6 @@
"@testing-library/user-event": "^12.8.0",
"@types/lodash": "^4.14.168",
"@types/react-bootstrap-typeahead": "^5.1.8",
"@types/react-datepicker": "^4.8.0",
"@types/react-query": "^1.1.2",
"@types/styled-components": "^5.1.9",
"@types/uuid": "^9.0.0",
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './src/test/e2e',
/* Maximum time one test can run for. */
timeout: 60 * 1000,
timeout: 120 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
Expand Down
83 changes: 33 additions & 50 deletions src/hooks/api/events.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { fromZonedTime, toZonedTime } from 'date-fns-tz';
import type { UseQueryOptions } from 'react-query';

import type { CalendarType } from '@/constants/CalendarType';
Expand Down Expand Up @@ -44,7 +45,7 @@ type EventArguments = {
calendarType: Values<typeof CalendarType>;
startDate: string;
endDate: string;
subEvent: SubEvent[];
subEvent: SubEvent[] | undefined;
openingHours: OpeningHours[];
terms: Term[];
workflowStatus: WorkflowStatus;
Expand Down Expand Up @@ -106,9 +107,15 @@ const addEvent = async ({
mainLanguage,
name,
calendarType,
startDate,
endDate,
subEvent,
startDate: fromZonedTime(startDate, 'Europe/Brussels'),
endDate: fromZonedTime(endDate, 'Europe/Brussels'),
subEvent: subEvent
? subEvent.map((it) => ({
...it,
startDate: fromZonedTime(it.startDate, 'Europe/Brussels'),
endDate: fromZonedTime(it.endDate, 'Europe/Brussels'),
}))
: undefined,
openingHours,
terms,
location,
Expand Down Expand Up @@ -184,7 +191,28 @@ const getEventById = async ({ headers, id }) => {
// eslint-disable-next-line no-console
return console.error(res);
}
return await res.json();
const data = (await res.json()) as Event;

if (data.subEvent) {
data.subEvent = data.subEvent.map((it) => ({
...it,
startDate: toZonedTime(it.startDate, 'Europe/Brussels').toISOString(),
endDate: toZonedTime(it.endDate, 'Europe/Brussels').toISOString(),
}));
}

if (data.startDate) {
data.startDate = toZonedTime(
data.startDate,
'Europe/Brussels',
).toISOString();
}

if (data.endDate) {
data.endDate = toZonedTime(data.endDate, 'Europe/Brussels').toISOString();
}

return data;
};

type UseGetEventByIdArguments = ServerSideQueryOptions & {
Expand Down Expand Up @@ -415,50 +443,6 @@ const useChangeNameMutation = (configuration = {}) =>
...configuration,
});

const changeCalendar = async ({
headers,
id,
calendarType,
timeSpans,
subEvent,
start,
end,
startDate,
endDate,
openingHours,
dayOfWeek,
opens,
closes,
}) => {
return fetchFromApi({
path: `/events/${id.toString()}/calendar`,
options: {
method: 'PUT',
body: JSON.stringify({
calendarType,
timeSpans,
subEvent,
start,
end,
startDate,
endDate,
openingHours,
dayOfWeek,
opens,
closes,
}),
headers,
},
});
};

const useChangeCalendarMutation = (configuration = {}) =>
useAuthenticatedMutation({
mutationFn: changeCalendar,
mutationKey: 'events-change-calendar',
...configuration,
});

const changeStatus = async ({ headers, id, type, reason }) =>
fetchFromApi({
path: `/events/${id.toString()}/status`,
Expand Down Expand Up @@ -637,7 +621,6 @@ export {
useChangeAttendanceModeMutation,
useChangeAudienceMutation,
useChangeAvailableFromMutation,
useChangeCalendarMutation,
useChangeLocationMutation,
useChangeNameMutation,
useChangeOnlineUrlMutation,
Expand Down
15 changes: 11 additions & 4 deletions src/hooks/api/offers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { fromZonedTime } from 'date-fns-tz';
import type { UseQueryOptions } from 'react-query';
import { UseMutationOptions } from 'react-query';

import { OfferTypes, ScopeTypes } from '@/constants/OfferType';
import { useGetEventByIdQuery } from '@/hooks/api/events';
import { useGetPlaceByIdQuery } from '@/hooks/api/places';
import { Offer } from '@/types/Offer';
import { type SubEvent, Offer } from '@/types/Offer';
import { createEmbededCalendarSummaries } from '@/utils/createEmbededCalendarSummaries';
import { createSortingArgument } from '@/utils/createSortingArgument';
import { fetchFromApi, isErrorObject } from '@/utils/fetchFromApi';
Expand Down Expand Up @@ -162,11 +163,17 @@ const changeOfferCalendar = async ({
body: JSON.stringify({
calendarType,
timeSpans,
subEvent,
subEvent: !!subEvent
? (subEvent as SubEvent[]).map((it) => ({
...it,
startDate: fromZonedTime(it.startDate, 'Europe/Brussels'),
endDate: fromZonedTime(it.endDate, 'Europe/Brussels'),
}))
: undefined,
start,
end,
startDate,
endDate,
startDate: fromZonedTime(startDate, 'Europe/Brussels'),
endDate: fromZonedTime(endDate, 'Europe/Brussels'),
openingHours,
dayOfWeek,
opens,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/steps/PlaceStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const getGlobalValue = getValueFromTheme('global');

type PlaceStepProps = StackProps &
StepProps & {
terms: Array<Values<typeof EventTypes>>;
terms?: Array<Values<typeof EventTypes>>;
municipality?: City;
country?: Country;
chooseLabel: (t: TFunction) => string;
Expand Down
61 changes: 60 additions & 1 deletion src/test/e2e/events/create-calendar-single.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { test } from '@playwright/test';
import { expect, test } from '@playwright/test';

import { withTimezone } from '@/test/e2e/withTimezone';

const dummyEvent = {
name: 'E2E test event with calendarType single',
Expand Down Expand Up @@ -44,3 +46,60 @@ test('create an event with calendarType single', async ({ baseURL, page }) => {
// Publish
await page.getByRole('button', { name: 'Publiceren', exact: true }).click();
});

test('create an event with calendarType single in Tokyo', async ({
baseURL,
browser,
}) => {
let url;

await withTimezone({ browser, timezoneId: 'Asia/Tokyo' }, async (page) => {
await page.goto(`${baseURL}/create`);
// 1. Select event
await page.getByRole('button', { name: 'Evenement' }).click();
// 2. Type
await page.getByRole('button', { name: 'Concert' }).click();

// 3. Date
// Use current date
await page.getByLabel('Beginuur').click();
await page.getByLabel('01:00').click();

// 4. Address
await page.getByLabel('Gemeente').click();
await page.getByLabel('Gemeente').fill(dummyEvent.address.zip);
await page
.getByRole('option', { name: dummyEvent.address.municipality })
.click();
await page.getByLabel('Kies een locatie').click();

await page
.getByLabel('Kies een locatie')
.fill(dummyEvent.address.place.substring(0, 3));

await page
.getByRole('option', { name: dummyEvent.address.place, exact: true })
.first()
.click();

// 5. Name and Age
await page.getByLabel('Naam van het evenement').click();
await page.getByLabel('Naam van het evenement').fill(dummyEvent.name);
await page.getByRole('button', { name: 'Volwassenen 18+' }).click();
await page.getByRole('button', { name: 'Opslaan' }).click();

// Publish
await page.getByRole('button', { name: 'Publiceren', exact: true }).click();

url = page.url();
});

await withTimezone(
{ browser, timezoneId: 'Europe/Brussels' },
async (page) => {
await page.goto(url);
const startHour = page.getByLabel('Beginuur');
expect(await startHour.inputValue({ timeout: 10_000 })).toEqual('01:00');
},
Copy link
Contributor

@brampauwelyn brampauwelyn Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will always be 01:00 I guess?
Even if we change the timezone here to Tokyo?

Or will it display the time with the Tokyo timezine?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The time should always show the time value you'd expect. SO indeed if the timezone is Tokyo or Brussels the time value should be 01:00

);
});
11 changes: 11 additions & 0 deletions src/test/e2e/withTimezone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { type Browser, type Page } from '@playwright/test';

export async function withTimezone(
ctx: { browser: Browser; timezoneId: string },
testFn: (page: Page) => Promise<void>,
) {
const context = await ctx.browser.newContext({ timezoneId: ctx.timezoneId });
const page = await context.newPage();
await testFn(page);
await context.close();
}
2 changes: 1 addition & 1 deletion src/ui/Box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
} from 'react';
import { forwardRef } from 'react';
import { AsyncTypeaheadProps, TypeaheadModel } from 'react-bootstrap-typeahead';
import { ReactDatePickerProps } from 'react-datepicker';
import { DatePickerProps as ReactDatePickerProps } from 'react-datepicker';
import type {
FlattenInterpolation,
FlattenSimpleInterpolation,
Expand Down
4 changes: 1 addition & 3 deletions src/ui/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import 'react-datepicker/dist/react-datepicker.css';

import de from 'date-fns/locale/de';
import fr from 'date-fns/locale/fr';
import nl from 'date-fns/locale/nl';
import { de, fr, nlBE as nl } from 'date-fns/locale';
import { useRef } from 'react';
import ReactDatePicker, {
registerLocale,
Expand Down
2 changes: 1 addition & 1 deletion src/ui/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type PaginationProps = InlineProps & {
currentPage: number;
totalItems: number;
perPage: number;
limitPages: number;
limitPages?: number;
onChangePage?: (newValue: number) => void;
};

Expand Down
2 changes: 1 addition & 1 deletion src/ui/TimeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ type CopyPayload =
}
| { method: 'all'; data: { [key: string]: Data } };

type RowProps = InlineProps & {
type RowProps = Omit<InlineProps, 'date'> & {
data: Record<string, unknown>;
date: string;
onCopy: (date: string) => void;
Expand Down
4 changes: 2 additions & 2 deletions src/ui/ToggleBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ const SuccessIcon = ({ active }: SuccessIconProps) => {
};

type Props = StackProps & {
active: boolean;
active?: boolean;
icon?: JSX.Element;
text: ReactNode;
text?: ReactNode;
disabled?: boolean;
};

Expand Down
3 changes: 1 addition & 2 deletions src/utils/formatPeriod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { differenceInDays, format } from 'date-fns';
import fr from 'date-fns/locale/fr';
import nl from 'date-fns/locale/nl-BE';
import { fr, nlBE as nl } from 'date-fns/locale';
import capitalize from 'lodash/capitalize';
import type { TFunction } from 'react-i18next';

Expand Down
Loading
Loading