Skip to content

[WEB-4841] chore: calendar component migration UI to propel#7730

Merged
sriramveeraghanta merged 7 commits intopreviewfrom
chore-calendar-migration-ui-to-propel
Sep 9, 2025
Merged

[WEB-4841] chore: calendar component migration UI to propel#7730
sriramveeraghanta merged 7 commits intopreviewfrom
chore-calendar-migration-ui-to-propel

Conversation

@anmolsinghbhatia
Copy link
Collaborator

@anmolsinghbhatia anmolsinghbhatia commented Sep 5, 2025

Description

This PR includes the following changes:

  • Migrated the Calendar component from @plane/ui to @plane/propel
  • Removed the react-day-picker dependency from the web app
  • Updated related imports and code refactoring
  • Stories added for calendar component

Type of Change

  • Improvement
  • Code refactoring

Media

Media
media

Summary by CodeRabbit

  • New Features
    • Added Calendar component stories to Storybook for browsing and examples.
  • Refactor
    • Calendar/date-picker moved into the design system; app imports updated to use the design system.
    • Calendar styling centralized and exposed from the design system.
  • Chores
    • Removed direct date-picker dependency from the web app; design system now manages it.
  • Notes
    • No user-facing behavior changes expected for date pickers.

@makeplane
Copy link

makeplane bot commented Sep 5, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Calendar UI and DayPicker styles were moved from the UI package into a new Propel calendar module. Web app imports were switched to @plane/propel/calendar and global DayPicker styles now import from @plane/propel/styles/react-day-picker. react-day-picker dependency moved into packages/propel. UI package calendar file and its re-export were removed.

Changes

Cohort / File(s) Summary of changes
Web: Calendar import migration
apps/web/core/components/core/filters/date-filter-modal.tsx, apps/web/core/components/dropdowns/date-range.tsx, apps/web/core/components/dropdowns/date.tsx, apps/web/core/components/inbox/modals/snooze-issue-modal.tsx
Switched Calendar (and related types) imports to @plane/propel/calendar; split combined imports (e.g., Button, ComboDropDown) into separate statements; no runtime logic changes.
Web: Global DayPicker styles import
apps/web/app/(all)/layout.tsx
Replaced local CSS import with @plane/propel/styles/react-day-picker.
Web: Dependency cleanup
apps/web/package.json
Removed react-day-picker dependency from the web app.
Propel: New Calendar module and exports
packages/propel/src/calendar/root.tsx, packages/propel/src/calendar/index.ts, packages/propel/package.json, packages/propel/tsdown.config.ts
Added a Calendar wrapper component (root) that re-exports DayPicker props/types, added Matcher and DateRange type re-exports, added ./calendar and ./styles/react-day-picker exports and react-day-picker dependency, and added calendar entry to tsdown build config.
Propel: Storybook and styles
packages/propel/.storybook/preview.ts, packages/propel/src/calendar/calendar.stories.tsx
Imported DayPicker CSS into Storybook preview and added a Calendar story file (exports meta and Default story using internal date state).
UI: Remove Calendar from UI package
packages/ui/src/calendar.tsx, packages/ui/src/index.ts
Deleted the UI package Calendar implementation and removed its re-export from the UI index.

Sequence Diagram(s)

sequenceDiagram
  participant Web as apps/web components
  participant Propel as @plane/propel/calendar
  participant RDP as react-day-picker

  Note over Web,Propel: New import routing
  Web->>Propel: import { Calendar, Matcher, DateRange } from "@plane/propel/calendar"
  Propel->>RDP: render DayPicker with forwarded props
  Propel->>Propel: apply startMonth/endMonth, chevrons, classNames defaults
  Propel-->>Web: rendered calendar UI (DayPicker output)

  Note over UI,Web: Old flow removed
  UI--xWeb: previously exported Calendar (deleted)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🛠️refactor, 🌟improvement

