Skip to content

Commit

Permalink
fix: Timezone in Email Embed not working calcom#15525 (calcom#15537)
Browse files Browse the repository at this point in the history
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Amit Sharma <74371312+Amit91848@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: Hariom <hariombalhara@gmail.com>
  • Loading branch information
6 people authored and MuhammadAimanSulaiman committed Feb 24, 2025
1 parent e1e23bd commit f6dd403
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Badge, Dialog, DialogContent } from "@calcom/ui";

import { getDurationFormatted } from "../../../components/event-meta/Duration";
import { useTimePreferences } from "../../../lib";
import { useBookerStore } from "../../store";
import { FromTime } from "../../utils/dates";
import { useEvent } from "../../utils/event";
import { useBookerTime } from "../hooks/useBookerTime";

const BookEventFormWrapper = ({ children, onCancel }: { onCancel: () => void; children: ReactNode }) => {
const { data } = useEvent();
Expand Down Expand Up @@ -43,7 +43,7 @@ export const BookEventFormWrapperComponent = ({
const { i18n, t } = useLocale();
const selectedTimeslot = useBookerStore((state) => state.selectedTimeslot);
const selectedDuration = useBookerStore((state) => state.selectedDuration);
const { timeFormat, timezone } = useTimePreferences();
const { timeFormat, timezone } = useBookerTime();
if (!selectedTimeslot) {
return null;
}
Expand Down
10 changes: 8 additions & 2 deletions packages/features/bookings/Booker/components/EventMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import i18nConfigration from "../../../../../i18n.json";
import { fadeInUp } from "../config";
import { useBookerStore } from "../store";
import { FromToTime } from "../utils/dates";
import { useBookerTime } from "./hooks/useBookerTime";

const WebTimezoneSelect = dynamic(
() => import("@calcom/ui/components/form/timezone-select/TimezoneSelect").then((mod) => mod.TimezoneSelect),
Expand Down Expand Up @@ -80,7 +81,9 @@ export const EventMeta = ({
};
locale?: string | null;
}) => {
const { setTimezone, timeFormat, timezone } = useTimePreferences();
const { timeFormat, timezone } = useBookerTime();
const [setTimezone] = useTimePreferences((state) => [state.setTimezone]);
const [setBookerStoreTimezone] = useBookerStore((state) => [state.setTimezone], shallow);
const selectedDuration = useBookerStore((state) => state.selectedDuration);
const selectedTimeslot = useBookerStore((state) => state.selectedTimeslot);
const bookerState = useBookerStore((state) => state.state);
Expand Down Expand Up @@ -214,7 +217,10 @@ export const EventMeta = ({
container: () => "max-w-full",
}}
value={timezone}
onChange={(tz) => setTimezone(tz.value)}
onChange={({ value }) => {
setTimezone(value);
setBookerStoreTimezone(value);
}}
isDisabled={event.lockTimeZoneToggleOnBookingPage}
/>
</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { shallow } from "zustand/shallow";

import { useBookerStore } from "@calcom/features/bookings/Booker/store";

import { useTimePreferences } from "../../../lib/timePreferences";
import { getBookerTimezone } from "../../utils/getBookerTimezone";

export const useBookerTime = () => {
const [timezoneFromBookerStore] = useBookerStore((state) => [state.timezone], shallow);
const { timezone: timezoneFromTimePreferences, timeFormat } = useTimePreferences();
const timezone = getBookerTimezone({
storeTimezone: timezoneFromBookerStore,
bookerUserPreferredTimezone: timezoneFromTimePreferences,
});

return {
timezone,
timeFormat,
timezoneFromBookerStore,
timezoneFromTimePreferences,
};
};
16 changes: 16 additions & 0 deletions packages/features/bookings/Booker/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type StoreInitializeType = {
durationConfig?: number[] | null;
org?: string | null;
isInstantMeeting?: boolean;
timezone?: string | null;
teamMemberEmail?: string | null;
crmOwnerRecordType?: string | null;
crmAppSlug?: string | null;
Expand Down Expand Up @@ -152,6 +153,9 @@ export type BookerStore = {
org?: string | null;
setOrg: (org: string | null | undefined) => void;

timezone: string | null;
setTimezone: (timezone: string | null) => void;

teamMemberEmail?: string | null;
crmOwnerRecordType?: string | null;
crmAppSlug?: string | null;
Expand Down Expand Up @@ -246,6 +250,12 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
set({ seatedEventData });
updateQueryParam("bookingUid", seatedEventData.bookingUid ?? "null");
},
// This is different from timeZone in timePreferencesStore, because timeZone in timePreferencesStore is the preferred timezone of the booker,
// it is the timezone configured through query param. So, this is in a way the preference of the person who shared the link.
timezone: getQueryParam("cal.tz") ?? null,
setTimezone: (timezone: string | null) => {
set({ timezone });
},
initialize: ({
username,
eventSlug,
Expand All @@ -260,6 +270,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
durationConfig,
org,
isInstantMeeting,
timezone = null,
teamMemberEmail,
crmOwnerRecordType,
crmAppSlug,
Expand All @@ -275,6 +286,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
get().bookingUid === bookingUid &&
get().bookingData?.responses.email === bookingData?.responses.email &&
get().layout === layout &&
get().timezone === timezone &&
get().rescheduledBy === rescheduledBy &&
get().teamMemberEmail === teamMemberEmail &&
get().crmOwnerRecordType === crmOwnerRecordType &&
Expand All @@ -293,6 +305,7 @@ export const useBookerStore = create<BookerStore>((set, get) => ({
layout: layout || BookerLayouts.MONTH_VIEW,
isTeamEvent: isTeamEvent || false,
durationConfig,
timezone,
// Preselect today's date in week / column view, since they use this to show the week title.
selectedDate:
selectedDateInStore ||
Expand Down Expand Up @@ -388,6 +401,7 @@ export const useInitializeBookerStore = ({
durationConfig,
org,
isInstantMeeting,
timezone = null,
teamMemberEmail,
crmOwnerRecordType,
crmAppSlug,
Expand All @@ -408,6 +422,7 @@ export const useInitializeBookerStore = ({
verifiedEmail,
durationConfig,
isInstantMeeting,
timezone,
teamMemberEmail,
crmOwnerRecordType,
crmAppSlug,
Expand All @@ -427,6 +442,7 @@ export const useInitializeBookerStore = ({
verifiedEmail,
durationConfig,
isInstantMeeting,
timezone,
teamMemberEmail,
crmOwnerRecordType,
crmAppSlug,
Expand Down
7 changes: 2 additions & 5 deletions packages/features/bookings/Booker/utils/event.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { usePathname } from "next/navigation";
import { shallow } from "zustand/shallow";

import { useSchedule } from "@calcom/features/schedules";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { trpc } from "@calcom/trpc/react";

import { useTimePreferences } from "../../lib/timePreferences";
import { useBookerTime } from "../components/hooks/useBookerTime";
import { useBookerStore } from "../store";

export type useEventReturnType = ReturnType<typeof useEvent>;
Expand Down Expand Up @@ -88,7 +87,7 @@ export const useScheduleForEvent = ({
fromRedirectOfNonOrgLink?: boolean;
isTeamEvent?: boolean;
} = {}) => {
const { timezone } = useTimePreferences();
const { timezone } = useBookerTime();
const [usernameFromStore, eventSlugFromStore, monthFromStore, durationFromStore] = useBookerStore(
(state) => [state.username, state.eventSlug, state.month, state.selectedDuration],
shallow
Expand All @@ -97,8 +96,6 @@ export const useScheduleForEvent = ({
const searchParams = useCompatSearchParams();
const rescheduleUid = searchParams?.get("rescheduleUid");

const pathname = usePathname();

const schedule = useSchedule({
username: usernameFromStore ?? username,
eventSlug: eventSlugFromStore ?? eventSlug,
Expand Down
14 changes: 14 additions & 0 deletions packages/features/bookings/Booker/utils/getBookerTimezone.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* TODO: We could convert it into a hook and then we can access bookerStore and timePreferences stores directly here, avoiding the need to do it by the caller
*/
export const getBookerTimezone = ({
storeTimezone,
bookerUserPreferredTimezone,
}: {
storeTimezone: string | null;
bookerUserPreferredTimezone: string;
}) => {
// BookerStore timezone is the one that is updated no matter what could be the reason of the update
// e.g. timezone configured through cal.tz query param is available there but not in the preferences as those are booker user's preferences
return storeTimezone ?? bookerUserPreferredTimezone;
};
6 changes: 3 additions & 3 deletions packages/features/bookings/components/AvailableTimes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { localStorage } from "@calcom/lib/webstorage";
import type { IGetAvailableSlots } from "@calcom/trpc/server/routers/viewer/slots/util";
import { Button, Icon, SkeletonText } from "@calcom/ui";

import { useBookerTime } from "../Booker/components/hooks/useBookerTime";
import { useBookerStore } from "../Booker/store";
import { getQueryParam } from "../Booker/utils/query-param";
import { useTimePreferences } from "../lib";
import { useCheckOverlapWithOverlay } from "../lib/useCheckOverlapWithOverlay";
import { SeatsAvailabilityText } from "./SeatsAvailabilityText";

Expand Down Expand Up @@ -64,8 +64,8 @@ const SlotItem = ({
const { t } = useLocale();

const overlayCalendarToggled =
getQueryParam("overlayCalendar") === "true" || localStorage?.getItem("overlayCalendarSwitchDefault");
const [timeFormat, timezone] = useTimePreferences((state) => [state.timeFormat, state.timezone]);
getQueryParam("overlayCalendar") === "true" || localStorage.getItem("overlayCalendarSwitchDefault");
const { timeFormat, timezone } = useBookerTime();
const bookingData = useBookerStore((state) => state.bookingData);
const layout = useBookerStore((state) => state.layout);
const { data: eventData } = event;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getRecurringFreq } from "@calcom/lib/recurringStrings";
import { Tooltip, Alert } from "@calcom/ui";
import { Input } from "@calcom/ui";

import { useTimePreferences } from "../../lib";
import { useBookerTime } from "../../Booker/components/hooks/useBookerTime";

export const EventOccurences = ({ event }: { event: Pick<BookerEvent, "recurringEvent"> }) => {
const maxOccurences = event.recurringEvent?.count || null;
Expand All @@ -23,7 +23,7 @@ export const EventOccurences = ({ event }: { event: Pick<BookerEvent, "recurring
);
const selectedTimeslot = useBookerStore((state) => state.selectedTimeslot);
const bookerState = useBookerStore((state) => state.state);
const { timezone, timeFormat } = useTimePreferences();
const { timezone, timeFormat } = useBookerTime();
const [warning, setWarning] = useState(false);
// Set initial value in booker store.
useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useEffect, useMemo, useRef } from "react";

import { useTimePreferences } from "@calcom/features/bookings/lib/timePreferences";
import { classNames } from "@calcom/lib";

import { useBookerTime } from "../../../bookings/Booker/components/hooks/useBookerTime";
import { useCalendarStore } from "../state/store";
import "../styles/styles.css";
import type { CalendarComponentProps } from "../types/state";
Expand All @@ -23,7 +23,7 @@ export function Calendar(props: CalendarComponentProps) {
const containerOffset = useRef<HTMLDivElement | null>(null);
const schedulerGrid = useRef<HTMLOListElement | null>(null);
const initialState = useCalendarStore((state) => state.initState);
const { timezone } = useTimePreferences();
const { timezone } = useBookerTime();

const startDate = useCalendarStore((state) => state.startDate);
const endDate = useCalendarStore((state) => state.endDate);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect, useState, useRef } from "react";

import dayjs from "@calcom/dayjs";
import { useTimePreferences } from "@calcom/features/bookings/lib";

import { useBookerTime } from "../../../../bookings/Booker/components/hooks/useBookerTime";
import { useCalendarStore } from "../../state/store";

function calculateMinutesFromStart(startHour: number, currentHour: number, currentMinute: number) {
Expand All @@ -19,7 +19,7 @@ export function CurrentTime() {
startHour: state.startHour || 0,
endHour: state.endHour || 23,
}));
const { timeFormat, timezone } = useTimePreferences();
const { timeFormat, timezone } = useBookerTime();

useEffect(() => {
// Set the container scroll position based on the current time.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { shallow } from "zustand/shallow";

import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import { useTimePreferences } from "@calcom/features/bookings/lib";
import { classNames } from "@calcom/lib";

import { OutOfOfficeInSlots } from "../../../../bookings/Booker/components/OutOfOfficeInSlots";
import { useBookerTime } from "../../../../bookings/Booker/components/hooks/useBookerTime";
import { useCalendarStore } from "../../state/store";
import type { CalendarAvailableTimeslots } from "../../types/state";
import type { GridCellToDateProps } from "../../utils";
Expand Down Expand Up @@ -39,7 +39,7 @@ type AvailableCellProps = {
};

export function AvailableCellsForDay({ availableSlots, day, startHour }: AvailableCellProps) {
const { timezone } = useTimePreferences();
const { timezone } = useBookerTime();
const date = dayjs(day);
const dateFormatted = date.format("YYYY-MM-DD");
const slotsForToday = availableSlots && availableSlots[dateFormatted];
Expand Down Expand Up @@ -136,7 +136,7 @@ type CellProps = {
};

function Cell({ isDisabled, topOffsetMinutes, timeSlot }: CellProps) {
const { timeFormat } = useTimePreferences();
const { timeFormat } = useBookerTime();

const { onEmptyCellClick, hoverEventDuration } = useCalendarStore(
(state) => ({
Expand Down
Loading

0 comments on commit f6dd403

Please sign in to comment.