Skip to content

feat(web): add infinite calendar views and display items#449

Open
JeanMeijer wants to merge 1 commit intomainfrom
feat/add-infinite-calendar-views-and-display-items
Open

feat(web): add infinite calendar views and display items#449
JeanMeijer wants to merge 1 commit intomainfrom
feat/add-infinite-calendar-views-and-display-items

Conversation

@JeanMeijer
Copy link
Collaborator

@JeanMeijer JeanMeijer commented Feb 12, 2026

Description

Briefly describe what you did and why.

Screenshots / Recordings

Add screenshots or recordings here to help reviewers understand your changes.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • UI/UX update
  • Docs update
  • Refactor / Cleanup

Related Areas

  • Authentication
  • Calendar UI
  • Data/API
  • Docs

Testing

  • Manual testing performed
  • Cross-browser testing (if UI changes)
  • Mobile responsiveness verified (if UI changes)

Checklist

  • I’ve read the CONTRIBUTING guide
  • My code works and is understandable and follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in complex areas
  • I have updated the documentation
  • Any dependent changes are merged and published

Notes

(Optional) Add anything else you'd like to share.

By submitting, I confirm I understand and stand behind this code. If AI was used, I’ve reviewed and verified everything myself.


Summary by cubic

Adds infinite-scrolling calendar views and a new display item system. Events, tasks, and journeys render consistently with drag/resize interactions and smoother navigation.

  • New Features

    • Infinite Month and Week views with virtualized providers and snap-to-month rows.
    • Unified DisplayItem model (events, tasks, journeys); Agenda shows items; drag, drop, and resize with a drag preview portal.
    • New container/transform providers and drag/resizable hooks; split month/week event components; improved context menu.
    • Header navigation and view menu rebuilt; calendar colors now resolve from the store; CalendarLayout is client-only for stability.
  • Migration

    • Replace Jotai atoms with CalendarStoreProvider and hooks (useCalendarStore/useCalendarView/useDefaultTimeZone, etc.). Remove prior atoms for settings, preferences, drag/resize, selection, windows.
    • Update imports for optimistic actions and event mutations to "@/hooks/calendar/...".
    • Replace DraggableEvent with DraggableMonthEvent/DraggableWeekEvent or ReadOnlyWeekEvent and use EventDisplayItem/InlineDisplayItem.
    • CSS: custom properties are typed via globals.d.ts; use style keys like "--calendar-color" and new "accent-light"/journey variables.

Written for commit cb9bcbe. Summary will update on new commits.

@vercel
Copy link

vercel bot commented Feb 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
analog Ready Ready Preview, Comment Feb 12, 2026 2:38pm

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

24 issues found across 280 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/src/components/calendar/header/calendar-picker/calendar-picker.tsx">

<violation number="1" location="apps/web/src/components/calendar/header/calendar-picker/calendar-picker.tsx:51">
P1: Rule violated: **CSS variable naming and usage conventions (Tailwind v4 namespaces)**

CSS variable name "--calendar-color" violates the Tailwind v4 token namespace rule. Use an allowed namespace such as --color-* for design tokens (rule: CSS variable naming and usage conventions).</violation>
</file>

<file name="apps/web/src/components/calendar/display-item/augmented-item.tsx">

<violation number="1" location="apps/web/src/components/calendar/display-item/augmented-item.tsx:13">
P1: Rule violated: **CSS variable naming and usage conventions (Tailwind v4 namespaces)**

CSS variable names must use an approved namespace (e.g., --color-*) per the “CSS variable naming and usage conventions (Tailwind v4 namespaces)” rule. `--item-color` and `--item-stripe-color` are un-namespaced tokens and violate the rule.</violation>
</file>

<file name="apps/web/src/components/calendar/event/drag-preview.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/drag-preview.tsx:20">
P1: Rule violated: **CSS variable naming and usage conventions (Tailwind v4 namespaces)**

Rename the CSS variable to an allowed Tailwind v4 token namespace (e.g., --color-*) per the CSS variable naming convention rule.</violation>
</file>

<file name="apps/web/src/app/globals.css">

<violation number="1" location="apps/web/src/app/globals.css:51">
P1: Rule violated: **Define custom utilities, variants and plugins using v4 directives; use @apply in components**

Use the Tailwind v4 `@variant` directive for custom variants; `@custom-variant` is deprecated under the rule’s v4 directive requirement.</violation>
</file>

