-
Notifications
You must be signed in to change notification settings - Fork 10.2k
feat: more atoms styles #22976
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: more atoms styles #22976
Conversation
WalkthroughThis change introduces styling customization hooks across scheduling and calendar atoms. It adds nested classNames APIs and types for CalendarSettings (selected and destination sections), DestinationCalendar, SelectedCalendars, AvailabilitySettings (dateOverride), and the schedule time picker. Schedule components gain SelectInnerClassNames and propagate timePicker classNames to LazySelect. AppListCard supports a classNameObject for container/title/description. Documentation is updated for AvailabilitySettings and CalendarSettings to reflect new props. Example pages are adjusted to pass the new classNames structures. A changeset bumps @calcom/atoms minor version. No business logic or data flow changes are included. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
TODO: document new styles props |
The latest updates on your projects. Learn more about Vercel for Git ↗︎ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (3)
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)
24-29
: Localize the fallback “Loading…” textPer guidelines, replace the hardcoded string with t("loading") and add the locale hook.
- <AtomsWrapper> - <> - {statusLoader} - {!statusLoader && <h1 className="m-5 text-xl font-semibold">Loading...</h1>} - </> - </AtomsWrapper> + <AtomsWrapper> + <> + {statusLoader} + {!statusLoader && <h1 className="m-5 text-xl font-semibold">{t("loading")}</h1>} + </> + </AtomsWrapper>Additional change needed outside this block:
+import { useLocale } from "@calcom/lib/hooks/useLocale"; ... export const DestinationCalendarSettingsPlatformWrapper = ({ statusLoader, classNames = "mx-5", classNamesObject, isDryRun = false, }: { ... }) => { + const { t } = useLocale();packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (2)
170-172
: Localize “Nameless calendar” fallbackUse t() for the fallback label to comply with localization guidelines.
- title={cal.name || "Nameless calendar"} - name={cal.name || "Nameless calendar"} + title={cal.name || t("nameless_calendar")} + name={cal.name || t("nameless_calendar")}
321-325
: Localize toast error messagesReplace hardcoded error strings with t() and interpolation.
- onError: (err) => { - toast({ - description: `Something went wrong while adding calendar - ${title}. ${err}`, - }); - }, + onError: (err) => { + toast({ + description: t("error_adding_calendar", { title, err: String(err) }), + }); + }, ... - onError: (err) => { - toast({ - description: `Something went wrong while removing calendar - ${title}. ${err}`, - }); - }, + onError: (err) => { + toast({ + description: t("error_removing_calendar", { title, err: String(err) }), + }); + },Also applies to: 329-335
🧹 Nitpick comments (9)
docs/platform/atoms/availability-settings.mdx (1)
134-135
: Docs: Good addition; also document scheduleClassNames.timePicker for completenessThe new dateOverrideClassNames section looks clear and actionable. Given the PR adds scheduleClassNames.timePicker as a public styling hook, please add a similar object-structure section for it so consumers understand the supported keys and how they map to the time picker UI parts.
I can draft the timePicker docs (container, valueContainer, value, input, dropdown) in the same format. Want me to push a patch?
Also applies to: 136-146
packages/ui/components/app-list-card/AppListCard.tsx (2)
25-29
: Make container optional to allow partial overridesRequiring container forces consumers to set it even when they only want to override title/description. Make it optional for flexibility.
-export type AppCardClassNames = { - container: string; +export type AppCardClassNames = { + container?: string; title?: string; description?: string; };
31-43
: Naming consistency: classNameObject vs classNamesObjectOther components in this PR (e.g., DestinationCalendarSettings) use classNamesObject. Consider aligning naming across the codebase for consistency.
packages/platform/examples/base/src/pages/availability.tsx (1)
76-81
: dateOverrideClassNames usage is correctKeys align with the new DateOverride API. Note that using Tailwind important (!) here may override theme defaults aggressively—ensure that’s intended in examples.
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (2)
19-31
: Avoid passing unknown props down to DestinationCalendarSelectorUsing {...props} passes classNames and classNamesObject into DestinationCalendarSelector, which doesn’t declare them. Prefer explicit prop forwarding to avoid accidental prop leakage.
-<DestinationCalendarSelector {...props} /> +const { + classNames: _dcClassNames, + classNamesObject: _dcClassNamesObject, + ...selectorProps +} = props; +<DestinationCalendarSelector {...selectorProps} />
25-29
: Naming consistency and composition look goodOuter container merges existing className string and nested container override; header classNames are applied per-part. Consider aligning naming (classNamesObject) with other components globally.
Also applies to: 43-54
docs/platform/atoms/calendar-settings.mdx (2)
73-81
: Document header.container for destinationCalendarSettingsClassNamesExamples showcase destination.header.container, but the table omits it. Add it for completeness and consistency with SelectedCalendars.
Proposed addition to the object structure table:
- header.container — Styles the header container
24-31
: React/MDX attribute casing for iframeUse React-compliant casing to avoid DOM property warnings in MDX.
- frameborder="0" + frameBorder="0" ... - allowfullscreen="true" + allowFullScreen={true}packages/platform/examples/base/src/pages/calendars.tsx (1)
14-14
: Nit: simplify boolean propallowDelete defaults to true; if you want to pass it explicitly, prefer shorthand.
- allowDelete={true} + allowDelete
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.changeset/mighty-wings-create.md
(1 hunks)docs/platform/atoms/availability-settings.mdx
(1 hunks)docs/platform/atoms/calendar-settings.mdx
(1 hunks)packages/features/schedules/components/Schedule.tsx
(8 hunks)packages/platform/atoms/availability/AvailabilitySettings.tsx
(6 hunks)packages/platform/atoms/availability/types.ts
(1 hunks)packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
(2 hunks)packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
(2 hunks)packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
(2 hunks)packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
(7 hunks)packages/platform/examples/base/src/pages/availability.tsx
(2 hunks)packages/platform/examples/base/src/pages/calendars.tsx
(1 hunks)packages/ui/components/app-list-card/AppListCard.tsx
(4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/platform/atoms/availability/types.ts
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/platform/atoms/availability/types.ts
packages/platform/examples/base/src/pages/availability.tsx
packages/ui/components/app-list-card/AppListCard.tsx
packages/platform/examples/base/src/pages/calendars.tsx
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/availability/AvailabilitySettings.tsx
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
packages/features/schedules/components/Schedule.tsx
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
Always use
t()
for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/platform/examples/base/src/pages/availability.tsx
packages/ui/components/app-list-card/AppListCard.tsx
packages/platform/examples/base/src/pages/calendars.tsx
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/availability/AvailabilitySettings.tsx
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
packages/features/schedules/components/Schedule.tsx
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
🧬 Code Graph Analysis (7)
packages/ui/components/app-list-card/AppListCard.tsx (1)
packages/ui/components/list/List.tsx (1)
ListItemText
(142-156)
packages/platform/examples/base/src/pages/calendars.tsx (1)
packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx (1)
CalendarSettings
(323-398)
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
DestinationCalendarClassNames
(14-17)
packages/platform/atoms/availability/AvailabilitySettings.tsx (1)
packages/lib/date-ranges.ts (1)
WorkingHours
(12-12)
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx (2)
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (2)
SelectedCalendarsClassNames
(33-56)SelectedCalendarsSettingsPlatformWrapper
(66-218)packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
DestinationCalendarClassNames
(14-17)
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
packages/platform/atoms/destination-calendar/DestinationCalendarSelector.tsx (1)
DestinationCalendarProps
(15-24)
packages/features/schedules/components/Schedule.tsx (1)
packages/platform/atoms/availability/types.ts (1)
scheduleClassNames
(24-38)
🔇 Additional comments (21)
.changeset/mighty-wings-create.md (1)
1-6
: Changeset is accurate and scoped correctlyMinor bump for new styling hooks is appropriate. No issues.
packages/platform/atoms/availability/types.ts (1)
31-37
: API extension LGTMAdding scheduleClassNames.timePicker with granular keys aligns with downstream usage in Schedule/TimeRangeField and examples. Type shape looks correct.
packages/ui/components/app-list-card/AppListCard.tsx (2)
63-67
: Container class merge order looks correcthighlight state composes with user-provided classes, and className takes precedence over classNameObject.container. Nice.
78-81
: Per-part overrides wired correctlyTitle and description merge defaults with overrides. Safe and non-breaking.
Also applies to: 87-91
packages/platform/atoms/availability/AvailabilitySettings.tsx (2)
71-76
: Public hook addition LGTMdateOverrideClassNames type is concise and matches the docs table (container, title, description, button).
197-203
: DateOverride styling pipeline is correctProp typing, usage of cn for merging defaults, and forwarding customClassNames?.dateOverrideClassNames are all well implemented.
Also applies to: 218-229, 253-257, 686-687
packages/platform/examples/base/src/pages/availability.tsx (1)
60-75
: Example styling hooks look correctscheduleClassNames and nested timePicker keys match the public types and Schedule component mapping. Good illustrative values.
packages/features/schedules/components/Schedule.tsx (3)
39-46
: SelectInnerClassNames type is appropriateKeys match internal react-select parts used by our Select wrapper. No concerns.
116-117
: Prop propagation to DayRanges looks goodIncluding timePicker in classNames ensures the new styles reach TimeRangeField. Nice.
114-118
: Select component already supports innerClassNames – no change required.We verified in
packages/ui/components/form/select/Select.tsx
that theSelect
Props interface includesinnerClassNames
(used throughout the component) and thatLazySelect
is correctly forwarding it via{...props}
. Styling overrides for inner elements will apply as intended.packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
8-17
: Type shapes LGTMDestinationHeaderClassnames and DestinationCalendarClassNames provide good granularity and keep container optional.
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)
10-16
: Propagate DestinationCalendarClassNames via classNamesObject: LGTMProp addition + forwarding is consistent and non-breaking.
Also applies to: 41-41
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx (2)
15-17
: New classNames shape: LGTMExtending CalendarSettingsPlatformWrapperProps.classNames with granular objects is clear and backward-compatible with existing ...CustomClassnames.
34-35
: Forwarding classNamesObject to child wrappers: LGTMProps are forwarded correctly to enable nested styling.
Also applies to: 42-42
docs/platform/atoms/calendar-settings.mdx (1)
50-52
: Docs mention new classNames objects: LGTMThe new rows clearly document the two props and align with the code changes.
packages/platform/examples/base/src/pages/calendars.tsx (1)
13-49
: Example shows correct nested classNames usage: LGTMThe example reflects the new public API and nested structure well.
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (5)
7-7
: cn import: LGTMUtility import is appropriate for merging defaults and overrides.
104-113
: List container override: LGTMClean fallback to "p-6 pt-2" and supports overrides via classNamesObject.
125-136
: AppListCard classNameObject mapping: LGTMSimple and flexible mapping for container/title/description. Good use of cn for merging.
150-163
: Body container/description className merge: LGTMMerges defaults with overrides properly. i18n for label is already handled with t("toggle_calendars_conflict").
220-231
: Header component classNames API: LGTMProp surface for container/title/description is clear and integrates well with cn().
Also applies to: 236-245
const handleFormSubmit = useCallback( | ||
(customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => { | ||
if (customCallbacks) { | ||
callbacksRef.current = customCallbacks; | ||
} | ||
|
||
if (saveButtonRef.current) { | ||
saveButtonRef.current.click(); | ||
} else { | ||
form.handleSubmit(async (data) => { | ||
try { | ||
await handleSubmit(data); | ||
callbacksRef.current?.onSuccess?.(); | ||
} catch (error) { | ||
callbacksRef.current?.onError?.(error as Error); | ||
} | ||
})(); | ||
} | ||
}, [form, handleSubmit]); | ||
if (saveButtonRef.current) { | ||
saveButtonRef.current.click(); | ||
} else { | ||
form.handleSubmit(async (data) => { | ||
try { | ||
await handleSubmit(data); | ||
callbacksRef.current?.onSuccess?.(); | ||
} catch (error) { | ||
callbacksRef.current?.onError?.(error as Error); | ||
} | ||
})(); | ||
} | ||
}, | ||
[form, handleSubmit] | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Bug: handleFormSubmit callbacks are not invoked when clicking the hidden Save button, and stale callbacks may persist
- If saveButtonRef.current exists, you trigger a click but never invoke callbacksRef.current.onSuccess/onError. Consumers passing callbacks to handleFormSubmit won’t see them called on the happy-path.
- If customCallbacks is not provided on subsequent calls, callbacksRef retains the previous ones (sticky behavior).
Fix options:
- Option A (simple): Always use form.handleSubmit(...) instead of clicking the button, and call callbacks in the submit handler.
- Option B (minimal change): Keep the button click, but wire callbacks into the wrapper so both manual save and programmatic save invoke the same callback ref. Also reset the ref when no custom callbacks are given.
Below is a minimal patch for Option B within this hunk to avoid sticky callbacks:
-const handleFormSubmit = useCallback(
- (customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => {
- if (customCallbacks) {
- callbacksRef.current = customCallbacks;
- }
+const handleFormSubmit = useCallback(
+ (customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => {
+ // Reset or set per-call callbacks
+ callbacksRef.current = customCallbacks ?? {};
if (saveButtonRef.current) {
saveButtonRef.current.click();
} else {
form.handleSubmit(async (data) => {
try {
await handleSubmit(data);
callbacksRef.current?.onSuccess?.();
} catch (error) {
callbacksRef.current?.onError?.(error as Error);
}
})();
}
},
[form, handleSubmit]
);
And apply this additional change to ensure callbacks also run when the form is submitted via the button click path (outside the selected lines):
// Around Line 635 (Form handleSubmit prop)
// Current:
handleSubmit={async (props) => {
handleSubmit(props);
}}
// Suggested:
handleSubmit={async (props) => {
try {
await handleSubmit(props);
callbacksRef.current?.onSuccess?.();
} catch (error) {
callbacksRef.current?.onError?.(error as Error);
}
}}
🤖 Prompt for AI Agents
In packages/platform/atoms/availability/AvailabilitySettings.tsx around lines
340 to 361, handleFormSubmit currently clicks a hidden save button and never
invokes the callbacksRef on success/error, and it also leaves prior callbacks
sticky when customCallbacks is omitted; change handleFormSubmit to set
callbacksRef.current = customCallbacks ?? undefined (clear when not provided)
and always call form.handleSubmit(async data => { try { await
handleSubmit(data); callbacksRef.current?.onSuccess?.(); } catch (e) {
callbacksRef.current?.onError?.(e as Error); } })() instead of only clicking the
save button; additionally update the Form component’s handleSubmit prop (around
line ~635) to wrap the existing handleSubmit call in the same try/catch that
invokes callbacksRef.current?.onSuccess/onError so both button-driven and
programmatic submits trigger the callbacks.
@@ -1,12 +1,19 @@ | |||
import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix potentially broken import path for DestinationCalendarClassNames
This bare path likely won’t resolve consistently. Use the same relative base used elsewhere in this file.
-import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar";
+import type { DestinationCalendarClassNames } from "../../destination-calendar/DestinationCalendar";
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar"; | |
import type { DestinationCalendarClassNames } from "../../destination-calendar/DestinationCalendar"; |
🤖 Prompt for AI Agents
In
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
around line 1, the import uses a bare module specifier import type {
DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar";
which may not resolve reliably; replace this with the same relative path base
used by other imports in this file (i.e., change the bare specifier to the
file-relative path used elsewhere for the destination-calendar module) so the
import resolves consistently across environments.
export type SelectedCalendarsClassNames = { | ||
container?: string; | ||
header?: { | ||
container?: string; | ||
title?: string; | ||
description?: string; | ||
}; | ||
selectedCalendarsListClassNames?: { | ||
container?: string; | ||
selectedCalendar: { | ||
container?: string; | ||
header?: { | ||
container: string; | ||
title?: string; | ||
description?: string; | ||
}; | ||
body?: { | ||
container?: string; | ||
description?: string; | ||
}; | ||
}; | ||
}; | ||
noSelectedCalendarsMessage?: string; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make header.container optional in SelectedCalendarsClassNames
Currently required, unlike adjacent optional fields; better to make it optional for ergonomic usage and consistency.
export type SelectedCalendarsClassNames = {
container?: string;
header?: {
- container?: string;
+ container?: string;
title?: string;
description?: string;
};
selectedCalendarsListClassNames?: {
container?: string;
selectedCalendar: {
container?: string;
header?: {
- container: string;
+ container?: string;
title?: string;
description?: string;
};
body?: {
container?: string;
description?: string;
};
};
};
noSelectedCalendarsMessage?: string;
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export type SelectedCalendarsClassNames = { | |
container?: string; | |
header?: { | |
container?: string; | |
title?: string; | |
description?: string; | |
}; | |
selectedCalendarsListClassNames?: { | |
container?: string; | |
selectedCalendar: { | |
container?: string; | |
header?: { | |
container: string; | |
title?: string; | |
description?: string; | |
}; | |
body?: { | |
container?: string; | |
description?: string; | |
}; | |
}; | |
}; | |
noSelectedCalendarsMessage?: string; | |
}; | |
export type SelectedCalendarsClassNames = { | |
container?: string; | |
header?: { | |
container?: string; | |
title?: string; | |
description?: string; | |
}; | |
selectedCalendarsListClassNames?: { | |
container?: string; | |
selectedCalendar: { | |
container?: string; | |
header?: { | |
container?: string; | |
title?: string; | |
description?: string; | |
}; | |
body?: { | |
container?: string; | |
description?: string; | |
}; | |
}; | |
}; | |
noSelectedCalendarsMessage?: string; | |
}; |
🤖 Prompt for AI Agents
In
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
around lines 33 to 56, change the SelectedCalendarsClassNames type so that
header.container is optional (header.container?: string) instead of required to
match adjacent optional fields; update the nested type signature accordingly and
run type-checks to ensure no call sites rely on it being required.
<SelectedCalendarsSettings classNames={classNamesObject?.container || classNames}> | ||
<SelectedCalendarsSettingsHeading | ||
classNames={classNamesObject?.header} | ||
calendarRedirectUrls={calendarRedirectUrls} | ||
isDryRun={isDryRun} | ||
/> | ||
<h1 className="px-6 py-4 text-base leading-5">No connected calendars found.</h1> | ||
<h1 | ||
className={cn( | ||
"px-6 py-4 text-base leading-5", | ||
classNamesObject?.noSelectedCalendarsMessage | ||
)}> | ||
No connected calendars found. | ||
</h1> | ||
</SelectedCalendarsSettings> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Localize “No connected calendars found.”
Replace hardcoded text with t() to meet i18n guidelines.
- <h1
- className={cn(
- "px-6 py-4 text-base leading-5",
- classNamesObject?.noSelectedCalendarsMessage
- )}>
- No connected calendars found.
- </h1>
+ <h1
+ className={cn(
+ "px-6 py-4 text-base leading-5",
+ classNamesObject?.noSelectedCalendarsMessage
+ )}>
+ {t("no_connected_calendars_found")}
+ </h1>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<SelectedCalendarsSettings classNames={classNamesObject?.container || classNames}> | |
<SelectedCalendarsSettingsHeading | |
classNames={classNamesObject?.header} | |
calendarRedirectUrls={calendarRedirectUrls} | |
isDryRun={isDryRun} | |
/> | |
<h1 className="px-6 py-4 text-base leading-5">No connected calendars found.</h1> | |
<h1 | |
className={cn( | |
"px-6 py-4 text-base leading-5", | |
classNamesObject?.noSelectedCalendarsMessage | |
)}> | |
No connected calendars found. | |
</h1> | |
</SelectedCalendarsSettings> | |
<SelectedCalendarsSettings classNames={classNamesObject?.container || classNames}> | |
<SelectedCalendarsSettingsHeading | |
classNames={classNamesObject?.header} | |
calendarRedirectUrls={calendarRedirectUrls} | |
isDryRun={isDryRun} | |
/> | |
<h1 | |
className={cn( | |
"px-6 py-4 text-base leading-5", | |
classNamesObject?.noSelectedCalendarsMessage | |
)}> | |
{t("no_connected_calendars_found")} | |
</h1> | |
</SelectedCalendarsSettings> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🔭 Outside diff range comments (1)
packages/platform/examples/base/src/pages/availability.tsx (1)
34-50
: Localize visible UI strings in examplesPer TSX guideline, wrap static text in t(). Suggested minimal changes:
- <h1 className="mx-10 my-4 text-2xl font-semibold">Availability Settings</h1> + <h1 className="mx-10 my-4 text-2xl font-semibold">{t("availability_settings")}</h1> - Validate Form + {t("validate_form")} ... - Submit Form + {t("submit_form")}If translation keys don’t exist, I can add them or reuse existing ones (e.g., availability, save).
🧹 Nitpick comments (7)
.changeset/mighty-wings-create.md (1)
1-6
: Changeset looks good; minor bump matches API surface expansion.Consider briefly enumerating the new public props (e.g., dateOverrideClassNames, scheduleClassNames.timePicker, selectedCalendarSettingsClassNames, destinationCalendarSettingsClassNames) to make the release note more scannable.
packages/platform/atoms/availability/types.ts (1)
31-37
: timePicker classNames: align naming and consider reusing a shared typeThe shape matches the mapping used in Schedule.tsx (container → control, value → singleValue, valueContainer → valueContainer, input → input, dropdown → menu). Two suggestions:
- Extract this to a reusable exported type (e.g., TimePickerClassNames) to avoid drift across packages.
- Ensure docs list these keys (container, valueContainer, value, input, dropdown). Currently, Availability docs do not include timePicker under scheduleClassNames.
docs/platform/atoms/calendar-settings.mdx (1)
53-81
: Verify property paths match wrapper/component props; add a minimal code exampleThe nested keys look thorough. Please double-check they align exactly with:
- packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
- packages/platform/atoms/destination-calendar/DestinationCalendar.tsx and its wrapper
A short code snippet demonstrating both selectedCalendarSettingsClassNames and destinationCalendarSettingsClassNames in use will help consumers avoid mistakes.
packages/ui/components/app-list-card/AppListCard.tsx (1)
25-29
: Make container optional to improve ergonomicsRequiring container when only customizing title/description is unnecessary friction. Make it optional.
-export type AppCardClassNames = { - container: string; +export type AppCardClassNames = { + container?: string; title?: string; description?: string; };packages/features/schedules/components/Schedule.tsx (2)
39-46
: SelectInnerClassNames type: good abstraction; consider centralizingThis is useful and mirrors react-select’s classNames keys. Consider exporting a shared type from @calcom/ui Select wrapper to avoid duplication and ensure consistency.
361-368
: Minor: Memoize innerClassNames to avoid re-creation on every renderNot critical, but a small optimization and keeps referential stability (useful if Select does shallow props comparisons).
- const innerClassNames: SelectInnerClassNames = { - control: timePickerClassNames?.container, - singleValue: timePickerClassNames?.value, - valueContainer: timePickerClassNames?.valueContainer, - input: timePickerClassNames?.input, - menu: timePickerClassNames?.dropdown, - }; + const innerClassNames = React.useMemo<SelectInnerClassNames>( + () => ({ + control: timePickerClassNames?.container, + singleValue: timePickerClassNames?.value, + valueContainer: timePickerClassNames?.valueContainer, + input: timePickerClassNames?.input, + menu: timePickerClassNames?.dropdown, + }), + [timePickerClassNames] + );packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
26-29
: Consider merging both className sources instead of using ORThe current implementation uses
props?.classNames || props?.classNamesObject?.container
, which means ifclassNames
is provided,classNamesObject?.container
will be ignored. Consider usingcn()
to merge both sources for more flexibility.className={cn( "border-subtle mb-6 mt-8 rounded-lg border", - props?.classNames || props?.classNamesObject?.container + props?.classNames, + props?.classNamesObject?.container )}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.changeset/mighty-wings-create.md
(1 hunks)docs/platform/atoms/availability-settings.mdx
(1 hunks)docs/platform/atoms/calendar-settings.mdx
(1 hunks)packages/features/schedules/components/Schedule.tsx
(8 hunks)packages/platform/atoms/availability/AvailabilitySettings.tsx
(6 hunks)packages/platform/atoms/availability/types.ts
(1 hunks)packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
(2 hunks)packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
(2 hunks)packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
(2 hunks)packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
(7 hunks)packages/platform/examples/base/src/pages/availability.tsx
(2 hunks)packages/platform/examples/base/src/pages/calendars.tsx
(1 hunks)packages/ui/components/app-list-card/AppListCard.tsx
(4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
Always use
t()
for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/platform/examples/base/src/pages/calendars.tsx
packages/ui/components/app-list-card/AppListCard.tsx
packages/platform/examples/base/src/pages/availability.tsx
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/availability/AvailabilitySettings.tsx
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
packages/features/schedules/components/Schedule.tsx
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/platform/examples/base/src/pages/calendars.tsx
packages/platform/atoms/availability/types.ts
packages/ui/components/app-list-card/AppListCard.tsx
packages/platform/examples/base/src/pages/availability.tsx
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/availability/AvailabilitySettings.tsx
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
packages/features/schedules/components/Schedule.tsx
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
**/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/platform/atoms/availability/types.ts
🧬 Code Graph Analysis (7)
packages/platform/examples/base/src/pages/calendars.tsx (1)
packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx (1)
CalendarSettings
(323-398)
packages/ui/components/app-list-card/AppListCard.tsx (1)
packages/ui/components/list/List.tsx (1)
ListItemText
(142-156)
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
DestinationCalendarClassNames
(14-17)
packages/platform/atoms/availability/AvailabilitySettings.tsx (1)
packages/lib/date-ranges.ts (1)
WorkingHours
(12-12)
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx (2)
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (2)
SelectedCalendarsClassNames
(33-56)SelectedCalendarsSettingsPlatformWrapper
(66-218)packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
DestinationCalendarClassNames
(14-17)
packages/features/schedules/components/Schedule.tsx (1)
packages/platform/atoms/availability/types.ts (1)
scheduleClassNames
(24-38)
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (1)
packages/ui/components/list/List.tsx (1)
List
(15-31)
🔇 Additional comments (15)
packages/platform/atoms/availability/AvailabilitySettings.tsx (3)
71-76
: New dateOverrideClassNames surface looks goodThe shape matches docs (container, title, description, button). No functional concerns.
189-203
: DateOverride now accepts classNames: consistent and non-breakingThe prop shape aligns with CustomClassNames.dateOverrideClassNames. Good separation of concerns.
686-687
: Wiring dateOverrideClassNames through: LGTMAvailabilitySettings forwards customClassNames?.dateOverrideClassNames to DateOverride. Good.
packages/platform/examples/base/src/pages/availability.tsx (1)
60-81
: Example classNames shape matches the new API
- scheduleClassNames includes the new timePicker keys.
- dateOverrideClassNames demonstrates all supported keys.
Looks consistent with types and Schedule wiring.packages/features/schedules/components/Schedule.tsx (4)
114-118
: Propagating timePicker through ScheduleDay ➜ DayRanges: LGTMThe additional classNames key is correctly passed down.
249-273
: DayRanges forwards timePicker to TimeRangeField: LGTMThe Pick type keeps the surface minimal and intentional.
353-360
: TimeRangeField typing for timePickerClassNames matches atoms/typesKeys: container, value, valueContainer, input, dropdown. Matches atoms/types and docs intent.
378-379
: innerClassNames forwarded to LazySelect: LGTMAssuming @calcom/ui/components/form Select supports these, the mapping is consistent.
If Select doesn’t yet accept innerClassNames, we should add/align this prop at the Select wrapper layer next.
Also applies to: 397-398
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
8-17
: LGTM! Well-structured type definitionsThe nested type structure for
DestinationCalendarClassNames
provides good granularity for styling customization while maintaining clear organization.packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)
4-5
: LGTM! Clean implementation of styling prop forwardingThe wrapper correctly imports the type and forwards the
classNamesObject
prop to the child component, maintaining consistency with the styling customization pattern.Also applies to: 10-16, 41-41
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (2)
33-56
: LGTM! Comprehensive type definition for styling customizationThe
SelectedCalendarsClassNames
type provides excellent granularity for styling different parts of the component hierarchy while maintaining clear organization.
125-136
: Well-implemented nested className object for AppListCardThe
classNameObject
prop properly maps the nested styling structure fromselectedCalendarsListClassNames.selectedCalendar
to the AppListCard component, maintaining consistency with the type definition.packages/platform/examples/base/src/pages/calendars.tsx (1)
13-48
: Good demonstration of the new styling capabilitiesThis example effectively demonstrates the granular styling control provided by the new
classNames
prop structure. The contrasting colors make it easy to identify which styles apply to which components during development.packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx (2)
11-17
: LGTM! Consistent implementation of nested styling propsThe component properly extends the classNames prop with new nested properties and correctly forwards them to child components, maintaining consistency with the overall styling customization pattern.
Also applies to: 34-34, 42-42
1-2
: Fix incorrect import pathThe import path is missing the relative path prefix. Based on the file structure, it should be importing from the destination-calendar directory at the same level.
-import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar"; +import type { DestinationCalendarClassNames } from "../../destination-calendar/DestinationCalendar";Likely an incorrect or invalid review comment.
| dateOverrideClassNames | An object for granular styling of date override components (see detailed table below) | | ||
|
||
### dateOverrideClassNames Object Structure | ||
|
||
The `dateOverrideClassNames` prop accepts an object with the following structure for granular styling of date override components: | ||
|
||
| Property Path | Description | | ||
|:--------------|:------------| | ||
| `container` | Styles the main container | | ||
| `title` | Styles the title| | ||
| `description` | Styles the description | | ||
| `button` | Styles the button to add date override | | ||
|
||
<Info>Please ensure all custom classnames are valid [Tailwind CSS](https://tailwindcss.com/) classnames.</Info> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Docs: Add scheduleClassNames.timePicker section for completeness
The code now supports scheduleClassNames.timePicker with keys: container, valueContainer, value, input, dropdown. Please add a short table mirroring these keys alongside existing scheduleClassNames docs to prevent mismatch between API and docs. I can draft it if helpful.
🤖 Prompt for AI Agents
In docs/platform/atoms/availability-settings.mdx around lines 134 to 147, the
documentation is missing a scheduleClassNames.timePicker section that the code
now supports; add a short table immediately alongside the existing
scheduleClassNames docs that lists the timePicker keys and descriptions:
container (wraps the whole time picker), valueContainer (wraps the displayed
value), value (styles the displayed time text), input (styles the time input
field), dropdown (styles the time selection dropdown). Mirror the formatting and
tone of the surrounding tables and include the same Tailwind-valid classname
note at the end.
const handleFormSubmit = useCallback( | ||
(customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => { | ||
if (customCallbacks) { | ||
callbacksRef.current = customCallbacks; | ||
} | ||
|
||
if (saveButtonRef.current) { | ||
saveButtonRef.current.click(); | ||
} else { | ||
form.handleSubmit(async (data) => { | ||
try { | ||
await handleSubmit(data); | ||
callbacksRef.current?.onSuccess?.(); | ||
} catch (error) { | ||
callbacksRef.current?.onError?.(error as Error); | ||
} | ||
})(); | ||
} | ||
}, [form, handleSubmit]); | ||
if (saveButtonRef.current) { | ||
saveButtonRef.current.click(); | ||
} else { | ||
form.handleSubmit(async (data) => { | ||
try { | ||
await handleSubmit(data); | ||
callbacksRef.current?.onSuccess?.(); | ||
} catch (error) { | ||
callbacksRef.current?.onError?.(error as Error); | ||
} | ||
})(); | ||
} | ||
}, | ||
[form, handleSubmit] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: handleFormSubmit callbacks are not invoked when Save button exists
When saveButtonRef.current exists, you programmatically click the Save button. The actual form’s handleSubmit handler does not call callbacksRef.current.onSuccess/onError, so custom callbacks passed to handleFormSubmit are silently ignored in the common path.
Fix by invoking callbacks in the Form’s handleSubmit handler; also consider renaming the inner parameter from props to formData to avoid shadowing.
- const handleFormSubmit = useCallback(
- (customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => {
+ const handleFormSubmit = useCallback(
+ (customCallbacks?: { onSuccess?: () => void; onError?: (error: Error) => void }) => {
if (customCallbacks) {
callbacksRef.current = customCallbacks;
}
if (saveButtonRef.current) {
saveButtonRef.current.click();
} else {
form.handleSubmit(async (data) => {
try {
await handleSubmit(data);
callbacksRef.current?.onSuccess?.();
} catch (error) {
callbacksRef.current?.onError?.(error as Error);
}
})();
}
},
[form, handleSubmit]
);
Apply callbacks in the Form’s submit handler too:
- <Form
+ <Form
form={form}
id="availability-form"
- handleSubmit={async (props) => {
- handleSubmit(props);
- }}
+ handleSubmit={async (formData) => {
+ try {
+ await handleSubmit(formData);
+ callbacksRef.current?.onSuccess?.();
+ } catch (error) {
+ callbacksRef.current?.onError?.(error as Error);
+ }
+ }}
className={cn(customClassNames?.formClassName, "flex flex-col sm:mx-0 xl:flex-row xl:space-x-6")}>
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/platform/atoms/availability/AvailabilitySettings.tsx around lines
340 to 360, the handleFormSubmit path that clicks saveButtonRef.current
currently bypasses invoking callbacksRef.current.onSuccess/onError so custom
callbacks are ignored; modify the form's actual submit handler (the function
passed to form.handleSubmit) to call callbacksRef.current?.onSuccess() on
success and callbacksRef.current?.onError(error) on failure, and ensure
handleFormSubmit still sets callbacksRef.current before triggering the click;
also rename the inner submit parameter (currently props) to formData to avoid
shadowing and improve clarity.
<h1 | ||
className={cn( | ||
"px-6 py-4 text-base leading-5", | ||
classNamesObject?.noSelectedCalendarsMessage | ||
)}> | ||
No connected calendars found. | ||
</h1> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use t() for text localization
The text "No connected calendars found." should be localized using the t()
function as per the coding guidelines for TSX files.
className={cn(
"px-6 py-4 text-base leading-5",
classNamesObject?.noSelectedCalendarsMessage
)}>
- No connected calendars found.
+ {t("no_connected_calendars_found")}
</h1>
🤖 Prompt for AI Agents
In
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
around lines 92 to 98, replace the hardcoded header string "No connected
calendars found." with a localized call using t(), e.g.
t('selectedCalendars.noConnectedCalendars') (or t('No connected calendars
found.') if you prefer literal keys), and ensure the component imports/uses the
i18n hook (const { t } = useTranslation() or equivalent) so t is available.
<div | ||
className={classNames( | ||
highlight && "dark:bg-muted bg-yellow-100", | ||
className || classNameObject?.container | ||
)}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Merge className and classNameObject.container instead of fallback
Current logic ignores classNameObject.container when className is set. Merge both for predictable overrides.
- <div
- className={classNames(
- highlight && "dark:bg-muted bg-yellow-100",
- className || classNameObject?.container
- )}>
+ <div
+ className={classNames(
+ highlight && "dark:bg-muted bg-yellow-100",
+ classNameObject?.container,
+ className
+ )}>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<div | |
className={classNames( | |
highlight && "dark:bg-muted bg-yellow-100", | |
className || classNameObject?.container | |
)}> | |
<div | |
className={classNames( | |
highlight && "dark:bg-muted bg-yellow-100", | |
classNameObject?.container, | |
className | |
)}> |
🤖 Prompt for AI Agents
In packages/ui/components/app-list-card/AppListCard.tsx around lines 63 to 67,
the current JSX uses className || classNameObject?.container which ignores
classNameObject.container when className is present; change it to merge both
values instead of fallback. Update the className prop to pass both into
classNames (e.g. classNames(highlight && "dark:bg-muted bg-yellow-100",
classNameObject?.container, className)) so both classNameObject.container and
className are combined and className appears last to allow intentional
overrides.
{isDefault && <Badge variant="green">{t("default")}</Badge>} | ||
{isTemplate && <Badge variant="red">Template</Badge>} | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Localize "Template" label
Per TSX localization guideline, avoid hardcoded strings. Use t().
- {isTemplate && <Badge variant="red">Template</Badge>}
+ {isTemplate && <Badge variant="red">{t("template")}</Badge>}
🤖 Prompt for AI Agents
In packages/ui/components/app-list-card/AppListCard.tsx around lines 83 to 85,
the "Template" badge text is hardcoded; replace the literal string with the i18n
call (e.g. {t("template")}) consistent with the existing {t("default")} usage,
and add the corresponding "template" key to the translations files if it doesn't
exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (4)
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
25-31
: Merge container classNames instead of picking oneCurrent logic prefers props.classNames over props.classNamesObject.container. Consider merging both to allow coarse and granular styles simultaneously.
- className={cn( - "border-subtle mb-6 mt-8 rounded-lg border", - props?.classNames || props?.classNamesObject?.container - )}> + className={cn( + "border-subtle mb-6 mt-8 rounded-lg border", + props?.classNames, + props?.classNamesObject?.container + )}>docs/platform/atoms/calendar-settings.mdx (1)
72-81
: Document header.container for destination calendarCode supports header.container in DestinationCalendarSettingsHeading, but docs list only header.title and header.description. Add header.container for completeness.
### destinationCalendarSettingsClassNames Object Structure The `destinationCalendarSettingsClassNames` prop accepts an object with the following nested structure for granular styling of the destination calendar component: | Property Path | Description | |:--------------|:------------| | `container` | Styles the main container of the destination calendar section | +| `header.container` | Styles the header container | | `header.title` | Styles the header title text | | `header.description` | Styles the header description text |
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (2)
86-86
: Merge container overrides instead of replacingUnify semantics with cn() so defaults and overrides compose.
-<SelectedCalendarsSettings classNames={classNamesObject?.container || classNames}> +<SelectedCalendarsSettings classNames={cn(classNames, classNamesObject?.container)}>Apply at both occurrences.
Also applies to: 104-104
110-113
: Preserve default spacing when overriding list containerUsing OR drops the default padding when an override is provided. Compose with cn() instead.
- <List - noBorderTreatment - className={classNamesObject?.selectedCalendarsListClassNames?.container || "p-6 pt-2"}> + <List + noBorderTreatment + className={cn( + "p-6 pt-2", + classNamesObject?.selectedCalendarsListClassNames?.container + )}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.changeset/mighty-wings-create.md
(1 hunks)docs/platform/atoms/availability-settings.mdx
(1 hunks)docs/platform/atoms/calendar-settings.mdx
(1 hunks)packages/features/schedules/components/Schedule.tsx
(8 hunks)packages/platform/atoms/availability/AvailabilitySettings.tsx
(6 hunks)packages/platform/atoms/availability/types.ts
(1 hunks)packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
(2 hunks)packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
(2 hunks)packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
(2 hunks)packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
(7 hunks)packages/platform/examples/base/src/pages/availability.tsx
(2 hunks)packages/platform/examples/base/src/pages/calendars.tsx
(1 hunks)packages/ui/components/app-list-card/AppListCard.tsx
(4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
**/*.ts
: For Prisma queries, only select data you need; never useinclude
, always useselect
Ensure thecredential.key
field is never returned from tRPC endpoints or APIs
Files:
packages/platform/atoms/availability/types.ts
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()
in hot paths like loops
Files:
packages/platform/atoms/availability/types.ts
packages/ui/components/app-list-card/AppListCard.tsx
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
packages/platform/examples/base/src/pages/availability.tsx
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
packages/platform/examples/base/src/pages/calendars.tsx
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/availability/AvailabilitySettings.tsx
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
packages/features/schedules/components/Schedule.tsx
**/*.tsx
📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)
Always use
t()
for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/ui/components/app-list-card/AppListCard.tsx
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx
packages/platform/examples/base/src/pages/availability.tsx
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
packages/platform/examples/base/src/pages/calendars.tsx
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
packages/platform/atoms/availability/AvailabilitySettings.tsx
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
packages/features/schedules/components/Schedule.tsx
🧬 Code Graph Analysis (8)
packages/ui/components/app-list-card/AppListCard.tsx (1)
packages/ui/components/list/List.tsx (1)
ListItemText
(142-156)
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
packages/platform/atoms/destination-calendar/DestinationCalendarSelector.tsx (1)
DestinationCalendarProps
(15-24)
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx (2)
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (2)
SelectedCalendarsClassNames
(33-56)SelectedCalendarsSettingsPlatformWrapper
(66-218)packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
DestinationCalendarClassNames
(14-17)
packages/platform/examples/base/src/pages/calendars.tsx (1)
packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx (1)
CalendarSettings
(323-398)
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (1)
DestinationCalendarClassNames
(14-17)
packages/platform/atoms/availability/AvailabilitySettings.tsx (1)
packages/lib/date-ranges.ts (1)
WorkingHours
(12-12)
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (1)
packages/ui/components/list/List.tsx (1)
List
(15-31)
packages/features/schedules/components/Schedule.tsx (1)
packages/platform/atoms/availability/types.ts (1)
scheduleClassNames
(24-38)
🔇 Additional comments (19)
.changeset/mighty-wings-create.md (1)
1-5
: LGTM!The changeset correctly documents the minor version bump for the new styling features.
packages/platform/atoms/availability/types.ts (1)
31-37
: Well-structured type addition for time picker stylingThe new
timePicker
property follows the established pattern for nested classNames and provides appropriate granularity for styling the time picker components.packages/platform/atoms/availability/AvailabilitySettings.tsx (2)
71-76
: Consistent styling API extensionThe
dateOverrideClassNames
addition follows the established pattern and provides appropriate granularity for styling date override components.
189-262
: Well-implemented classNames propagationThe DateOverride component correctly applies the custom classNames to each UI element while maintaining default styles as fallbacks.
packages/platform/examples/base/src/pages/availability.tsx (1)
60-80
: Example effectively demonstrates the new styling capabilitiesThe example clearly shows how to use the new
scheduleClassNames
anddateOverrideClassNames
props with distinct styling to demonstrate each customizable element.Note: As mentioned in the PR comments, documentation for these new style props is still pending.
docs/platform/atoms/availability-settings.mdx (1)
134-145
: Documentation properly updated for new styling propsThe documentation clearly describes the new
dateOverrideClassNames
prop structure. This partially addresses the "TODO: document new styles props" mentioned in the PR objectives.packages/features/schedules/components/Schedule.tsx (2)
39-45
: Type definition aligns with react-select's classNames structureThe
SelectInnerClassNames
type properly matches the expected structure for customizing react-select components.
456-470
: innerClassNames prop is properly supported by SelectThe Select component in
packages/ui/components/form/select/Select.tsx
declares aninnerClassNames
prop, destructures it fromprops
, and merges its values into each part’s style function. It’s excluded fromrestProps
, so it won’t cause unknown-prop warnings and will correctly apply custom styling. No changes required.packages/platform/examples/base/src/pages/calendars.tsx (1)
13-49
: Example usage of nested classNames looks goodStructure matches the new SelectedCalendarsClassNames and DestinationCalendarClassNames. Good coverage of container/header/body overrides.
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (2)
10-16
: New classNamesObject prop is correctly typed and optionalProp typing and defaults look good.
41-41
: Propagating classNamesObject to child is correctForwarding preserves the new styling API. Good.
packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (2)
8-18
: Type additions look solidDestinationHeaderClassnames and DestinationCalendarClassNames are well-scoped and future-proof.
43-56
: Heading i18n and className hooks are applied correctlyt() is used for all user-facing strings; header class hooks are cleanly threaded.
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx (3)
15-17
: New nested classNames props on wrapper look correctPublic API augmentation aligns with downstream wrappers.
34-35
: Destination classNamesObject forwarded correctlyWiring is accurate.
42-43
: Selected calendars classNamesObject forwarded correctlyWiring is accurate.
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (3)
125-136
: AppListCard classNameObject usage looks correctContainer/title/description overrides are correctly threaded via classNameObject.
150-163
: Good: i18n applied to conflict toggle copyt("toggle_calendars_conflict") is used appropriately and classes are composable.
236-245
: Heading i18n + composable class names are correctHeader container/title/description all use cn() with t() for text.
@@ -1,12 +1,19 @@ | |||
import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import path likely incorrect; use relative path
Other imports use relative paths. This absolute-ish alias may not resolve.
-import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar";
+import type { DestinationCalendarClassNames } from "../../destination-calendar/DestinationCalendar";
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar"; | |
import type { DestinationCalendarClassNames } from "../../destination-calendar/DestinationCalendar"; |
🤖 Prompt for AI Agents
In
packages/platform/atoms/calendar-settings/wrappers/CalendarSettingsPlatformWrapper.tsx
around line 1, the import uses "destination-calendar/DestinationCalendar" which
is inconsistent with other relative imports and may not resolve; change the
import to the correct relative path (e.g.,
./../../destination-calendar/DestinationCalendar or the actual relative path
from this file to the DestinationCalendar module) and update the import
statement to use that relative path so it matches the project structure and
resolves correctly.
import { useUpdateDestinationCalendars } from "../../hooks/calendars/useUpdateDestinationCalendars"; | ||
import { useConnectedCalendars } from "../../hooks/useConnectedCalendars"; | ||
import { AtomsWrapper } from "../../src/components/atoms-wrapper"; | ||
import type { DestinationCalendarClassNames } from "../DestinationCalendar"; | ||
import { DestinationCalendarSettings } from "../DestinationCalendar"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add i18n for fallback "Loading..." (and ensure hook import if used)
There’s a literal "Loading..." string in this component. Per guideline, wrap user-facing text with t().
Proposed minimal change:
+import { useLocale } from "@calcom/lib/hooks/useLocale";
Inside the component, initialize t():
export const DestinationCalendarSettingsPlatformWrapper = ({
statusLoader,
classNames = "mx-5",
classNamesObject,
isDryRun = false,
}: {
@@
}) => {
+ const { t } = useLocale();
const calendars = useConnectedCalendars({});
Use it in the fallback:
- {!statusLoader && <h1 className="m-5 text-xl font-semibold">Loading...</h1>}
+ {!statusLoader && <h1 className="m-5 text-xl font-semibold">{t("loading")}</h1>}
🤖 Prompt for AI Agents
In
packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx
around lines 1 to 6 there is a literal "Loading..." string used as fallback;
import the i18n hook (useTranslation) at the top of the file, call const { t } =
useTranslation() inside the component body, and replace the plain "Loading..."
with t('Loading...') (or a suitable translation key) so the fallback text is
internationalized; ensure the import is added only if the hook is used.
export type SelectedCalendarsClassNames = { | ||
container?: string; | ||
header?: { | ||
container?: string; | ||
title?: string; | ||
description?: string; | ||
}; | ||
selectedCalendarsListClassNames?: { | ||
container?: string; | ||
selectedCalendar: { | ||
container?: string; | ||
header?: { | ||
container: string; | ||
title?: string; | ||
description?: string; | ||
}; | ||
body?: { | ||
container?: string; | ||
description?: string; | ||
}; | ||
}; | ||
}; | ||
noSelectedCalendarsMessage?: string; | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make nested container fields optional for flexibility
If header is provided only to override title/description, requiring header.container is constraining. Suggest making it optional.
export type SelectedCalendarsClassNames = {
container?: string;
header?: {
- container?: string;
+ container?: string;
title?: string;
description?: string;
};
selectedCalendarsListClassNames?: {
container?: string;
selectedCalendar: {
container?: string;
header?: {
- container: string;
+ container?: string;
title?: string;
description?: string;
};
body?: {
container?: string;
description?: string;
};
};
};
noSelectedCalendarsMessage?: string;
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export type SelectedCalendarsClassNames = { | |
container?: string; | |
header?: { | |
container?: string; | |
title?: string; | |
description?: string; | |
}; | |
selectedCalendarsListClassNames?: { | |
container?: string; | |
selectedCalendar: { | |
container?: string; | |
header?: { | |
container: string; | |
title?: string; | |
description?: string; | |
}; | |
body?: { | |
container?: string; | |
description?: string; | |
}; | |
}; | |
}; | |
noSelectedCalendarsMessage?: string; | |
}; | |
export type SelectedCalendarsClassNames = { | |
container?: string; | |
header?: { | |
container?: string; | |
title?: string; | |
description?: string; | |
}; | |
selectedCalendarsListClassNames?: { | |
container?: string; | |
selectedCalendar: { | |
container?: string; | |
header?: { | |
container?: string; | |
title?: string; | |
description?: string; | |
}; | |
body?: { | |
container?: string; | |
description?: string; | |
}; | |
}; | |
}; | |
noSelectedCalendarsMessage?: string; | |
}; |
🤖 Prompt for AI Agents
In
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
around lines 33 to 57, the nested header.container inside
selectedCalendarsListClassNames.selectedCalendar.header is currently required
("container: string;") which is too strict; change that specific field to
optional ("container?: string;") so callers can provide header just to override
title/description without supplying a container value.
<h1 | ||
className={cn( | ||
"px-6 py-4 text-base leading-5", | ||
classNamesObject?.noSelectedCalendarsMessage | ||
)}> | ||
No connected calendars found. | ||
</h1> | ||
</SelectedCalendarsSettings> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Localize user-facing empty-state string
Wrap with t() per i18n guideline for TSX.
- <h1
+ <h1
className={cn(
"px-6 py-4 text-base leading-5",
classNamesObject?.noSelectedCalendarsMessage
- )}>
- No connected calendars found.
- </h1>
+ )}>
+ {t("no_connected_calendars_found")}
+ </h1>
Ensure the translation key exists; if not, add it to locales.
🏁 Script executed:
#!/bin/bash
# Search for the translation key in the codebase to verify existence
rg -n '"no_connected_calendars_found"' .
Length of output: 42
Localize empty-state string and add missing translation key
Wrap the literal in t()
and add the corresponding entry to your locale files.
• File: packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
– Replace the hard-coded string with t("no_connected_calendars_found")
– Ensure t
is imported (e.g. import { t } from "i18n"
or your project’s i18n utility)
• Locale files (e.g. locales/en.json)
– Add:
{
"no_connected_calendars_found": "No connected calendars found."
}
Proposed diff:
<h1
className={cn(
"px-6 py-4 text-base leading-5",
classNamesObject?.noSelectedCalendarsMessage
)}>
- No connected calendars found.
+ {t("no_connected_calendars_found")}
</h1>
🤖 Prompt for AI Agents
In
packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx
around lines 92 to 99, the empty-state header contains a hard-coded string;
replace it with a localized key by calling t("no_connected_calendars_found"),
add the necessary import for t from your i18n utility (e.g. import { t } from
"i18n" or project equivalent), and then add the key
"no_connected_calendars_found": "No connected calendars found." to your locale
files (e.g. locales/en.json) so the translated string is available.
<div | ||
className={classNames( | ||
highlight && "dark:bg-muted bg-yellow-100", | ||
className || classNameObject?.container | ||
)}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge both className sources instead of using OR logic
The current implementation ignores classNameObject?.container
when className
is provided. Both should be merged to allow users to use either or both styling approaches.
Apply this fix:
- <div
- className={classNames(
- highlight && "dark:bg-muted bg-yellow-100",
- className || classNameObject?.container
- )}>
+ <div
+ className={classNames(
+ highlight && "dark:bg-muted bg-yellow-100",
+ className,
+ classNameObject?.container
+ )}>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<div | |
className={classNames( | |
highlight && "dark:bg-muted bg-yellow-100", | |
className || classNameObject?.container | |
)}> | |
<div | |
className={classNames( | |
highlight && "dark:bg-muted bg-yellow-100", | |
className, | |
classNameObject?.container | |
)}> |
🤖 Prompt for AI Agents
In packages/ui/components/app-list-card/AppListCard.tsx around lines 63 to 67,
the className expression uses `className || classNameObject?.container` which
drops container classes when `className` exists; update it to merge both sources
instead of OR-ing them by passing both `className` and
`classNameObject?.container` into the classNames call (so both strings are
combined and falsy values are ignored).
No description provided.