Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5980343
Revert "improve transition"
devin-ai-integration[bot] Jul 6, 2026
48feaf4
Revert "size transition component"
devin-ai-integration[bot] Jul 6, 2026
67b9fa3
feat(booker): animate step 1->2 with motion instead of custom SizeTra…
devin-ai-integration[bot] Jul 6, 2026
d0e16cb
fix(booker): remove layout=position from steps to stop horizontal slide
devin-ai-integration[bot] Jul 6, 2026
6fb663b
merge feat/atoms: keep motion step transition, drop size-transition
devin-ai-integration[bot] Jul 6, 2026
a7a23c9
feat(booker): drive real width/height with motion animate + AnimatePr…
devin-ai-integration[bot] Jul 6, 2026
cfcae4d
refactor(booker): extract step resize into hook, autofocus confirm input
devin-ai-integration[bot] Jul 6, 2026
4efce4f
mc
pasqualevitiello Jul 6, 2026
49f680d
build reg
pasqualevitiello Jul 6, 2026
9ea99bf
fix(booker): trigger step resize on step-value change, not first-rend…
devin-ai-integration[bot] Jul 6, 2026
08a28d7
chore(booker): TEMP diagnostic logging for step resize
devin-ai-integration[bot] Jul 6, 2026
9b6b00a
fix(booker): FLIP from resting size so step resize animates every time
devin-ai-integration[bot] Jul 6, 2026
f2ae67f
simplify motion
pasqualevitiello Jul 6, 2026
275237f
remove comments
pasqualevitiello Jul 6, 2026
bc310f7
more optimisations
pasqualevitiello Jul 6, 2026
7fed84a
mc
pasqualevitiello Jul 6, 2026
96723c3
build reg
pasqualevitiello Jul 6, 2026
c43e623
complete form
pasqualevitiello Jul 6, 2026
2208a24
form improvements
pasqualevitiello Jul 8, 2026
ffbb5c0
mc
pasqualevitiello Jul 8, 2026
959b73c
build reg
pasqualevitiello Jul 8, 2026
62bdb4f
move the data info
pasqualevitiello Jul 8, 2026
7aca8ba
implement form validation
pasqualevitiello Jul 8, 2026
6b24e9d
icons alignment
pasqualevitiello Jul 8, 2026
96faac8
submit form implementation
pasqualevitiello Jul 13, 2026
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
1 change: 1 addition & 0 deletions apps/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"jotai": "^2.15.1",
"lucide-react": "^0.555.0",
"marked": "^18.0.5",
"motion": "12.42.0",
"next": "16.2.5",
"react": "^19.2.6",
"react-day-picker": "^9.13.0",
Expand Down
38 changes: 27 additions & 11 deletions apps/ui/public/r/booker-1.json

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions apps/ui/public/r/cal-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
{
"path": "registry/default/lib/cal-api/event-types.ts",
"content": "import \"server-only\";\n\nimport { calApi } from \"./client\";\nimport type { EventType } from \"./types\";\n\nconst EVENT_TYPES_API_VERSION = \"2024-06-14\";\n\nexport async function listEventTypes(params: {\n username?: string;\n usernames?: string[];\n teamId?: number;\n teamSlug?: string;\n orgId?: number;\n orgSlug?: string;\n isTeamEvent?: boolean;\n eventSlug?: string;\n}): Promise<EventType[]> {\n const cacheKey =\n params.teamId?.toString() ??\n params.teamSlug ??\n params.usernames?.join(\",\") ??\n params.username ??\n \"all\";\n\n return calApi<EventType[]>(\"/event-types\", {\n apiVersion: EVENT_TYPES_API_VERSION,\n next: { revalidate: 60, tags: [\"event-types\", cacheKey] },\n query: {\n eventSlug: params.eventSlug,\n isTeamEvent: params.isTeamEvent,\n orgId: params.orgId,\n orgSlug: params.orgSlug,\n teamId: params.teamId,\n teamSlug: params.teamSlug,\n username: params.username,\n usernames: params.usernames?.join(\",\"),\n },\n });\n}\n\nexport async function getEventType(params: {\n username: string;\n eventSlug: string;\n orgId?: number;\n orgSlug?: string;\n}): Promise<EventType | null> {\n const matches = await listEventTypes(params);\n return matches[0] ?? null;\n}\n\nexport async function getTeamEventType(params: {\n teamId: number;\n eventSlug: string;\n orgId?: number;\n}): Promise<EventType | null> {\n const matches = await listEventTypes({\n eventSlug: params.eventSlug,\n isTeamEvent: true,\n orgId: params.orgId,\n teamId: params.teamId,\n });\n return matches[0] ?? null;\n}\n\nexport async function getTeamSlugEventType(params: {\n teamSlug: string;\n eventSlug: string;\n orgId?: number;\n orgSlug?: string;\n}): Promise<EventType | null> {\n const matches = await listEventTypes({\n eventSlug: params.eventSlug,\n isTeamEvent: true,\n orgId: params.orgId,\n orgSlug: params.orgSlug,\n teamSlug: params.teamSlug,\n });\n return matches[0] ?? null;\n}\n\nexport async function getDynamicEventType(params: {\n usernames: string[];\n orgId?: number;\n orgSlug?: string;\n eventSlug?: string;\n}): Promise<EventType | null> {\n const matches = await listEventTypes({\n eventSlug: params.eventSlug ?? \"dynamic\",\n orgId: params.orgId,\n orgSlug: params.orgSlug,\n usernames: params.usernames,\n });\n return matches[0] ?? null;\n}\n\nexport async function getEventTypeById(\n eventTypeId: number,\n): Promise<EventType> {\n return calApi<EventType>(`/event-types/${eventTypeId}`, {\n apiVersion: EVENT_TYPES_API_VERSION,\n next: { revalidate: 60, tags: [`event-type-${eventTypeId}`] },\n });\n}\n",
"content": "import \"server-only\";\n\nimport { calApi } from \"./client\";\nimport type { EventType } from \"./types\";\n\nconst EVENT_TYPES_API_VERSION = \"2024-06-14\";\n\nfunction findEventTypeBySlug(\n matches: EventType[],\n eventSlug: string,\n): EventType | null {\n return matches.find((event) => event.slug === eventSlug) ?? null;\n}\n\nexport async function listEventTypes(params: {\n username?: string;\n usernames?: string[];\n teamId?: number;\n teamSlug?: string;\n orgId?: number;\n orgSlug?: string;\n isTeamEvent?: boolean;\n eventSlug?: string;\n}): Promise<EventType[]> {\n const cacheKey =\n params.teamId?.toString() ??\n params.teamSlug ??\n params.usernames?.join(\",\") ??\n params.username ??\n \"all\";\n\n return calApi<EventType[]>(\"/event-types\", {\n apiVersion: EVENT_TYPES_API_VERSION,\n next: { revalidate: 60, tags: [\"event-types\", cacheKey] },\n query: {\n eventSlug: params.eventSlug,\n isTeamEvent: params.isTeamEvent,\n orgId: params.orgId,\n orgSlug: params.orgSlug,\n teamId: params.teamId,\n teamSlug: params.teamSlug,\n username: params.username,\n usernames: params.usernames?.join(\",\"),\n },\n });\n}\n\nexport async function getEventType(params: {\n username: string;\n eventSlug: string;\n orgId?: number;\n orgSlug?: string;\n}): Promise<EventType | null> {\n const matches = await listEventTypes(params);\n return findEventTypeBySlug(matches, params.eventSlug);\n}\n\nexport async function getTeamEventType(params: {\n teamId: number;\n eventSlug: string;\n orgId?: number;\n}): Promise<EventType | null> {\n const matches = await listEventTypes({\n eventSlug: params.eventSlug,\n isTeamEvent: true,\n orgId: params.orgId,\n teamId: params.teamId,\n });\n return findEventTypeBySlug(matches, params.eventSlug);\n}\n\nexport async function getTeamSlugEventType(params: {\n teamSlug: string;\n eventSlug: string;\n orgId?: number;\n orgSlug?: string;\n}): Promise<EventType | null> {\n const matches = await listEventTypes({\n eventSlug: params.eventSlug,\n isTeamEvent: true,\n orgId: params.orgId,\n orgSlug: params.orgSlug,\n teamSlug: params.teamSlug,\n });\n return findEventTypeBySlug(matches, params.eventSlug);\n}\n\nexport async function getDynamicEventType(params: {\n usernames: string[];\n orgId?: number;\n orgSlug?: string;\n eventSlug?: string;\n}): Promise<EventType | null> {\n const eventSlug = params.eventSlug ?? \"dynamic\";\n const matches = await listEventTypes({\n eventSlug,\n orgId: params.orgId,\n orgSlug: params.orgSlug,\n usernames: params.usernames,\n });\n return findEventTypeBySlug(matches, eventSlug);\n}\n\nexport async function getEventTypeById(\n eventTypeId: number,\n): Promise<EventType> {\n return calApi<EventType>(`/event-types/${eventTypeId}`, {\n apiVersion: EVENT_TYPES_API_VERSION,\n next: { revalidate: 60, tags: [`event-type-${eventTypeId}`] },\n });\n}\n",
"type": "registry:lib",
"target": "lib/cal-api/event-types.ts"
},
Expand All @@ -38,9 +38,15 @@
},
{
"path": "registry/default/lib/cal-api/types.ts",
"content": "export type ApiSuccess<T> = {\n status: \"success\";\n data: T;\n};\n\nexport type ApiError = {\n status: \"error\";\n timestamp?: string;\n path?: string;\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n};\n\nexport type ApiResponse<T> = ApiSuccess<T> | ApiError;\n\nexport type EventTypeLocation = {\n type: string;\n address?: string;\n link?: string;\n hostPhoneNumber?: string;\n displayLocationPublicly?: boolean;\n};\n\nexport type EventTypeOwner = {\n id: number;\n username: string;\n name?: string | null;\n avatarUrl?: string | null;\n weekStart?: string;\n timeZone?: string;\n};\n\nexport type EventTypeTeam = {\n id: number;\n slug: string;\n name: string;\n bannerUrl?: string | null;\n logoUrl?: string | null;\n};\n\nexport type EventType = {\n id: number;\n slug: string;\n title: string;\n description?: string | null;\n lengthInMinutes: number;\n locations: EventTypeLocation[];\n bookingFields?: BookingField[];\n disableGuests?: boolean;\n hidden?: boolean;\n requiresConfirmation?: boolean;\n isInstantEvent?: boolean;\n ownerId?: number;\n teamId?: number;\n team?: EventTypeTeam;\n users?: EventTypeOwner[];\n hosts?: EventTypeOwner[];\n metadata?: Record<string, unknown>;\n};\n\nexport type BookingFieldType =\n | \"name\"\n | \"email\"\n | \"phone\"\n | \"text\"\n | \"textarea\"\n | \"number\"\n | \"select\"\n | \"multiselect\"\n | \"checkbox\"\n | \"radio\"\n | \"boolean\"\n | \"url\"\n | \"address\";\n\nexport type BookingField = {\n slug: string;\n type: BookingFieldType;\n label?: string;\n placeholder?: string;\n required?: boolean;\n disableOnPrefill?: boolean;\n hidden?: boolean;\n options?: Array<{ label: string; value: string }>;\n};\n\nexport type Slot = {\n start: string;\n attendees?: number;\n bookingUid?: string;\n};\n\nexport type AvailableSlots = Record<string, Slot[]>;\n\nexport type BookingAttendee = {\n name: string;\n email: string;\n timeZone: string;\n language?: string;\n phoneNumber?: string;\n};\n\nexport type Booking = {\n uid: string;\n id: number;\n title: string;\n status: \"accepted\" | \"pending\" | \"cancelled\" | \"rejected\" | \"awaiting_host\";\n start: string;\n end: string;\n duration: number;\n eventTypeId: number;\n eventType?: { id: number; slug: string; title?: string };\n attendees: BookingAttendee[];\n hosts: Array<{ id: number; name: string; email: string; username?: string }>;\n meetingUrl?: string | null;\n location?: string;\n absentHost?: boolean;\n createdAt?: string;\n updatedAt?: string;\n metadata?: Record<string, unknown>;\n rescheduledFromUid?: string;\n};\n\nexport type CreateBookingInput = {\n start: string;\n eventTypeId: number;\n attendee: BookingAttendee;\n guests?: string[];\n bookingFieldsResponses?: Record<string, unknown>;\n location?: string;\n metadata?: Record<string, unknown>;\n lengthInMinutes?: number;\n};\n",
"content": "export type ApiSuccess<T> = {\n status: \"success\";\n data: T;\n};\n\nexport type ApiError = {\n status: \"error\";\n timestamp?: string;\n path?: string;\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n};\n\nexport type ApiResponse<T> = ApiSuccess<T> | ApiError;\n\nexport type EventTypeLocation = {\n type: string;\n address?: string;\n link?: string;\n hostPhoneNumber?: string;\n displayLocationPublicly?: boolean;\n};\n\nexport type EventTypeOwner = {\n id: number;\n username: string;\n name?: string | null;\n avatarUrl?: string | null;\n weekStart?: string;\n timeZone?: string;\n};\n\nexport type EventTypeTeam = {\n id: number;\n slug: string;\n name: string;\n bannerUrl?: string | null;\n logoUrl?: string | null;\n};\n\nexport type EventType = {\n id: number;\n slug: string;\n title: string;\n description?: string | null;\n lengthInMinutes: number;\n locations: EventTypeLocation[];\n bookingFields?: BookingField[];\n disableGuests?: boolean;\n hidden?: boolean;\n requiresConfirmation?: boolean;\n isInstantEvent?: boolean;\n ownerId?: number;\n teamId?: number;\n team?: EventTypeTeam;\n users?: EventTypeOwner[];\n hosts?: EventTypeOwner[];\n metadata?: Record<string, unknown>;\n};\n\nexport type BookingFieldType =\n | \"name\"\n | \"email\"\n | \"phone\"\n | \"text\"\n | \"textarea\"\n | \"number\"\n | \"select\"\n | \"multiselect\"\n | \"checkbox\"\n | \"radio\"\n | \"boolean\"\n | \"url\"\n | \"address\";\n\nexport type BookingField = {\n slug: string;\n type: BookingFieldType;\n label?: string;\n placeholder?: string;\n required?: boolean;\n disableOnPrefill?: boolean;\n hidden?: boolean;\n options?: Array<{ label: string; value: string }>;\n};\n\nexport type Slot = {\n start: string;\n attendees?: number;\n bookingUid?: string;\n};\n\nexport type AvailableSlots = Record<string, Slot[]>;\n\nexport type BookingAttendee = {\n name: string;\n email: string;\n timeZone: string;\n language?: string;\n phoneNumber?: string;\n};\n\nexport type Booking = {\n uid: string;\n id: number;\n title: string;\n status: \"accepted\" | \"pending\" | \"cancelled\" | \"rejected\" | \"awaiting_host\";\n start: string;\n end: string;\n duration: number;\n eventTypeId: number;\n eventType?: { id: number; slug: string; title?: string };\n attendees: BookingAttendee[];\n hosts: Array<{ id: number; name: string; email: string; username?: string }>;\n meetingUrl?: string | null;\n location?: string;\n absentHost?: boolean;\n createdAt?: string;\n updatedAt?: string;\n metadata?: Record<string, unknown>;\n rescheduledFromUid?: string;\n};\n\nexport type BookingLocationInput =\n | { type: \"integration\"; integration: string }\n | { type: \"address\" }\n | { type: \"link\" }\n | { type: \"phone\" }\n | { type: \"organizersDefaultApp\" };\n\nexport type CreateBookingInput = {\n start: string;\n eventTypeId?: number;\n eventTypeSlug?: string;\n username?: string;\n teamSlug?: string;\n organizationSlug?: string;\n attendee: BookingAttendee;\n guests?: string[];\n bookingFieldsResponses?: Record<string, unknown>;\n location?: BookingLocationInput | string;\n metadata?: Record<string, unknown>;\n lengthInMinutes?: number;\n};\n",
"type": "registry:lib",
"target": "lib/cal-api/types.ts"
},
{
"path": "registry/default/lib/cal-api/bookings.ts",
"content": "import \"server-only\";\n\nimport { calApi } from \"./client\";\nimport type { Booking, CreateBookingInput } from \"./types\";\n\nexport async function createBooking(\n input: CreateBookingInput,\n): Promise<Booking> {\n return calApi<Booking>(\"/bookings\", {\n body: input,\n method: \"POST\",\n });\n}\n",
"type": "registry:lib",
"target": "lib/cal-api/bookings.ts"
}
],
"type": "registry:lib"
Expand Down
37 changes: 21 additions & 16 deletions apps/ui/public/r/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
"@coss/separator",
"@coss/sheet",
"@coss/sidebar",
"@coss/size-transition",
"@coss/skeleton",
"@coss/slider",
"@coss/spinner",
Expand Down Expand Up @@ -729,19 +728,6 @@
],
"type": "registry:ui"
},
{
"dependencies": [
"@base-ui/react"
],
"files": [
{
"path": "registry/default/ui/size-transition.tsx",
"type": "registry:ui"
}
],
"name": "size-transition",
"type": "registry:ui"
},
{
"css": {
"@keyframes skeleton": {
Expand Down Expand Up @@ -11343,7 +11329,8 @@
"dependencies": [
"isomorphic-dompurify",
"marked",
"lucide-react"
"lucide-react",
"motion"
],
"description": "A full scheduling flow powered by Cal.com API v2.",
"files": [
Expand All @@ -11352,6 +11339,16 @@
"target": "components/atoms/booker-1.tsx",
"type": "registry:block"
},
{
"path": "registry/default/atoms/booker/booker-confirm-form.tsx",
"target": "components/atoms/booker/booker-confirm-form.tsx",
"type": "registry:component"
},
{
"path": "registry/default/atoms/booker/booker-steps.tsx",
"target": "components/atoms/booker/booker-steps.tsx",
"type": "registry:component"
},
{
"path": "registry/default/atoms/booker/booker-calendar.tsx",
"target": "components/atoms/booker/booker-calendar.tsx",
Expand Down Expand Up @@ -11430,14 +11427,17 @@
"@coss/card",
"@coss/combobox",
"@coss/empty",
"@coss/field",
"@coss/form",
"@coss/group",
"@coss/input",
"@coss/label",
"@coss/popover",
"@coss/scroll-area",
"@coss/select",
"@coss/size-transition",
"@coss/skeleton",
"@coss/switch",
"@coss/textarea",
"@coss/tooltip"
],
"meta": {
Expand Down Expand Up @@ -11739,6 +11739,11 @@
"path": "registry/default/lib/cal-api/types.ts",
"target": "lib/cal-api/types.ts",
"type": "registry:lib"
},
{
"path": "registry/default/lib/cal-api/bookings.ts",
"target": "lib/cal-api/bookings.ts",
"type": "registry:lib"
}
],
"name": "cal-api",
Expand Down
Loading
Loading