diff --git a/apps/web/components/eventtype/EventAvailabilityTab.tsx b/apps/web/components/eventtype/EventAvailabilityTab.tsx index 49fd8824b9..eaa585e274 100644 --- a/apps/web/components/eventtype/EventAvailabilityTab.tsx +++ b/apps/web/components/eventtype/EventAvailabilityTab.tsx @@ -10,6 +10,7 @@ import type { AvailabilityOption, FormValues } from "@calcom/features/eventtypes import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { weekdayNames } from "@calcom/lib/weekday"; +import { weekStartNum } from "@calcom/lib/weekstart"; import { SchedulingType } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc/react"; import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery"; @@ -87,14 +88,16 @@ const EventTypeScheduleDetails = memo( { enabled: !!scheduleId || !!loggedInUser?.defaultScheduleId || !!selectedScheduleValue } ); + const weekStart = weekStartNum(loggedInUser?.weekStart); + const filterDays = (dayNum: number) => - schedule?.schedule.filter((item) => item.days.includes((dayNum + 1) % 7)) || []; + schedule?.schedule.filter((item) => item.days.includes((dayNum + weekStart) % 7)) || []; return (
    - {weekdayNames(i18n.language, 1, "long").map((day, index) => { + {weekdayNames(i18n.language, weekStart, "long").map((day, index) => { const isAvailable = !!filterDays(index).length; return (
  1. diff --git a/apps/web/pages/availability/index.tsx b/apps/web/pages/availability/index.tsx index 569b47fbcf..6c0713c75e 100644 --- a/apps/web/pages/availability/index.tsx +++ b/apps/web/pages/availability/index.tsx @@ -125,6 +125,7 @@ export function AvailabilityList({ schedules }: RouterOutputs["viewer"]["availab displayOptions={{ hour12: meQuery.data?.timeFormat ? meQuery.data.timeFormat === 12 : undefined, timeZone: meQuery.data?.timeZone, + weekStart: meQuery.data?.weekStart || "Sunday", }} key={schedule.id} schedule={schedule} diff --git a/packages/features/schedules/components/ScheduleListItem.tsx b/packages/features/schedules/components/ScheduleListItem.tsx index ab66b23030..3212a110d0 100644 --- a/packages/features/schedules/components/ScheduleListItem.tsx +++ b/packages/features/schedules/components/ScheduleListItem.tsx @@ -3,6 +3,7 @@ import { Fragment } from "react"; import { availabilityAsString } from "@calcom/lib/availability"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { sortAvailabilityStrings } from "@calcom/lib/weekstart"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; import { @@ -30,6 +31,7 @@ export function ScheduleListItem({ displayOptions?: { timeZone?: string; hour12?: boolean; + weekStart?: string; }; isDeletable: boolean; updateDefault: ({ scheduleId, isDefault }: { scheduleId: number; isDefault: boolean }) => void; @@ -58,12 +60,17 @@ export function ScheduleListItem({

    {schedule.availability .filter((availability) => !!availability.days.length) - .map((availability) => ( - - {availabilityAsString(availability, { - locale: i18n.language, - hour12: displayOptions?.hour12, - })} + .map((availability) => + availabilityAsString(availability, { + locale: i18n.language, + hour12: displayOptions?.hour12, + }) + ) + // sort the availability strings as per user's weekstart (settings) + .sort(sortAvailabilityStrings(i18n.language, displayOptions?.weekStart)) + .map((availabilityString, index) => ( + + {availabilityString}
    ))} diff --git a/packages/lib/weekstart.test.ts b/packages/lib/weekstart.test.ts new file mode 100644 index 0000000000..0cfecbf275 --- /dev/null +++ b/packages/lib/weekstart.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, it } from "vitest"; + +import { sortAvailabilityStrings } from "./weekstart"; + +describe("Weekstart tests", () => { + describe("fn: sortAvailabilityStrings", () => { + it("should sort the availability strings when changing weekstart from Sunday to Monday", () => { + const input = [ + "Sun, 11:45 AM - 5:00 PM", + "Mon, 7:45 AM - 4:15 PM", + "Tue, 9:30 AM - 5:00 PM", + "Wed, 9:15 AM - 5:00 PM", + "Thu, 9:00 AM - 5:00 PM", + "Fri, 7:45 AM - 5:00 PM", + "Sat, 10:00 AM - 5:00 PM", + ]; + + const expected = [ + "Mon, 7:45 AM - 4:15 PM", + "Tue, 9:30 AM - 5:00 PM", + "Wed, 9:15 AM - 5:00 PM", + "Thu, 9:00 AM - 5:00 PM", + "Fri, 7:45 AM - 5:00 PM", + "Sat, 10:00 AM - 5:00 PM", + "Sun, 11:45 AM - 5:00 PM", + ]; + + const result = input.sort(sortAvailabilityStrings("en-US", "Monday")); + + expect(result).toEqual(expected); + }); + + it("should sort the availability strings when changing weekstart from Monday to Sunday", () => { + const input = [ + "Mon - Tue, Thu 7:45 AM - 4:15 PM", + "Tue, 5:00 PM - 8:00 PM", + "Wed, 9:15 AM - 5:00 PM", + "Fri, 7:45 AM - 5:00 PM", + "Sat, 10:00 AM - 5:00 PM", + "Sun, 11:45 AM - 5:00 PM", + ]; + + const expected = [ + "Sun, 11:45 AM - 5:00 PM", + "Mon - Tue, Thu 7:45 AM - 4:15 PM", + "Tue, 5:00 PM - 8:00 PM", + "Wed, 9:15 AM - 5:00 PM", + "Fri, 7:45 AM - 5:00 PM", + "Sat, 10:00 AM - 5:00 PM", + ]; + + const result = input.sort(sortAvailabilityStrings("en-US", "Sunday")); + + expect(result).toEqual(expected); + }); + + it("should sort the availability strings as per the weekstart (random to tuesday)", () => { + // this input scenario is not possible to occur, as regardless of any day as start of week, + // the weekdays always occur consecutively. But, this to test the sorting function in any case. + const input = [ + "Thu, Mon 7:45 AM - 8:45 AM", + "Sat, 10:00 AM - 10:30 AM", + "Tue, Fri 4:00 PM - 4:30 PM", + "Tue, 5:00 PM - 8:00 PM", + "Tue, Sun 9:00 AM - 9:30 AM", + "Wed - Thu, Sat 11:00 AM - 11:30 AM", + ]; + + const expected = [ + "Tue, Fri 4:00 PM - 4:30 PM", + "Tue, 5:00 PM - 8:00 PM", + "Tue, Sun 9:00 AM - 9:30 AM", + "Wed - Thu, Sat 11:00 AM - 11:30 AM", + "Thu, Mon 7:45 AM - 8:45 AM", + "Sat, 10:00 AM - 10:30 AM", + ]; + + const result = input.sort(sortAvailabilityStrings("en-US", "Tuesday")); + + expect(result).toEqual(expected); + }); + }); +}); diff --git a/packages/lib/weekstart.ts b/packages/lib/weekstart.ts new file mode 100644 index 0000000000..53a394ea1a --- /dev/null +++ b/packages/lib/weekstart.ts @@ -0,0 +1,23 @@ +import { weekdayNames } from "./weekday"; + +// returns index of input weekName(long) from array starting from Sunday +// as fall back returns 0 i.e. Sunday +export function weekStartNum(weekName = "Sunday") { + const weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + const idx = weekDays.indexOf(weekName); + return (idx !== -1 ? idx : 0) as 0 | 1 | 2 | 3 | 4 | 5 | 6; +} + +// sorts the availability strings based on the weekStart +export function sortAvailabilityStrings(language: string, weekStart = "Sunday") { + return (a: string, b: string) => { + const weekNames = weekdayNames(language, weekStartNum(weekStart), "short"); + const weekIndex = (day: string) => { + for (let i = 0; i < weekNames.length; i++) { + if (day.includes(weekNames[i])) return i; + } + return -1; + }; + return weekIndex(a) - weekIndex(b); + }; +} diff --git a/packages/platform/atoms/availability/AvailabilitySettings.tsx b/packages/platform/atoms/availability/AvailabilitySettings.tsx index 65f164548a..7049b6d0ca 100644 --- a/packages/platform/atoms/availability/AvailabilitySettings.tsx +++ b/packages/platform/atoms/availability/AvailabilitySettings.tsx @@ -10,6 +10,7 @@ import WebShell from "@calcom/features/shell/Shell"; import { availabilityAsString } from "@calcom/lib/availability"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { sortAvailabilityStrings } from "@calcom/lib/weekstart"; import type { RouterOutputs } from "@calcom/trpc/react"; import type { TimeRange, WorkingHours } from "@calcom/types/schedule"; import { @@ -291,11 +292,17 @@ export function AvailabilitySettings({ schedule ? ( schedule.schedule .filter((availability) => !!availability.days.length) - .map((availability) => ( - - {availabilityAsString(availability, { locale: i18n.language, hour12: timeFormat === 12 })} + .map((availability) => + availabilityAsString(availability, { + locale: i18n.language, + hour12: timeFormat === 12, + }) + ) + // sort the availability strings as per user's weekstart (settings) + .sort(sortAvailabilityStrings(i18n.language, weekStart)) + .map((availabilityString, index) => ( + + {availabilityString}
    )) diff --git a/packages/platform/atoms/availability/wrappers/AvailabilitySettingsPlatformWrapper.tsx b/packages/platform/atoms/availability/wrappers/AvailabilitySettingsPlatformWrapper.tsx index 7c4bc43adc..ac01bfa691 100644 --- a/packages/platform/atoms/availability/wrappers/AvailabilitySettingsPlatformWrapper.tsx +++ b/packages/platform/atoms/availability/wrappers/AvailabilitySettingsPlatformWrapper.tsx @@ -99,7 +99,7 @@ export const AvailabilitySettingsPlatformWrapper = ({ handleSubmit={async (data) => { atomSchedule.id && handleUpdate(atomSchedule.id, data); }} - weekStart="Sunday" + weekStart={me?.data?.weekStart || "Sunday"} timeFormat={timeFormat} enableOverrides={enableOverrides} isLoading={isLoading}