<file name="apps/web/src/components/calendar/event/draggable-week-event.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/draggable-week-event.tsx:138">
P1: Bug: `!columnIndex` is a falsy check that incorrectly rejects column index `0` as invalid. `calculateColumnIndex` returns `null` for out-of-bounds and a number (including `0`) for valid columns. Use a strict null check instead.</violation>
</file>

<file name="apps/web/src/components/calendar/header/calendar-navigation.tsx">

<violation number="1" location="apps/web/src/components/calendar/header/calendar-navigation.tsx:24">
P3: "use memo" is not a recognized directive and is a no-op string statement, so it adds dead code and can mislead readers into thinking memoization is applied. Remove it (or use React.memo if memoization is intended).</violation>
</file>

<file name="apps/web/src/components/calendar/event/use-horizontal-resizable.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/use-horizontal-resizable.tsx:111">
P2: relativeX is never initialized on resize start, so ending a resize without movement reports a negative delta. Initialize relativeX on start (or handle the no-move case) to avoid incorrect resize deltas.</violation>
</file>

<file name="apps/web/src/components/calendar/flows/create-event/create-event-attendee-dialog.tsx">

<violation number="1" location="apps/web/src/components/calendar/flows/create-event/create-event-attendee-dialog.tsx:18">
P3: "use memo" is not a valid React/Next.js directive and does nothing here. It adds dead code and implies memoization that doesn’t exist. Remove it or implement actual memoization (e.g., React.memo).</violation>
</file>

<file name="apps/web/src/components/calendar/flows/update-event/update-recurring-event-dialog.tsx">

<violation number="1" location="apps/web/src/components/calendar/flows/update-event/update-recurring-event-dialog.tsx:18">
P3: "use memo" is not a recognized React directive and does nothing inside the component body, so the new line is a no-op and misleading. Remove it or replace with actual memoization logic (e.g., wrapping the component with React.memo).</violation>
</file>

<file name="apps/web/src/components/calendar/flows/delete-event/delete-event-attendee-dialog.tsx">

<violation number="1" location="apps/web/src/components/calendar/flows/delete-event/delete-event-attendee-dialog.tsx:18">
P2: "use memo" is a no-op string literal and not a valid React/Next.js directive. It won’t memoize the component and just adds dead code. Remove it (or replace with a real memoization pattern if needed).</violation>
</file>

<file name="apps/web/src/components/app-sidebar.tsx">

<violation number="1" location="apps/web/src/components/app-sidebar.tsx:20">
P3: This "use memo" directive is not a recognized React/Next directive and sits inside the component body, so it has no effect (and may trip no-unused-expressions). Remove it or replace with actual memoization (e.g., React.memo).</violation>
</file>

<file name="apps/web/src/components/calendar/month-view/infinite-month-view-provider.tsx">

<violation number="1" location="apps/web/src/components/calendar/month-view/infinite-month-view-provider.tsx:43">
P1: Use the context Provider component; rendering the context object directly will not pass the value to consumers and will fail at runtime.</violation>
</file>

<file name="apps/web/src/components/calendar/display-item/draggable.tsx">

<violation number="1" location="apps/web/src/components/calendar/display-item/draggable.tsx:38">
P1: Local drag handlers shadow the prop callbacks and then call themselves, causing infinite recursion and preventing the passed-in handlers from ever running. Rename the internal handlers and call the props instead (e.g., `handleDragStart` -> `onDragStart`).</violation>
</file>

<file name="apps/web/src/components/calendar/context/container-provider.tsx">

<violation number="1" location="apps/web/src/components/calendar/context/container-provider.tsx:38">
P1: Render the context provider (`ContainerContext.Provider`) instead of the context object, otherwise the value is never provided to children.</violation>
</file>

<file name="apps/web/src/components/calendar/month-view/infinite-month-view.tsx">

<violation number="1" location="apps/web/src/components/calendar/month-view/infinite-month-view.tsx:20">
P3: Standalone string literal inside the component is a no-op. If memoization is intended, this needs a real memoization mechanism (e.g., React.memo/useMemo); otherwise remove the line to avoid dead code.</violation>
</file>

