Skip to content
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
2 changes: 1 addition & 1 deletion apps/web/test/lib/getSchedule/expects.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { diff } from "jest-diff";
import { expect } from "vitest";

import type { Slot } from "@calcom/trpc/server/routers/viewer/slots/types";
import type { Slot } from "@calcom/atoms/booker/types";

export const expectedSlotsForSchedule = {
IstWorkHours: {
Expand Down
12 changes: 6 additions & 6 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,17 @@
"patterns": [
{
"group": [
"@calcom/trpc/react",
"@calcom/trpc/react/**"
"@calcom/trpc",
"@calcom/trpc/**"
],
"message": "atoms package should not import from @calcom/trpc/react."
"message": "atoms package should not import from @calcom/trpc."
},
{
"group": [
"../../trpc/react",
"../../trpc/react/**"
"../../trpc",
"../../trpc/**"
],
"message": "atoms package should not import from trpc/react."
"message": "atoms package should not import from trpc."
}
]
}
Expand Down
32 changes: 31 additions & 1 deletion packages/platform/atoms/booker/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ import type {
ApiSuccessResponseWithoutData,
RoutingFormSearchParams,
} from "@calcom/platform-types";
import type { Slot } from "@calcom/trpc/server/routers/viewer/slots/types";

import type { UseCreateBookingInput } from "../hooks/bookings/useCreateBooking";

export type Slot = {
time: string;
userIds?: string[];
attendees?: number;
bookingUid?: string;
users?: string[];
};
Comment on lines +17 to +23
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the Slot type definition (lines 17-23)
cat -n packages/platform/atoms/booker/types.ts | sed -n '1,50p'

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 1870


🏁 Script executed:

# Let's also see the lines around 115-136 to view SlotInfo
cat -n packages/platform/atoms/booker/types.ts | sed -n '100,150p'

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 1207


🏁 Script executed:

# Search for usage of these types and ID comparisons
rg -n --type=ts 'userIds|toUser|fromUser' packages/platform/atoms/booker/ -A 2 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 1477


🏁 Script executed:

# Search for where Slot and SlotInfo are used/compared
rg -n --type=ts 'Slot\[|SlotInfo\[|\.userIds|\.toUser\.id|\.fromUser\.id' packages/platform/atoms/booker/ -A 1 -B 1

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 562


🏁 Script executed:

# Search for onTimeslotsLoaded callback usage to see how Slot[] is used
rg -n --type=ts --type=tsx 'onTimeslotsLoaded' packages/platform/ -A 5 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 113


🏁 Script executed:

# Search for GetAvailableSlotsResponse usage to see how SlotInfo is converted or used
rg -n --type=ts --type=tsx 'GetAvailableSlotsResponse' packages/platform/ -A 3 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 113


🏁 Script executed:

# Look for any slot transformation/conversion logic
rg -n --type=ts --type=tsx 'SlotInfo|toUser|fromUser' packages/platform/ -A 3 -B 1 | head -100

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 113


🏁 Script executed:

# Search for Slot type usage and API calls in the booker directory
rg -n --type=ts --type=tsx 'slots.*=|availableSlots' packages/platform/atoms/booker/ -A 2 -B 1

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 113


🏁 Script executed:

# Search for onTimeslotsLoaded callback usage
rg -n 'onTimeslotsLoaded' packages/platform/atoms/booker/ -A 5 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 2488


🏁 Script executed:

# Search for GetAvailableSlotsResponse usage to see how SlotInfo is converted
rg -n 'GetAvailableSlotsResponse' packages/platform/ -A 3 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 1849


🏁 Script executed:

# Look for slot transformation/conversion logic in the booker directory
rg -n 'SlotInfo|toUser.*id|fromUser.*id' packages/platform/atoms/booker/ -A 2 -B 1

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 535


🏁 Script executed:

# Search for where Slot type is mapped from API response (SlotInfo)
rg -n 'map.*Slot|transform.*Slot|convert.*Slot' packages/platform/atoms/booker/ -A 3

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 68


🏁 Script executed:

# Check if there are any type assertions or casting between Slot and SlotInfo
rg -n 'as Slot|as SlotInfo' packages/platform/atoms/booker/ -B 2 -A 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 68


🏁 Script executed:

# Find where schedule is defined in BookerPlatformWrapper.tsx
rg -n 'const schedule|useAvailableSlots' packages/platform/atoms/booker/BookerPlatformWrapper.tsx -A 5 -B 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 861


🏁 Script executed:

# Check the useAvailableSlots hook implementation for any transformation
cat -n packages/platform/atoms/hooks/useAvailableSlots.ts

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 1753


🏁 Script executed:

# Search for any slot transformation or mapping logic in the booker directory
rg -n 'SlotInfo.*Slot|Slot.*SlotInfo|slots\.map|slots\.forEach' packages/platform/atoms/booker/ -A 2

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 68


🏁 Script executed:

# Check for actual property access patterns on the slots passed to onTimeslotsLoaded
rg -n 'onTimeslotsLoaded' packages/platform/ -A 20 | head -60

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 5525


🏁 Script executed:

# Look for userIds or toUser access patterns in the booker component files
rg -n '\.userIds|\.toUser|\.fromUser' packages/platform/atoms/booker/ -B 3 -A 1

Repository: qodo-benchmark/cal.com-combined-coderabbit

Length of output: 68


Reconcile Slot and SlotInfo type definitions or transform API response before callback

onTimeslotsLoaded expects Record<string, Slot[]> but receives schedule.data.slots which is Record<string, SlotInfo[]>. These types have incompatible structures: Slot uses userIds: string[] while SlotInfo uses toUser: { id: number } and fromUser: { id: string }. Either transform the API response to match the Slot type before passing to the callback, or update the callback signature to accept SlotInfo.

🤖 Prompt for AI Agents
In `@packages/platform/atoms/booker/types.ts` around lines 17 - 23, The callback
mismatch: onTimeslotsLoaded expects Record<string, Slot[]> but
schedule.data.slots is Record<string, SlotInfo[]> with different fields
(Slot.userIds vs SlotInfo.toUser/fromUser). Fix by either transforming
schedule.data.slots into the Slot shape before invoking onTimeslotsLoaded (map
each SlotInfo to Slot by converting toUser/fromUser ids into userIds:string[]
and normalizing bookingUid/attendees/users), or by changing the callback/type to
accept Record<string, SlotInfo[]> and update any downstream consumers; locate
the types Slot and SlotInfo in types.ts and the call site where
onTimeslotsLoaded is invoked with schedule.data.slots to apply the
transformation or signature change.


// Type that includes only the data values from BookerStore (excluding functions)
export type BookerStoreValues = Omit<
BookerStore,
Expand Down Expand Up @@ -104,3 +111,26 @@ export type BookerPlatformWrapperAtomPropsForTeam = BookerPlatformWrapperAtomPro
routingFormSearchParams?: RoutingFormSearchParams;
rrHostSubsetIds?: number[];
};

type SlotInfo = {
time: string;
attendees?: number;
bookingUid?: string;
away?: boolean;
fromUser?: {
id: string;
displayName: string | null;
};
toUser?: {
id: number;
username: string | null;
displayName: string | null;
};
reason?: string;
emoji?: string;
showNotePublicly?: boolean;
};

export type GetAvailableSlotsResponse = {
slots: Record<string, SlotInfo[]>;
};
50 changes: 50 additions & 0 deletions packages/platform/atoms/hooks/schedules/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
type Schedule = {
id: number;
userId: number;
name: string;
timeZone: string | null;
};

export type CreateScheduleHandlerReturn = {
schedule: Schedule;
};

export type DuplicateScheduleHandlerReturn = {
schedule: Schedule;
};

export type GetAvailabilityListHandlerReturn = {
schedules: (Omit<Schedule, "userId"> & {
availability: {
id: number;
userId: number | null;
eventTypeId: number | null;
days: string[];
startTime: Date;
endTime: Date;
date: Date | null;
scheduleId: number | null;
}[];
isDefault: boolean;
})[];
};

export type CreateScheduleInput = {
name: string;
schedule?: { start: Date; end: Date }[][];
eventTypeId?: number;
};

export function validateCreateScheduleInput(input: unknown): CreateScheduleInput {
if (!input || typeof input !== 'object') {
throw new Error('Invalid input: must be an object');
}

const data = input as Record<string, unknown>;

if (typeof data.name !== 'string' || data.name.length === 0) {
throw new Error('Invalid input: name must be a non-empty string');
}

return data as CreateScheduleInput;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import type { ApiResponse, ApiErrorResponse, ApiSuccessResponse } from "@calcom/platform-types";
import type { CreateScheduleHandlerReturn } from "@calcom/trpc/server/routers/viewer/availability/schedule/create.handler";
import { TCreateInputSchema as CreateScheduleSchema } from "@calcom/trpc/server/routers/viewer/availability/schedule/create.schema";

import http from "../../lib/http";
import type { CreateScheduleHandlerReturn, CreateScheduleInput as CreateScheduleSchema } from "./types";
import { QUERY_KEY as SchedulesQueryKey } from "./useAtomGetAllSchedules";
import { QUERY_KEY as ScheduleQueryKey } from "./useAtomSchedule";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import type { ApiResponse, ApiErrorResponse } from "@calcom/platform-types";
import type { DuplicateScheduleHandlerReturn } from "@calcom/trpc/server/routers/viewer/availability/schedule/duplicate.handler";

import http from "../../lib/http";
import type { DuplicateScheduleHandlerReturn } from "./types";
import { QUERY_KEY as ScheduleQueryKey } from "./useAtomSchedule";

interface useAtomDuplicateScheduleOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { useQuery } from "@tanstack/react-query";

import { SUCCESS_STATUS } from "@calcom/platform-constants";
import type { ApiResponse } from "@calcom/platform-types";
import type { GetAvailabilityListHandlerReturn } from "@calcom/trpc/server/routers/viewer/availability/list.handler";

import http from "../../lib/http";
import type { GetAvailabilityListHandlerReturn } from "./types";
import { useAtomsContext } from "../useAtomsContext";

export const QUERY_KEY = "use-atom-user-schedules";
Expand Down
2 changes: 1 addition & 1 deletion packages/platform/atoms/hooks/useAvailableSlots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import type {
ApiResponse,
ApiSuccessResponse,
} from "@calcom/platform-types";
import type { GetAvailableSlotsResponse } from "@calcom/trpc/server/routers/viewer/slots/util";

import http from "../lib/http";
import type { GetAvailableSlotsResponse } from "../booker/types";

export const QUERY_KEY = "get-available-slots";

Expand Down
2 changes: 1 addition & 1 deletion packages/platform/atoms/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
"./add-members-switch/AddMembersWithSwitchPlatformWrapper": "./add-members-switch/AddMembersWithSwitchPlatformWrapper.tsx",
"./availability/AvailabilitySettings": "./availability/AvailabilitySettings.tsx",
"./booker": "./booker/index.ts",
"./booker/types": "./booker/types.ts",
"./selected-calendars/SelectedCalendarsSettings": "./selected-calendars/SelectedCalendarsSettings.tsx",
"./components/ui/shell": "./src/components/ui/shell.tsx",
"./dist/index.ts": "./index.ts",
Expand Down
2 changes: 0 additions & 2 deletions packages/platform/atoms/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
"../../dayjs",
"../../prisma/zod-utils.ts",
"../../prisma/zod",
"../../trpc/server/routers/viewer/slots",
"../../trpc/server/types",
"../../features/eventtypes",
"../../features/schedules",
"../../features/bookings/Booker",
Expand Down
8 changes: 0 additions & 8 deletions packages/trpc/server/routers/viewer/slots/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,6 @@ export const reserveSlotSchema = z
"Either slotUtcStartDate, slotUtcEndDate or eventTypeId should be filled in."
);

export type Slot = {
time: string;
userIds?: number[];
attendees?: number;
bookingUid?: string;
users?: string[];
};

export const removeSelectedSlotSchema = z.object({
uid: z.string().nullable(),
});
Expand Down
Loading