Skip to content

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

feat: more atoms styles #22976

wants to merge 10 commits into from

Conversation

supalarry
Copy link
Contributor

No description provided.

Copy link
Contributor

coderabbitai bot commented Aug 8, 2025

Walkthrough

This 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 Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-new-atoms-styles

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@supalarry
Copy link
Contributor Author

TODO: document new styles props

@keithwillcode keithwillcode added core area: core, team members only platform Anything related to our platform plan labels Aug 8, 2025
Copy link

vercel bot commented Aug 11, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal ⬜️ Ignored (Inspect) Aug 11, 2025 0:47am
cal-eu ⬜️ Ignored (Inspect) Aug 11, 2025 0:47am

@supalarry supalarry marked this pull request as ready for review August 11, 2025 13:45
@supalarry supalarry requested review from a team as code owners August 11, 2025 13:45
@dosubot dosubot bot added the ✨ feature New feature or request label Aug 11, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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…” text

Per 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” fallback

Use 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 messages

Replace 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 completeness

The 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 overrides

Requiring 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 classNamesObject

Other 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 correct

Keys 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 DestinationCalendarSelector

Using {...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 good

Outer 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 destinationCalendarSettingsClassNames

Examples 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 iframe

Use 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 prop

allowDelete 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

📥 Commits

Reviewing files that changed from the base of the PR and between eb05d54 and e9987a4.

📒 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 use include, always use select
Ensure the credential.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 correctly

Minor bump for new styling hooks is appropriate. No issues.

packages/platform/atoms/availability/types.ts (1)

31-37: API extension LGTM

Adding 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 correct

highlight state composes with user-provided classes, and className takes precedence over classNameObject.container. Nice.


78-81: Per-part overrides wired correctly

Title 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 LGTM

dateOverrideClassNames type is concise and matches the docs table (container, title, description, button).


197-203: DateOverride styling pipeline is correct

Prop 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 correct

scheduleClassNames 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 appropriate

Keys match internal react-select parts used by our Select wrapper. No concerns.


116-117: Prop propagation to DayRanges looks good

Including 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 the SelectProps interface includes innerClassNames (used throughout the component) and that LazySelect 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 LGTM

DestinationHeaderClassnames and DestinationCalendarClassNames provide good granularity and keep container optional.

packages/platform/atoms/destination-calendar/wrappers/DestinationCalendarSettingsPlatformWrapper.tsx (1)

10-16: Propagate DestinationCalendarClassNames via classNamesObject: LGTM

Prop 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: LGTM

Extending CalendarSettingsPlatformWrapperProps.classNames with granular objects is clear and backward-compatible with existing ...CustomClassnames.


34-35: Forwarding classNamesObject to child wrappers: LGTM

Props 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: LGTM

The 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: LGTM

The example reflects the new public API and nested structure well.

packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (5)

7-7: cn import: LGTM

Utility import is appropriate for merging defaults and overrides.


104-113: List container override: LGTM

Clean fallback to "p-6 pt-2" and supports overrides via classNamesObject.


125-136: AppListCard classNameObject mapping: LGTM

Simple and flexible mapping for container/title/description. Good use of cn for merging.


150-163: Body container/description className merge: LGTM

Merges defaults with overrides properly. i18n for label is already handled with t("toggle_calendars_conflict").


220-231: Header component classNames API: LGTM

Prop surface for container/title/description is clear and integrates well with cn().

Also applies to: 236-245

Comment on lines +340 to 361
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]
);

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

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";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +33 to +56
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;
};
Copy link
Contributor

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.

Suggested change
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.

Comment on lines +86 to 99
<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>
Copy link
Contributor

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.

Suggested change
<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>

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 examples

Per 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 type

The 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 example

The 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 ergonomics

Requiring 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 centralizing

This 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 render

Not 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 OR

The current implementation uses props?.classNames || props?.classNamesObject?.container, which means if classNames is provided, classNamesObject?.container will be ignored. Consider using cn() 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

📥 Commits

Reviewing files that changed from the base of the PR and between eb05d54 and e9987a4.

📒 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 use include, always use select
Ensure the credential.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 good

The shape matches docs (container, title, description, button). No functional concerns.


189-203: DateOverride now accepts classNames: consistent and non-breaking

The prop shape aligns with CustomClassNames.dateOverrideClassNames. Good separation of concerns.