Suggested reviewers

  • sriramveeraghanta
  • vamsikrishnamathala

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description omits the required “Test Scenarios” and “References” sections from the repository template and uses a non-standard heading “Media” instead of “Screenshots and Media (if applicable).” Please add the “Test Scenarios” section detailing how changes were verified and the “References” section linking related issues, and rename “Media” to “Screenshots and Media (if applicable)” to match the template.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the primary change—migrating the calendar component from the UI package to Propel—using conventional PR prefixes and avoids irrelevant details or generic phrasing.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I hopped from UI fields to Propel’s glen,
Calendars bloomed where new exports begin.
Dates now skip in tidy rows,
Styles bundled where the story grows.
A little rabbit cheers the change—🐇📅

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore-calendar-migration-ui-to-propel

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR migrates the Calendar component from @plane/ui to @plane/propel package, consolidating dependencies and improving component organization.

  • Moved Calendar component from @plane/ui to @plane/propel with react-day-picker dependency
  • Updated all import statements across the web app to use the new calendar location
  • Added comprehensive Storybook stories for the calendar component

Reviewed Changes

Copilot reviewed 14 out of 16 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/ui/src/index.ts Removed calendar export from UI package
packages/ui/src/calendar.tsx Deleted old calendar component implementation
packages/propel/tsdown.config.ts Added calendar to build configuration
packages/propel/src/calendar/root.tsx New calendar component implementation in propel
packages/propel/src/calendar/index.ts Calendar component exports and type re-exports
packages/propel/src/calendar/calendar.stories.tsx Comprehensive Storybook stories for calendar
packages/propel/package.json Added calendar export and react-day-picker dependency
packages/propel/.storybook/preview.ts Added calendar styles to Storybook
apps/web/package.json Removed react-day-picker dependency from web app
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx Updated calendar import
apps/web/core/components/dropdowns/date.tsx Updated calendar and types import
apps/web/core/components/dropdowns/date-range.tsx Updated calendar and types import
apps/web/core/components/core/filters/date-filter-modal.tsx Updated calendar import
apps/web/app/(all)/layout.tsx Updated calendar styles import
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/core/components/core/filters/date-filter-modal.tsx (1)

47-50: Bug: date2 watches date1, breaking range validation

date2 is incorrectly derived from watch("date1"), so isInvalid can’t detect inverted ranges.

Apply this diff:

-  const date1 = getDate(watch("date1"));
-  const date2 = getDate(watch("date1"));
+  const date1 = getDate(watch("date1"));
+  const date2 = getDate(watch("date2"));
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (1)

67-73: Fix undefined close() call in onClick.

close() is not defined in scope; call the provided handleClose() to dismiss the modal before confirming.

-                  <Button
+                  <Button
                     variant="primary"
                     onClick={() => {
-                      close();
+                      handleClose();
                       onConfirm(date);
                     }}
                   >
🧹 Nitpick comments (10)
packages/propel/package.json (1)

52-52: Version ownership: pin vs. catalog

Having Propel own react-day-picker@9.5.0 is fine. If you prefer centralized versioning like other deps (catalog:), consider moving this to the repo catalog for consistency. Optional.

apps/web/core/components/core/filters/date-filter-modal.tsx (1)

97-110: Minor: dedupe repeated Calendar classNames

The classNames.root string is duplicated. Consider extracting to a constant to keep it DRY.

+ const calendarRootClass = "border border-custom-border-200 p-3 rounded-md";
...
   <Calendar
-    classNames={{ root: ` border border-custom-border-200 p-3 rounded-md` }}
+    classNames={{ root: calendarRootClass }}
     ...
   />
...
   <Calendar
-    classNames={{ root: ` border border-custom-border-200 p-3 rounded-md` }}
+    classNames={{ root: calendarRootClass }}
     ...
   />

Also applies to: 122-135

apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (1)

51-66: Optional: avoid shadowing and redundant cloning.

The onSelect parameter date shadows the state variable date, and selected/defaultMonth re-wrap date with new Date(..) unnecessarily. Not a bug, but minor cleanup possible.

-                    onSelect={(date) => {
-                      if (!date) return;
-                      setDate(date);
+                    onSelect={(d) => {
+                      if (!d) return;
+                      setDate(d);
                     }}
-                    selected={date ? new Date(date) : undefined}
-                    defaultMonth={date ? new Date(date) : undefined}
+                    selected={date ?? undefined}
+                    defaultMonth={date ?? undefined}
packages/propel/src/calendar/root.tsx (2)

21-33: Tighten Chevron override (destructure orientation, clearer props).

Readability: destructure orientation directly and pass the rest explicitly.

-      components={{
-        Chevron: ({ className, ...props }) => (
-          <ChevronLeft
-            className={cn(
-              "size-4",
-              { "rotate-180": props.orientation === "right", "-rotate-90": props.orientation === "down" },
-              className
-            )}
-            {...props}
-          />
-        ),
-      }}
+      components={{
+        Chevron: ({ className, orientation, ...rest }) => (
+          <ChevronLeft
+            className={cn(
+              "size-4",
+              { "rotate-180": orientation === "right", "-rotate-90": orientation === "down" },
+              className
+            )}
+            {...rest}
+          />
+        ),
+      }}

19-35: Remove redundant prop and clarify end-of-window var name.

  • weekStartsOn is already included via {...props}; the explicit prop is redundant.
  • Rename thirtyYearsFromNowFirstDay to thirtyYearsFromNowLastDay to reflect Dec 31.
 export const Calendar = ({ className, showOutsideDays = true, ...props }: CalendarProps) => {
   const currentYear = new Date().getFullYear();
   const thirtyYearsAgoFirstDay = new Date(currentYear - 30, 0, 1);
-  const thirtyYearsFromNowFirstDay = new Date(currentYear + 30, 11, 31);
+  const thirtyYearsFromNowLastDay = new Date(currentYear + 30, 11, 31);

   return (
     <DayPicker
       showOutsideDays={showOutsideDays}
       className={cn("p-3", className)}
-      weekStartsOn={props.weekStartsOn}
       components={{
         Chevron: ({ className, ...props }) => (
           <ChevronLeft
             className={cn(
               "size-4",
               { "rotate-180": props.orientation === "right", "-rotate-90": props.orientation === "down" },
               className
             )}
             {...props}
           />
         ),
       }}
       startMonth={thirtyYearsAgoFirstDay}
-      endMonth={thirtyYearsFromNowFirstDay}
+      endMonth={thirtyYearsFromNowLastDay}
       {...props}
     />
   );
 }
packages/propel/src/calendar/calendar.stories.tsx (5)

1-4: Import from the public barrel and pull in reusable types

Stories should exercise the public API and reuse exported types.

-import { Calendar } from "./root";
+import { Calendar, type DateRange, type Matcher } from ".";

41-44: Use the DateRange type for stronger typing

Aligns with the Calendar/DayPicker API and simplifies future refactors.

-    const [dateRange, setDateRange] = useState<{ from?: Date; to?: Date }>({
+    const [dateRange, setDateRange] = useState<DateRange | undefined>({
       from: new Date(),
       to: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days from now
     });

73-75: Guard onSelect against undefined in multiple mode

DayPicker may call onSelect with undefined; keep state consistent.

-          onSelect={setDates}
+          onSelect={(v) => setDates(v ?? [])}

86-90: Type disabledDays for better safety and editor help

Annotate as Matcher[] to match DayPicker’s matcher API.

-    const disabledDays = [
+    const disabledDays: Matcher[] = [
       { dayOfWeek: [0, 6] }, // Sunday and Saturday
       new Date(2024, 4, 10), // May 10, 2024
     ];

21-143: Optional: make stories time-stable

Direct new Date() calls can cause flaky visuals over time. Consider a fixed “today” (e.g., via a const or Storybook global/arg) to stabilize snapshots.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 20d139c and 953991e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • apps/web/app/(all)/layout.tsx (1 hunks)
  • apps/web/core/components/core/filters/date-filter-modal.tsx (1 hunks)
  • apps/web/core/components/dropdowns/date-range.tsx (1 hunks)
  • apps/web/core/components/dropdowns/date.tsx (1 hunks)
  • apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (1 hunks)
  • apps/web/package.json (0 hunks)
  • packages/propel/.storybook/preview.ts (1 hunks)
  • packages/propel/package.json (3 hunks)
  • packages/propel/src/calendar/calendar.stories.tsx (1 hunks)
  • packages/propel/src/calendar/index.ts (1 hunks)
  • packages/propel/src/calendar/root.tsx (1 hunks)
  • packages/propel/tsdown.config.ts (1 hunks)
  • packages/ui/src/calendar.tsx (0 hunks)
  • packages/ui/src/index.ts (0 hunks)
💤 Files with no reviewable changes (3)
  • packages/ui/src/index.ts
  • apps/web/package.json
  • packages/ui/src/calendar.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-04T16:22:44.344Z
Learnt from: lifeiscontent
PR: makeplane/plane#7164
File: packages/ui/.storybook/main.ts:24-47
Timestamp: 2025-06-04T16:22:44.344Z
Learning: In packages/ui/.storybook/main.ts, the webpackFinal function intentionally overrides the CSS loader strategy by finding and replacing existing CSS rules. This is a temporary workaround for a known upstream issue in Storybook's CSS handling that has been communicated to the Storybook maintainers. The current implementation should not be changed until the upstream issue is resolved.

Applied to files:

  • packages/propel/.storybook/preview.ts
🧬 Code graph analysis (1)
packages/propel/src/calendar/calendar.stories.tsx (1)
packages/propel/src/calendar/root.tsx (1)
  • Calendar (11-38)
🪛 GitHub Check: Build and lint web apps
packages/propel/src/calendar/calendar.stories.tsx

[failure] 5-5:
An interface declaring no members is equivalent to its supertype

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (12)
apps/web/app/(all)/layout.tsx (1)

8-8: No lingering old stylesheet references; migration complete
Verified there are no imports or files for the old react-day-picker.css and all consumers now import from @plane/propel/styles/react-day-picker.

packages/propel/.storybook/preview.ts (1)

3-3: Storybook CSS import is appropriate for local dev

Importing from src keeps HMR tight for Storybook. No change requested.

packages/propel/package.json (2)

21-34: Exports and copy step verified
Calendar and react-day-picker CSS subpath exports match their dist paths and tsdown copies src/styles as configured, so importing the CSS subpath will work.


41-57: Confirm no react-day-picker usage in apps/web
No references found in apps/web/package.json or code imports/requires; safe to merge.

packages/propel/tsdown.config.ts (2)

7-8: Calendar entry added to build surface—LGTM

Including src/calendar/index.ts ensures types and JS ship properly.


27-28: Verify CSS export path Ensure that after running the build, react-day-picker.css is located at packages/propel/dist/styles/react-day-picker.css.

apps/web/core/components/core/filters/date-filter-modal.tsx (1)

8-9: Import migration to Propel calendar looks correct

Decouples the app from UI’s calendar. Button import separation is fine.

apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (2)

7-8: Calendar import migration looks good.

Importing Calendar from @plane/propel/calendar and keeping Button from @plane/ui aligns with the package split.


1-85: Resolve DayPicker style and dependency checks: CSS import from @plane/propel/styles/react-day-picker is present, no direct react-day-picker imports or Calendar from @plane/ui remain, and the react-day-picker dependency has been moved to packages/propel.

packages/propel/src/calendar/index.ts (1)

1-2: Barrel and type re-exports look correct.

Re-exporting Calendar and the Matcher/DateRange types from one place simplifies app imports.

apps/web/core/components/dropdowns/date-range.tsx (1)

12-13: Good consolidation of imports via Propel.

Pulling Calendar, DateRange, and Matcher from @plane/propel/calendar removes the app’s direct coupling to react-day-picker.

apps/web/core/components/dropdowns/date.tsx (1)

8-9: Import migration looks good.

Using Calendar and Matcher from @plane/propel/calendar with ComboDropDown from @plane/ui matches the new split.

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: 1

🧹 Nitpick comments (4)
packages/propel/src/calendar/calendar.stories.tsx (4)

7-16: Adopt Storybook “satisfies” typing and drop the local props alias

Using the v7/v8-recommended “satisfies” pattern improves type safety and eliminates the need for a local CalendarProps alias and explicit generic wiring.

-import { ComponentProps, useState } from "react";
-import type { Meta, StoryObj } from "@storybook/react-vite";
+import { useState } from "react";
+import type { Meta, StoryObj } from "@storybook/react";
-import { Calendar } from "./root";
+import { Calendar } from "."; // mirror consumer import surface

-type CalendarProps = ComponentProps<typeof Calendar>;

-const meta: Meta<CalendarProps> = {
+const meta = {
   title: "Components/Calendar",
   component: Calendar,
   parameters: {
     layout: "centered",
   },
-  args: {
-    showOutsideDays: true,
-  },
-};
+} satisfies Meta<typeof Calendar>;
 
 export default meta;
-type Story = StoryObj<CalendarProps>;
+type Story = StoryObj<typeof meta>;
 
 export const Default: Story = {
   args: {},
-  render: (args: CalendarProps) => {
+  render: (args) => {

Also applies to: 19-20, 23-23


3-3: Import from the barrel index instead of './root'

Stories should import the public surface to match consumer usage and catch export/packaging issues earlier.

-import { Calendar } from "./root";
+import { Calendar } from ".";

24-24: Stabilize the initial date to avoid flaky visual/snapshot diffs

Using “today” can cause story renders to change daily. Pick a fixed date for determinism in Chromatic/visual tests.

-    const [date, setDate] = useState<Date | undefined>(new Date());
+    const [date, setDate] = useState<Date | undefined>(new Date(2024, 0, 1));

21-32: Hooks inside render may trigger react-hooks lint in some setups

If lint complains about hooks in inline render functions, move state into a small wrapper component or a Template function.

Example:

const DefaultRender = (args: React.ComponentProps<typeof Calendar>) => {
  const [date, setDate] = useState<Date | undefined>(new Date(2024, 0, 1));
  return (
    <div className="p-4">
      <Calendar {...args} mode="single" selected={date} onSelect={setDate} className="rounded-md border" />
    </div>
  );
};

export const Default: Story = { render: DefaultRender };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f51b2b and e2e899c.

📒 Files selected for processing (2)
  • packages/propel/src/calendar/calendar.stories.tsx (1 hunks)
  • packages/propel/src/calendar/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/propel/src/calendar/index.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/propel/src/calendar/calendar.stories.tsx (1)
packages/propel/src/calendar/root.tsx (2)
  • CalendarProps (9-9)
  • Calendar (11-38)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build and lint web apps
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
packages/propel/src/calendar/calendar.stories.tsx (1)

5-5: Resolved lint warning: empty interface replaced with type alias — good fix

This addresses the earlier lint failure. No further action needed here.

@sriramveeraghanta sriramveeraghanta merged commit 4986132 into preview Sep 9, 2025
6 of 7 checks passed
@sriramveeraghanta sriramveeraghanta deleted the chore-calendar-migration-ui-to-propel branch September 9, 2025 18:21
yarikoptic pushed a commit to yarikoptic/plane that referenced this pull request Oct 1, 2025
…e#7730)

* chore: move calendar components and dependencies

* chore: update package configurations

* chore: calendar import updated

* chore: propel config updated

* chore: propel calendar code refactor

* chore: code refactor

* fix: build error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants