diff --git a/apps/web/modules/bookings/components/BookingDetailsSheet.tsx b/apps/web/modules/bookings/components/BookingDetailsSheet.tsx index ee9bdfc607..0532bdc9bc 100644 --- a/apps/web/modules/bookings/components/BookingDetailsSheet.tsx +++ b/apps/web/modules/bookings/components/BookingDetailsSheet.tsx @@ -4,6 +4,7 @@ import dayjs from "@calcom/dayjs"; import { useBookingLocation } from "@calcom/features/bookings/hooks"; import { shouldShowFieldInCustomResponses } from "@calcom/lib/bookings/SystemField"; import { formatPrice } from "@calcom/lib/currencyConversions"; +import { formatToLocalizedTimezone } from "@calcom/lib/dayjs"; import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage"; import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl"; import { useLocale } from "@calcom/lib/hooks/useLocale"; @@ -445,14 +446,20 @@ function DisplayTimestamp({ endTime: Date | dayjs.Dayjs; timeZone?: string; }) { + const { + i18n: { language }, + } = useLocale(); const start = startTime instanceof Date ? dayjs(startTime).tz(timeZone) : startTime; const end = endTime instanceof Date ? dayjs(endTime).tz(timeZone) : endTime; + const localizedTimezone = timeZone + ? formatToLocalizedTimezone(start, language, timeZone) ?? timeZone + : start.format("Z"); return ( <> {start.format("dddd, MMMM D, YYYY")} - {start.format("h:mma")} - {end.format("h:mma")} ({timeZone || start.format("Z")}) + {start.format("h:mma")} - {end.format("h:mma")} ({localizedTimezone}) ); @@ -507,6 +514,9 @@ function WhoSection({ booking }: { booking: BookingOutput }) { />

{name}

+ {attendee.phoneNumber && ( +

{attendee.phoneNumber}

+ )}

{attendee.email}

diff --git a/packages/lib/dayjs/formatToLocalizedTimezone.test.ts b/packages/lib/dayjs/formatToLocalizedTimezone.test.ts new file mode 100644 index 0000000000..60371bc61c --- /dev/null +++ b/packages/lib/dayjs/formatToLocalizedTimezone.test.ts @@ -0,0 +1,91 @@ +import { describe, expect, it, beforeAll, vi } from "vitest"; + +import dayjs from "@calcom/dayjs"; + +import { formatToLocalizedTimezone } from "./index"; + +beforeAll(() => { + vi.setSystemTime(dayjs.utc("2024-06-15T12:00:00Z").toDate()); +}); + +describe("formatToLocalizedTimezone", () => { + it("returns a localized timezone string for a Date object with explicit timezone", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const result = formatToLocalizedTimezone(date, "en", "America/New_York"); + expect(result).toBeDefined(); + expect(typeof result).toBe("string"); + // Should contain recognizable timezone name like "Eastern Daylight Time" + expect(result!.length).toBeGreaterThan(0); + }); + + it("returns a localized timezone string for a Dayjs object with explicit timezone", () => { + const date = dayjs.utc("2024-06-15T12:00:00Z"); + const result = formatToLocalizedTimezone(date, "en", "America/New_York"); + expect(result).toBeDefined(); + expect(typeof result).toBe("string"); + expect(result!.length).toBeGreaterThan(0); + }); + + it("returns consistent results for Date and Dayjs objects with same timezone", () => { + const jsDate = new Date("2024-06-15T12:00:00Z"); + const djsDate = dayjs.utc("2024-06-15T12:00:00Z"); + const resultDate = formatToLocalizedTimezone(jsDate, "en", "America/New_York"); + const resultDayjs = formatToLocalizedTimezone(djsDate, "en", "America/New_York"); + expect(resultDate).toBe(resultDayjs); + }); + + it("returns different results for different timezones", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const nyResult = formatToLocalizedTimezone(date, "en", "America/New_York"); + const tokyoResult = formatToLocalizedTimezone(date, "en", "Asia/Tokyo"); + expect(nyResult).not.toBe(tokyoResult); + }); + + it("returns a short timezone name when timeZoneName is 'short'", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const longResult = formatToLocalizedTimezone(date, "en", "America/New_York", "long"); + const shortResult = formatToLocalizedTimezone(date, "en", "America/New_York", "short"); + expect(shortResult).toBeDefined(); + expect(longResult).toBeDefined(); + // Short name should be shorter than or equal to long name + expect(shortResult!.length).toBeLessThanOrEqual(longResult!.length); + }); + + it("defaults to long timezone name when timeZoneName is not provided", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const defaultResult = formatToLocalizedTimezone(date, "en", "America/New_York"); + const longResult = formatToLocalizedTimezone(date, "en", "America/New_York", "long"); + expect(defaultResult).toBe(longResult); + }); + + it("works with undefined locale (falls back to environment default)", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const result = formatToLocalizedTimezone(date, undefined, "America/New_York"); + expect(result).toBeDefined(); + expect(typeof result).toBe("string"); + expect(result!.length).toBeGreaterThan(0); + }); + + it("handles UTC timezone", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const result = formatToLocalizedTimezone(date, "en", "UTC"); + expect(result).toBeDefined(); + expect(result).toContain("Coordinated Universal Time"); + }); + + it("handles Europe/London timezone", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const result = formatToLocalizedTimezone(date, "en", "Europe/London"); + expect(result).toBeDefined(); + expect(typeof result).toBe("string"); + expect(result!.length).toBeGreaterThan(0); + }); + + it("handles Pacific/Auckland timezone", () => { + const date = new Date("2024-06-15T12:00:00Z"); + const result = formatToLocalizedTimezone(date, "en", "Pacific/Auckland"); + expect(result).toBeDefined(); + expect(typeof result).toBe("string"); + expect(result!.length).toBeGreaterThan(0); + }); +});