686-687: Wiring dateOverrideClassNames through: LGTM

AvailabilitySettings 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: LGTM

The additional classNames key is correctly passed down.


249-273: DayRanges forwards timePicker to TimeRangeField: LGTM

The Pick type keeps the surface minimal and intentional.


353-360: TimeRangeField typing for timePickerClassNames matches atoms/types

Keys: container, value, valueContainer, input, dropdown. Matches atoms/types and docs intent.


378-379: innerClassNames forwarded to LazySelect: LGTM

Assuming @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 definitions

The 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 forwarding

The 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 customization

The 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 AppListCard

The classNameObject prop properly maps the nested styling structure from selectedCalendarsListClassNames.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 capabilities

This 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 props

The 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 path

The 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.

Comment on lines +134 to 147
| 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>
Copy link
Contributor

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.

Comment on lines +340 to +360
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]
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Comment on lines +92 to +98
<h1
className={cn(
"px-6 py-4 text-base leading-5",
classNamesObject?.noSelectedCalendarsMessage
)}>
No connected calendars found.
</h1>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Comment on lines +63 to +67
<div
className={classNames(
highlight && "dark:bg-muted bg-yellow-100",
className || classNameObject?.container
)}>
Copy link
Contributor

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.

Suggested change
<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.

Comment on lines 83 to 85
{isDefault && <Badge variant="green">{t("default")}</Badge>}
{isTemplate && <Badge variant="red">Template</Badge>}
</div>
Copy link
Contributor

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 one

Current 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 calendar

Code 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 replacing

Unify 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 container

Using 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

📥 Commits

Reviewing files that changed from the base of the PR and between eb05d54 and e9987a4.

📒 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 use include, always use select
Ensure the credential.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 styling

The 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 extension

The dateOverrideClassNames addition follows the established pattern and provides appropriate granularity for styling date override components.


189-262: Well-implemented classNames propagation

The 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 capabilities

The example clearly shows how to use the new scheduleClassNames and dateOverrideClassNames 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 props

The 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 structure

The SelectInnerClassNames type properly matches the expected structure for customizing react-select components.


456-470: innerClassNames prop is properly supported by Select

The Select component in packages/ui/components/form/select/Select.tsx declares an innerClassNames prop, destructures it from props, and merges its values into each part’s style function. It’s excluded from restProps, 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 good

Structure 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 optional

Prop typing and defaults look good.


41-41: Propagating classNamesObject to child is correct

Forwarding preserves the new styling API. Good.

packages/platform/atoms/destination-calendar/DestinationCalendar.tsx (2)

8-18: Type additions look solid

DestinationHeaderClassnames and DestinationCalendarClassNames are well-scoped and future-proof.


43-56: Heading i18n and className hooks are applied correctly

t() 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 correct

Public API augmentation aligns with downstream wrappers.


34-35: Destination classNamesObject forwarded correctly

Wiring is accurate.


42-43: Selected calendars classNamesObject forwarded correctly

Wiring is accurate.

packages/platform/atoms/selected-calendars/wrappers/SelectedCalendarsSettingsPlatformWrapper.tsx (3)

125-136: AppListCard classNameObject usage looks correct

Container/title/description overrides are correctly threaded via classNameObject.


150-163: Good: i18n applied to conflict toggle copy

t("toggle_calendars_conflict") is used appropriately and classes are composable.


236-245: Heading i18n + composable class names are correct

Header container/title/description all use cn() with t() for text.

@@ -1,12 +1,19 @@
import type { DestinationCalendarClassNames } from "destination-calendar/DestinationCalendar";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines 1 to 6
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";

Copy link
Contributor

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.

Comment on lines +33 to +57
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;
};

Copy link
Contributor

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.

Suggested change
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.

Comment on lines +92 to 99
<h1
className={cn(
"px-6 py-4 text-base leading-5",
classNamesObject?.noSelectedCalendarsMessage
)}>
No connected calendars found.
</h1>
</SelectedCalendarsSettings>
Copy link
Contributor

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.

Comment on lines +63 to +67
<div
className={classNames(
highlight && "dark:bg-muted bg-yellow-100",
className || classNameObject?.container
)}>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Suggested change
<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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core area: core, team members only ✨ feature New feature or request platform Anything related to our platform plan
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants