Skip to content
Merged
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
49 changes: 38 additions & 11 deletions apps/web/components/booking/pages/BookingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSession } from "next-auth/react";
import dynamic from "next/dynamic";
import Head from "next/head";
import { useRouter } from "next/router";
import { useEffect, useMemo, useReducer, useState } from "react";
import { useCallback, useEffect, useMemo, useReducer, useState } from "react";
import { useForm, useFormContext } from "react-hook-form";
import { v4 as uuidv4 } from "uuid";
import { z } from "zod";
Expand All @@ -15,6 +15,7 @@ import { getEventLocationType, locationKeyToString } from "@calcom/app-store/loc
import { createPaymentLink } from "@calcom/app-store/stripepayment/lib/client";
import { getEventTypeAppData } from "@calcom/app-store/utils";
import type { LocationObject } from "@calcom/core/location";
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import {
useEmbedNonStylesConfig,
Expand All @@ -38,6 +39,7 @@ import useTheme from "@calcom/lib/hooks/useTheme";
import { HttpError } from "@calcom/lib/http-error";
import { getEveryFreqFor } from "@calcom/lib/recurringStrings";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import type { RecurringEvent } from "@calcom/types/Calendar";
import { Button, Form, Tooltip } from "@calcom/ui";
import { FiAlertTriangle, FiCalendar, FiRefreshCw, FiUser } from "@calcom/ui/components/icon";

Expand Down Expand Up @@ -213,6 +215,20 @@ const BookingPage = ({
duration = Number(queryDuration);
}

// This is a workaround for forcing the same time format for both server side rendering and client side rendering
// At initial render, we use the default time format which is 12H
const [withDefaultTimeFormat, setWithDefaultTimeFormat] = useState(true);
const parseDateFunc = useCallback(
(date: string | null | Dayjs) => {
return parseDate(date, i18n, withDefaultTimeFormat);
},
[withDefaultTimeFormat]
);
// After intial render on client side, we let parseDateFunc to use the time format from the localStorage
useEffect(() => {
setWithDefaultTimeFormat(false);
}, []);

useEffect(() => {
if (top !== window) {
//page_view will be collected automatically by _middleware.ts
Expand Down Expand Up @@ -370,15 +386,26 @@ const BookingPage = ({
// Calculate the booking date(s)
let recurringStrings: string[] = [],
recurringDates: Date[] = [];
const parseRecurringDatesFunc = useCallback(
(date: string | null | Dayjs, recurringEvent: RecurringEvent, recurringCount: number) => {
return parseRecurringDates(
{
startDate: date,
timeZone: timeZone(),
recurringEvent: recurringEvent,
recurringCount: recurringCount,
withDefaultTimeFormat: withDefaultTimeFormat,
},
i18n
);
},
[withDefaultTimeFormat, date, eventType.recurringEvent, recurringEventCount]
);
if (eventType.recurringEvent?.freq && recurringEventCount !== null) {
[recurringStrings, recurringDates] = parseRecurringDates(
{
startDate: date,
timeZone: timeZone(),
recurringEvent: eventType.recurringEvent,
recurringCount: parseInt(recurringEventCount.toString()),
},
i18n
[recurringStrings, recurringDates] = parseRecurringDatesFunc(
date,
eventType.recurringEvent,
parseInt(recurringEventCount.toString())
);
}

Expand Down Expand Up @@ -507,7 +534,7 @@ const BookingPage = ({
<div className="text-sm font-medium">
{isClientTimezoneAvailable &&
(rescheduleUid || !eventType.recurringEvent?.freq) &&
`${parseDate(date, i18n)}`}
`${parseDateFunc(date)}`}
{isClientTimezoneAvailable &&
!rescheduleUid &&
eventType.recurringEvent?.freq &&
Expand Down Expand Up @@ -537,7 +564,7 @@ const BookingPage = ({
<FiCalendar className="ml-[2px] -mt-1 inline-block h-4 w-4 ltr:mr-[10px] rtl:ml-[10px]" />
{isClientTimezoneAvailable &&
typeof booking.startTime === "string" &&
parseDate(dayjs(booking.startTime), i18n)}
parseDateFunc(dayjs(booking.startTime))}
</p>
</div>
)}
Expand Down
16 changes: 10 additions & 6 deletions apps/web/lib/parseDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ import { RRule } from "rrule";

import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import { detectBrowserTimeFormat } from "@calcom/lib/timeFormat";
import { detectBrowserTimeFormat, TimeFormat } from "@calcom/lib/timeFormat";
import type { RecurringEvent } from "@calcom/types/Calendar";

import { parseZone } from "./parseZone";

const processDate = (date: string | null | Dayjs, i18n: I18n) => {
const processDate = (date: string | null | Dayjs, i18n: I18n, withDefaultTimeFormat: boolean) => {
const parsedZone = parseZone(date);
if (!parsedZone?.isValid()) return "Invalid date";
const formattedTime = parsedZone?.format(detectBrowserTimeFormat);
const formattedTime = parsedZone?.format(
withDefaultTimeFormat ? TimeFormat.TWELVE_HOUR : detectBrowserTimeFormat
);
return formattedTime + ", " + dayjs(date).toDate().toLocaleString(i18n.language, { dateStyle: "full" });
};

export const parseDate = (date: string | null | Dayjs, i18n: I18n) => {
export const parseDate = (date: string | null | Dayjs, i18n: I18n, withDefaultTimeFormat: boolean) => {
if (!date) return ["No date"];
return processDate(date, i18n);
return processDate(date, i18n, withDefaultTimeFormat);
};

export const parseRecurringDates = (
Expand All @@ -26,11 +28,13 @@ export const parseRecurringDates = (
timeZone,
recurringEvent,
recurringCount,
withDefaultTimeFormat,
}: {
startDate: string | null | Dayjs;
timeZone?: string;
recurringEvent: RecurringEvent | null;
recurringCount: number;
withDefaultTimeFormat: boolean;
},
i18n: I18n
): [string[], Date[]] => {
Expand All @@ -50,7 +54,7 @@ export const parseRecurringDates = (
});
const dateStrings = times.map((t) => {
// finally; show in local timeZone again
return processDate(t.tz(timeZone), i18n);
return processDate(t.tz(timeZone), i18n, withDefaultTimeFormat);
});

return [dateStrings, times.map((t) => t.toDate())];
Expand Down