<file name="apps/web/src/components/calendar/event/draggable-month-event.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/draggable-month-event.tsx:142">
P3: The `"use memo"` string is a no-op inside the component body and does not memoize anything. Remove it (or wrap the component with `React.memo` if memoization is intended) to avoid misleading code and potential lint failures.</violation>
</file>

<file name="apps/web/src/components/calendar/event/use-draggable.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/use-draggable.tsx:30">
P3: The "use memo" directive is a no-op and not a valid React directive. It adds dead code and can mislead readers; remove it or replace with actual memoization if intended.</violation>

<violation number="2" location="apps/web/src/components/calendar/event/use-draggable.tsx:68">
P2: onDragEnd should mirror onDragStart/onDrag and return early when disabled or no container ref; otherwise it can fire callbacks with invalid drag state.</violation>
</file>

<file name="apps/web/src/components/calendar/display-item/task-item.tsx">

<violation number="1" location="apps/web/src/components/calendar/display-item/task-item.tsx:23">
P2: Provide an accessible label for the checkbox so assistive tech can identify which task it represents.</violation>
</file>

<file name="apps/web/src/components/calendar/agenda-view/agenda-view.tsx">

<violation number="1" location="apps/web/src/components/calendar/agenda-view/agenda-view.tsx:11">
P3: `"use memo"` is not a valid React/Next.js directive and is a no-op string expression. If memoization is intended, use `React.memo` or `useMemo`; otherwise remove this line to avoid confusing dead code.</violation>

<violation number="2" location="apps/web/src/components/calendar/agenda-view/agenda-view.tsx:14">
P2: The empty-state overlay is now always visible because `AgendaViewEmpty` is always rendered and the wrapper no longer has hiding/conditional logic. This will display “No items found” even when items exist. Render the empty state conditionally (e.g., when `items.length === 0`) or reintroduce a hide/show mechanism.</violation>
</file>

<file name="apps/web/src/components/calendar/display-item/draggable-task-item.tsx">

<violation number="1" location="apps/web/src/components/calendar/display-item/draggable-task-item.tsx:39">
P2: Only set the dragging event id after verifying the container exists; otherwise a missing container leaves the store stuck in a dragging state.</violation>
</file>

<file name="apps/web/src/components/calendar/event/event-item.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/event-item.tsx:98">
P2: Avoid calling `selectAction` on both `onMouseDown` and `onClick`; a single click currently triggers the selection logic twice, which can result in duplicate `LOAD` events and redundant selection updates.</violation>
</file>

<file name="apps/web/src/components/calendar/event/use-vertical-resizable.tsx">

<violation number="1" location="apps/web/src/components/calendar/event/use-vertical-resizable.tsx:97">
P2: Clamp the resized height (and derived top offset) to a minimum so dragging the top handle past the bottom can’t create negative heights and inverted event durations.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

timelineWidth,
});

if (!columnIndex) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 12, 2026

Choose a reason for hiding this comment

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

P1: Bug: !columnIndex is a falsy check that incorrectly rejects column index 0 as invalid. calculateColumnIndex returns null for out-of-bounds and a number (including 0) for valid columns. Use a strict null check instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/calendar/event/draggable-week-event.tsx, line 138:

<comment>Bug: `!columnIndex` is a falsy check that incorrectly rejects column index `0` as invalid. `calculateColumnIndex` returns `null` for out-of-bounds and a number (including `0`) for valid columns. Use a strict null check instead.</comment>

<file context>
@@ -0,0 +1,324 @@
+        timelineWidth,
+      });
+
+      if (!columnIndex) {
+        return;
+      }
</file context>
Fix with Cubic

className,
...props
}: InfiniteMonthViewProps) {
"use memo";
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 12, 2026

Choose a reason for hiding this comment

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

P3: Standalone string literal inside the component is a no-op. If memoization is intended, this needs a real memoization mechanism (e.g., React.memo/useMemo); otherwise remove the line to avoid dead code.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/web/src/components/calendar/month-view/infinite-month-view.tsx, line 20:

<comment>Standalone string literal inside the component is a no-op. If memoization is intended, this needs a real memoization mechanism (e.g., React.memo/useMemo); otherwise remove the line to avoid dead code.</comment>

<file context>
@@ -0,0 +1,79 @@
+  className,
+  ...props
+}: InfiniteMonthViewProps) {
+  "use memo";
+
+  const containerRef = React.useRef<HTMLDivElement>(null);
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant