feat: Add event support to notes (color + recurring)#94
Conversation
Adds first-class "event" items alongside free-form notes so users can create colored, recurring events and have them displayed/styled in the calendar. Adds type, color, recurring pattern and interval fields to the data model and API; updates hooks and responses to create/update events. Extends the note editor with type selection, color presets and custom recurring intervals, and updates calendar rendering to surface event titles and border styling. Updates translations, README copy and UI dialog handling, and adds a small UI dependency for radio controls. Benefits: enables distinct event semantics, visual differentiation, and recurring scheduling for calendar entries, improving usability for planned events versus simple notes.
|
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughThis PR introduces support for typed notes and recurring events to the calendar application. Database schema adds type, color, recurringPattern, and recurringInterval columns to calendar_notes. API routes extended to handle these fields. New event utility functions match recurring events by date. UI components redesigned to support event creation/editing with color selection and recurrence configuration. New dialog component for listing notes/events per date. Localization expanded across multiple languages. Changes
Sequence DiagramsequenceDiagram
actor User
participant UI as Note Sheet UI
participant Handler as handleNoteSubmit
participant API as API Route<br/>(POST/PUT)
participant DB as Database
participant Grid as Calendar Grid
User->>UI: Select type (Note or Event)
alt Type = Event
User->>UI: Pick color
User->>UI: Select recurring pattern
alt Recurring = Custom
User->>UI: Set interval & unit
end
end
User->>UI: Submit
UI->>Handler: handleNoteSubmit(text, type, color, pattern, interval)
Handler->>API: POST/PUT with all fields
API->>DB: Insert/Update note with type, color,<br/>recurringPattern, recurringInterval
DB-->>API: Success
API-->>Handler: Confirm
Handler->>Grid: Refresh calendar view
Note over Grid: findNotesForDate finds matching<br/>recurring events for each day
Grid->>Grid: Render events with color,<br/>borders, recurrence badge
Grid-->>User: Display updated calendar
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested labels
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
lib/db/schema.ts (1)
121-124: Consider makingrecurringPatternNOT NULL for data consistency.The
recurringPatternfield has a default value of"none"but is not marked asnotNull(). This could lead to inconsistent states where some records haveNULLand others have"none"for the same semantic meaning.Unless there's a specific reason to allow NULL (e.g., distinguishing legacy records), consider updating the schema:
- recurringPattern: text("recurring_pattern").default("none"), + recurringPattern: text("recurring_pattern").notNull().default("none"),This would require regenerating the migration to include
NOT NULLin the ALTER statement.As per coding guidelines, database schema changes require generating migrations with
npm run db:generateandnpm run db:migrate.hooks/useNoteActions.ts (1)
5-22: Consider using an options object for cleaner function signatures.The
createNoteandupdateNotefunctions now have 7 positional parameters each, with several optional ones at the end. This pattern can become unwieldy as more fields are added.🔎 Suggested refactor using options object
interface UseNoteActionsProps { - createNote: ( - text: string, - date: Date, - onPasswordRequired: () => void, - type?: "note" | "event", - color?: string, - recurringPattern?: string, - recurringInterval?: number - ) => Promise<boolean>; - updateNote: ( - id: string, - text: string, - onPasswordRequired: () => void, - type?: "note" | "event", - color?: string, - recurringPattern?: string, - recurringInterval?: number - ) => Promise<boolean>; + createNote: ( + text: string, + date: Date, + onPasswordRequired: () => void, + options?: { + type?: "note" | "event"; + color?: string; + recurringPattern?: string; + recurringInterval?: number; + } + ) => Promise<boolean>; + updateNote: ( + id: string, + text: string, + onPasswordRequired: () => void, + options?: { + type?: "note" | "event"; + color?: string; + recurringPattern?: string; + recurringInterval?: number; + } + ) => Promise<boolean>;components/calendar-grid.tsx (1)
134-152: Potential O(n²) complexity in recurring event matching.The current implementation calls
findEventForDate(notes, day)inside the filter callback for each note, which iterates through all notes again. This results in O(n²) complexity per day.🔎 Suggested optimization
// Find notes/events for this day using new event-utils - const matchingNotes = notes.filter((note) => { - if (!note.date) return false; - const noteDate = new Date(note.date); - - // Always match exact date for both notes and events - if (isSameDay(noteDate, day)) return true; - - // For events with recurring patterns, use findEventForDate - if ( - note.type === "event" && - note.recurringPattern && - note.recurringPattern !== "none" - ) { - const foundEvent = findEventForDate(notes, day); - return foundEvent?.id === note.id; - } - - return false; - }); + // Find the event for this day (handles recurring) - O(n) + const dayEvent = findEventForDate(notes, day); + + // Find notes that match this exact day - O(n) + const dayNote = notes.find((note) => { + if (!note.date || note.type !== "note") return false; + return isSameDay(new Date(note.date), day); + });This eliminates the need for
matchingNotesentirely since you only usedayNoteanddayEventanyway.components/note-sheet.tsx (1)
343-352: Consider dynamic max value based on unit.The
max={52}works well for weeks (≈1 year), but for months it allows intervals up to 52 months. Consider adjusting dynamically if you want to constrain monthly intervals differently.🔎 Optional: Dynamic max based on unit
<Input type="number" min={1} - max={52} + max={recurringUnit === "weeks" ? 52 : 24} value={recurringInterval}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (20)
README.md(1 hunks)app/api/notes/[id]/route.ts(2 hunks)app/api/notes/route.ts(2 hunks)app/page.tsx(6 hunks)components/calendar-grid.tsx(4 hunks)components/calendar-sheet.tsx(1 hunks)components/dialog-manager.tsx(1 hunks)components/note-sheet.tsx(4 hunks)components/ui/radio-group.tsx(1 hunks)drizzle/0012_organic_romulus.sql(1 hunks)drizzle/meta/0012_snapshot.json(1 hunks)drizzle/meta/_journal.json(1 hunks)hooks/useNoteActions.ts(2 hunks)hooks/useNotes.ts(4 hunks)lib/db/schema.ts(1 hunks)lib/event-utils.ts(1 hunks)messages/de.json(1 hunks)messages/en.json(1 hunks)messages/it.json(1 hunks)package.json(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
app/api/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/api/**/*.ts: Use Next.js 16 App Router with async dynamic route params - alwaysawait paramsin route handlers
Password protection uses two-tier system: checkisLockedflag for read operations (GET), andpasswordHashfor all write operations (POST/PUT/DELETE)
Files:
app/api/notes/[id]/route.tsapp/api/notes/route.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use English for all code, comments, and variable names
Write comments only for complex or non-obvious logic - prefer self-documenting variable names
Files:
app/api/notes/[id]/route.tscomponents/ui/radio-group.tsxhooks/useNotes.tscomponents/calendar-grid.tsxlib/event-utils.tsapp/api/notes/route.tsapp/page.tsxhooks/useNoteActions.tscomponents/calendar-sheet.tsxcomponents/note-sheet.tsxcomponents/dialog-manager.tsxlib/db/schema.ts
hooks/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Create custom hooks in
hooks/directory for CRUD operations following existing patterns in available custom hooks
Files:
hooks/useNotes.tshooks/useNoteActions.ts
app/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/**/*.tsx: Always use existing custom hooks fromhooks/instead of implementing custom fetch logic for CRUD operations on shifts, presets, notes, and calendars
UsegetCachedPassword(),verifyAndCachePassword(),setCachedPassword(), andremoveCachedPassword()fromlib/password-cache.tsfor password handling
Always useuseDirtyStatehook for tracking unsaved changes in forms and sheets
UsePRESET_COLORSarray and store colors in hex format (#RRGGBB), applying 20% opacity for backgrounds using format${color}20
UseformatDateToLocal()utility for formatting dates to YYYY-MM-DD format in UI
UseConfirmationDialogcomponent for confirmations - never use native JavaScriptconfirm()
Support real-time updates via Server-Sent Events (SSE) - listen to relevant SSE events and use silent refresh patterns (fetchData(false)) to update without loading states
Use Tailwind CSS 4, shadcn/ui components, and gradient styling patterns: gradient backgrounds (from-primary/10 via-primary/5), border opacity (border-border/50), consistent padding (px-6 py-6), and sticky footers
Use separate mobile calendar dialog withshowMobileCalendarDialogprop for improved mobile UI/UX
Files:
app/page.tsx
messages/*.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
messages/*.json: Use next-intl for internationalization with messages inmessages/{de,en,it}.json- add new keys to all three language files
Organize translation keys inmessages/*.jsonas:common.*for CRUD operations with{item}parameter,validation.*for validation messages,form.*for reusable form labels, and feature-specific namespaces for feature keys
Files:
messages/de.jsonmessages/it.jsonmessages/en.json
messages/de.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
German translations must ALWAYS use informal 'du' form, never 'Sie'
Files:
messages/de.json
lib/db/schema.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
lib/db/schema.ts: Generate database migrations usingnpm run db:generateandnpm run db:migrate- never usedb:push
Store SQLite timestamps as integers using{ mode: "timestamp" }which are auto-converted to Date objects
Use crypto.randomUUID() for all ID generation in database schema
Database schema changes require updatinglib/db/schema.tsAND generating migrations - create API routes for new tables atapp/api/tablename/route.tsandapp/api/tablename/[id]/route.ts
Implement cascade delete relationships in database schema - deleting a calendar removes all related shifts, presets, and notes
Files:
lib/db/schema.ts
🧠 Learnings (13)
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/calendar*.tsx : Calendar interactions: left-click toggles shift with selected preset (delete if exists, create if not), right-click opens note dialog with prevented default context menu
Applied to files:
README.mdcomponents/calendar-grid.tsxapp/page.tsxmessages/de.jsonhooks/useNoteActions.tscomponents/calendar-sheet.tsxcomponents/note-sheet.tsxcomponents/dialog-manager.tsxmessages/en.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use Tailwind CSS 4, shadcn/ui components, and gradient styling patterns: gradient backgrounds (`from-primary/10 via-primary/5`), border opacity (`border-border/50`), consistent padding (`px-6 py-6`), and sticky footers
Applied to files:
package.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to lib/db/schema.ts : Database schema changes require updating `lib/db/schema.ts` AND generating migrations - create API routes for new tables at `app/api/tablename/route.ts` and `app/api/tablename/[id]/route.ts`
Applied to files:
app/api/notes/[id]/route.tslib/db/schema.ts
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use separate mobile calendar dialog with `showMobileCalendarDialog` prop for improved mobile UI/UX
Applied to files:
components/calendar-grid.tsxapp/page.tsxcomponents/calendar-sheet.tsxcomponents/dialog-manager.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Always use existing custom hooks from `hooks/` instead of implementing custom fetch logic for CRUD operations on shifts, presets, notes, and calendars
Applied to files:
components/calendar-grid.tsxapp/page.tsxhooks/useNoteActions.tscomponents/note-sheet.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `formatDateToLocal()` utility for formatting dates to YYYY-MM-DD format in UI
Applied to files:
components/calendar-grid.tsxlib/event-utils.tsapp/page.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `getCachedPassword()`, `verifyAndCachePassword()`, `setCachedPassword()`, and `removeCachedPassword()` from `lib/password-cache.ts` for password handling
Applied to files:
app/page.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/*.json : Use next-intl for internationalization with messages in `messages/{de,en,it}.json` - add new keys to all three language files
Applied to files:
messages/de.jsonmessages/it.jsonmessages/en.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/de.json : German translations must ALWAYS use informal 'du' form, never 'Sie'
Applied to files:
messages/de.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*sheet*.tsx : Use `BaseSheet` component for simple forms (create, edit, settings) with gradient headers, border opacity styling, and sticky footer
Applied to files:
components/note-sheet.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Always use `useDirtyState` hook for tracking unsaved changes in forms and sheets
Applied to files:
components/note-sheet.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to lib/db/schema.ts : Implement cascade delete relationships in database schema - deleting a calendar removes all related shifts, presets, and notes
Applied to files:
lib/db/schema.ts
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/*.json : Organize translation keys in `messages/*.json` as: `common.*` for CRUD operations with `{item}` parameter, `validation.*` for validation messages, `form.*` for reusable form labels, and feature-specific namespaces for feature keys
Applied to files:
messages/en.json
🧬 Code graph analysis (5)
components/ui/radio-group.tsx (1)
lib/utils.ts (1)
cn(4-6)
hooks/useNotes.ts (1)
lib/password-cache.ts (1)
getCachedPassword(9-14)
components/calendar-grid.tsx (1)
lib/event-utils.ts (1)
findEventForDate(76-101)
app/page.tsx (3)
lib/event-utils.ts (2)
findNoteForDate(103-132)findEventForDate(76-101)components/empty-calendar-state.tsx (1)
EmptyCalendarState(11-59)components/dialog-manager.tsx (1)
DialogManager(113-258)
components/note-sheet.tsx (2)
components/ui/base-sheet.tsx (1)
BaseSheet(41-142)lib/constants.ts (1)
PRESET_COLORS(8-17)
🪛 Biome (2.1.2)
lib/event-utils.ts
[error] 51-51: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 53-53: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
[error] 56-59: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.
The declaration is defined in this switch clause:
Safe fix: Wrap the declaration in a block.
(lint/correctness/noSwitchDeclarations)
⏰ 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: Agent
- GitHub Check: build-dev
🔇 Additional comments (25)
README.md (1)
40-40: LGTM! Documentation accurately reflects the new event functionality.The updated Quick Actions description now correctly mentions that right-click can add notes or events, aligning with the broader event support introduced in this PR.
drizzle/meta/_journal.json (1)
89-95: LGTM! Migration journal entry is properly structured.The new journal entry for migration
0012_organic_romulusfollows the established pattern and correctly accompanies the schema changes for event support.components/ui/radio-group.tsx (1)
1-44: LGTM! Well-structured RadioGroup components.The RadioGroup and RadioGroupItem components follow the established shadcn/ui pattern with proper:
- forwardRef implementation for ref handling
- TypeScript typing from Radix primitives
- displayName for debugging
- Tailwind styling with the cn utility
These components provide the foundation for the new note/event type selection UI.
messages/it.json (1)
121-139: LGTM! Italian translations properly support the new event and recurring features.The translation keys are well-organized and cover all aspects of the new functionality:
- Type selection (note vs. event)
- Event-specific fields (color, title)
- Recurring patterns and custom intervals
The use of
{item}parameter increateandeditkeys provides good flexibility for reuse.As per coding guidelines, new translation keys should be added to all three language files (de, en, it).
messages/de.json (1)
121-139: LGTM! German translations correctly use informal 'du' form and cover all new features.The translations properly implement:
- Informal "du" form as required by guidelines (e.g., "drücke", "mache")
- Consistent key structure with other language files
- Complete coverage of event and recurring functionality
As per coding guidelines, German translations must always use informal 'du' form, never 'Sie'.
drizzle/0012_organic_romulus.sql (1)
1-4: LGTM! Migration correctly implements the schema changes.The migration adds four new columns to support events and recurring items:
typewith NOT NULL constraint and default value ensures backward compatibilitycolorandrecurring_intervalare appropriately nullablerecurring_patternhas a default but no NOT NULL constraint (consistent with schema.ts)Note: The
recurring_patternnullability observation fromlib/db/schema.tsapplies here as well. If that field is updated to NOT NULL, remember to regenerate this migration.As per coding guidelines, migrations should be generated using
npm run db:generateand applied withnpm run db:migrate.package.json (1)
28-28: No action needed — dependency version is current.The
@radix-ui/react-radio-groupdependency is at version 1.3.8, the latest stable release. The caret range specified is appropriate for dependency management.components/calendar-sheet.tsx (1)
20-20: LGTM!Extending the return type to support both synchronous and asynchronous submission aligns well with the expanded note/event submission flow across the PR.
drizzle/meta/0012_snapshot.json (1)
38-67: LGTM!The snapshot correctly reflects the schema additions for event metadata (type, color, recurring_pattern, recurring_interval) with appropriate defaults and nullability constraints.
app/api/notes/route.ts (1)
85-94: LGTM!The POST handler correctly extends the request body to accept event metadata and applies sensible defaults (type="note", recurringPattern="none") that align with the database schema.
Also applies to: 132-135
hooks/useNotes.ts (2)
43-97: LGTM!The
createNotefunction correctly extends its signature and request payload to support event metadata, and dynamically adjusts toast messages based on item type.
100-150: LGTM!The
updateNotefunction correctly extends its signature and request payload to support event metadata, with consistent error handling and dynamic toast messages.components/dialog-manager.tsx (1)
103-109: LGTM!The
onNoteSubmitcallback signature is correctly extended to accept event metadata parameters, aligning with the broader API changes across the PR.app/page.tsx (4)
150-186: LGTM!The
handleNoteSubmitwrapper correctly extends the signature, forwards event metadata tonoteActions.handleNoteSubmit, and reloads compare-mode data to reflect changes.
458-473: LGTM!Replacing ad-hoc note lookups with
findNoteForDateensures consistent handling of both exact-date and recurring notes/events across all interaction paths (right-click, note icon, long press).
711-712: LGTM!Using
findEventForDatein compare mode correctly locates the original event for recurring instances, ensuring users edit the source event rather than creating duplicates.Also applies to: 730-731
1080-1149: LGTM!Wrapping
EmptyCalendarStatewithDialogManagerensures the calendar creation dialog is accessible even when no calendars exist, improving the onboarding flow.hooks/useNoteActions.ts (1)
37-94: LGTM!The
handleNoteSubmitcallback correctly forwards all event-related parameters (type,color,recurringPattern,recurringInterval) to bothcreateNoteandupdateNote, and the dependency array is complete.components/calendar-grid.tsx (2)
210-225: LGTM!The event border styling is correctly applied via inline styles when an event exists, and the conditional class handling properly defers to the inline style when
dayEventis present.
244-282: LGTM!The event and note title rendering is well-implemented with:
- Proper click handling that respects
selectedPresetIdstate- Event propagation correctly stopped to prevent day click
- Appropriate truncation and hover states for interactive elements
- Title attributes for accessibility/tooltips
components/note-sheet.tsx (4)
27-33: LGTM!The expanded
onSubmitsignature correctly supports the new event metadata fields while maintaining backward compatibility through optional parameters.
74-126: LGTM!The initialization logic correctly:
- Extracts the unit from compound patterns like
"custom-weeks"- Captures initial state for change detection in edit mode
- Resets all fields to defaults when the sheet closes
257-308: LGTM!The type selection and color picker UI are well-implemented with:
- Accessible radio buttons with proper labels
- Color buttons using
aria-labelfor screen readers- Clear visual feedback with the checkmark icon for the selected color
371-387: LGTM!The note/event text input correctly adapts its label and placeholder based on the selected type, maintaining consistent UX while supporting both use cases.
messages/en.json (1)
120-140: German and Italian translation files properly include all note keys.All new note.* keys are present in messages/de.json and messages/it.json with complete localizations. The keys are properly organized under the note namespace and follow the coding guidelines with correct
{item}parameter usage for dynamic content.
There was a problem hiding this comment.
Pull request overview
This PR adds first-class event support to the notes feature, enabling users to create colored, recurring events that are visually distinguished from regular notes in the calendar. The implementation extends the existing notes data model with type discrimination, color properties, and flexible recurring patterns (custom weekly/monthly intervals).
Key changes:
- Database schema extended with event-specific fields (type, color, recurringPattern, recurringInterval) and corresponding migration
- New recurring event matching logic supporting yearly, quarterly, half-yearly, monthly, and custom interval patterns
- Enhanced note editor UI with type selection (note/event), color picker, and recurring pattern configuration
- Calendar grid rendering updated to display event borders and titles inline with dates
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json, package-lock.json | Adds @radix-ui/react-radio-group dependency for type selection UI |
| messages/{de,en,it}.json | Adds translations for event-specific UI elements (type, color, recurring patterns) |
| lib/event-utils.ts | New utility module implementing recurring event date matching logic |
| lib/db/schema.ts | Extends calendarNotes table with type, color, and recurring pattern fields |
| drizzle/meta/_journal.json, drizzle/meta/0012_snapshot.json, drizzle/0012_organic_romulus.sql | Database migration files for schema changes |
| components/ui/radio-group.tsx | New shadcn/ui component for note/event type selection |
| components/note-sheet.tsx | Major refactor to support event configuration (type, color, recurring patterns) |
| components/dialog-manager.tsx | Updates onNoteSubmit signature to accept event parameters |
| components/calendar-sheet.tsx | Type signature adjustment for async callback |
| components/calendar-grid.tsx | Updates rendering logic to display event borders and titles, replaces sticky note icon with inline text |
| hooks/useNotes.ts | Extends createNote and updateNote to accept event-specific parameters |
| hooks/useNoteActions.ts | Updates submission flow to pass event parameters through |
| app/page.tsx | Integrates findEventForDate and findNoteForDate utilities, adds DialogManager to empty state |
| app/api/notes/route.ts | POST endpoint accepts and stores event parameters |
| app/api/notes/[id]/route.ts | PUT endpoint accepts and updates event parameters |
| README.md | Updates feature description to mention event support |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
app/page.tsx(9 hunks)components/calendar-grid.tsx(5 hunks)components/dialog-manager.tsx(3 hunks)components/notes-list-dialog.tsx(1 hunks)components/ui/badge.tsx(1 hunks)hooks/useDialogStates.ts(4 hunks)lib/event-utils.ts(1 hunks)messages/de.json(1 hunks)messages/en.json(1 hunks)messages/it.json(2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use English for all code, comments, and variable names
Write comments only for complex or non-obvious logic - prefer self-documenting variable names
Files:
components/ui/badge.tsxapp/page.tsxcomponents/notes-list-dialog.tsxcomponents/calendar-grid.tsxcomponents/dialog-manager.tsxhooks/useDialogStates.tslib/event-utils.ts
app/**/*.tsx
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
app/**/*.tsx: Always use existing custom hooks fromhooks/instead of implementing custom fetch logic for CRUD operations on shifts, presets, notes, and calendars
UsegetCachedPassword(),verifyAndCachePassword(),setCachedPassword(), andremoveCachedPassword()fromlib/password-cache.tsfor password handling
Always useuseDirtyStatehook for tracking unsaved changes in forms and sheets
UsePRESET_COLORSarray and store colors in hex format (#RRGGBB), applying 20% opacity for backgrounds using format${color}20
UseformatDateToLocal()utility for formatting dates to YYYY-MM-DD format in UI
UseConfirmationDialogcomponent for confirmations - never use native JavaScriptconfirm()
Support real-time updates via Server-Sent Events (SSE) - listen to relevant SSE events and use silent refresh patterns (fetchData(false)) to update without loading states
Use Tailwind CSS 4, shadcn/ui components, and gradient styling patterns: gradient backgrounds (from-primary/10 via-primary/5), border opacity (border-border/50), consistent padding (px-6 py-6), and sticky footers
Use separate mobile calendar dialog withshowMobileCalendarDialogprop for improved mobile UI/UX
Files:
app/page.tsx
messages/*.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
messages/*.json: Use next-intl for internationalization with messages inmessages/{de,en,it}.json- add new keys to all three language files
Organize translation keys inmessages/*.jsonas:common.*for CRUD operations with{item}parameter,validation.*for validation messages,form.*for reusable form labels, and feature-specific namespaces for feature keys
Files:
messages/it.jsonmessages/de.jsonmessages/en.json
hooks/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Create custom hooks in
hooks/directory for CRUD operations following existing patterns in available custom hooks
Files:
hooks/useDialogStates.ts
messages/de.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
German translations must ALWAYS use informal 'du' form, never 'Sie'
Files:
messages/de.json
🧠 Learnings (12)
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use Tailwind CSS 4, shadcn/ui components, and gradient styling patterns: gradient backgrounds (`from-primary/10 via-primary/5`), border opacity (`border-border/50`), consistent padding (`px-6 py-6`), and sticky footers
Applied to files:
components/ui/badge.tsxcomponents/calendar-grid.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/calendar*.tsx : Calendar interactions: left-click toggles shift with selected preset (delete if exists, create if not), right-click opens note dialog with prevented default context menu
Applied to files:
app/page.tsxcomponents/notes-list-dialog.tsxcomponents/calendar-grid.tsxcomponents/dialog-manager.tsxhooks/useDialogStates.tsmessages/de.jsonmessages/en.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use separate mobile calendar dialog with `showMobileCalendarDialog` prop for improved mobile UI/UX
Applied to files:
app/page.tsxcomponents/notes-list-dialog.tsxcomponents/calendar-grid.tsxcomponents/dialog-manager.tsxhooks/useDialogStates.ts
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `formatDateToLocal()` utility for formatting dates to YYYY-MM-DD format in UI
Applied to files:
app/page.tsxcomponents/calendar-grid.tsxlib/event-utils.ts
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Always use existing custom hooks from `hooks/` instead of implementing custom fetch logic for CRUD operations on shifts, presets, notes, and calendars
Applied to files:
app/page.tsxcomponents/calendar-grid.tsxcomponents/dialog-manager.tsxhooks/useDialogStates.ts
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `getCachedPassword()`, `verifyAndCachePassword()`, `setCachedPassword()`, and `removeCachedPassword()` from `lib/password-cache.ts` for password handling
Applied to files:
app/page.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `ConfirmationDialog` component for confirmations - never use native JavaScript `confirm()`
Applied to files:
components/notes-list-dialog.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/*.json : Use next-intl for internationalization with messages in `messages/{de,en,it}.json` - add new keys to all three language files
Applied to files:
messages/it.jsonmessages/de.jsonmessages/en.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*sheet*.tsx : Use `BaseSheet` component for simple forms (create, edit, settings) with gradient headers, border opacity styling, and sticky footer
Applied to files:
components/dialog-manager.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Always use `useDirtyState` hook for tracking unsaved changes in forms and sheets
Applied to files:
hooks/useDialogStates.ts
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/de.json : German translations must ALWAYS use informal 'du' form, never 'Sie'
Applied to files:
messages/de.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/*.json : Organize translation keys in `messages/*.json` as: `common.*` for CRUD operations with `{item}` parameter, `validation.*` for validation messages, `form.*` for reusable form labels, and feature-specific namespaces for feature keys
Applied to files:
messages/en.json
🧬 Code graph analysis (5)
components/ui/badge.tsx (1)
lib/utils.ts (1)
cn(4-6)
components/calendar-grid.tsx (1)
lib/event-utils.ts (1)
findNotesForDate(90-119)
components/dialog-manager.tsx (2)
lib/db/schema.ts (1)
CalendarNote(164-164)components/notes-list-dialog.tsx (1)
NotesListDialog(28-219)
hooks/useDialogStates.ts (1)
lib/db/schema.ts (1)
CalendarNote(164-164)
lib/event-utils.ts (1)
lib/db/schema.ts (1)
CalendarNote(164-164)
⏰ 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: build-dev
🔇 Additional comments (18)
components/ui/badge.tsx (1)
1-36: LGTM!The Badge component follows standard shadcn/ui patterns with proper variant support, focus states, and transition styling. The implementation is clean and consistent with the project's UI component architecture.
hooks/useDialogStates.ts (1)
1-62: LGTM!The additions properly extend the dialog state management to support the new notes list dialog. The state is correctly typed with
CalendarNote[]and follows the existing patterns in the hook.components/dialog-manager.tsx (2)
10-120: LGTM!The DialogManager API is properly extended to support the notes list dialog. The
onNoteSubmitsignature now accepts event metadata (type, color, recurring pattern/interval), and the new notes list props are well-structured for handling per-date note operations.
257-267: LGTM!The NotesListDialog is correctly rendered conditionally based on
selectedDayDateand all props are properly wired to their respective handlers. The integration follows the established dialog management pattern.components/notes-list-dialog.tsx (1)
1-219: LGTM!The NotesListDialog component is well-designed with:
- Clean separation of events and regular notes sections
- Proper use of gradient styling patterns as per guidelines
- Recurring labels displayed via Badge component
- Locale-aware date formatting
- Good UX with empty state, edit/delete actions, and Add button
- Consistent with the project's dialog component architecture
Based on learnings, this follows Tailwind CSS 4, shadcn/ui components, and gradient styling patterns.
components/calendar-grid.tsx (3)
133-143: LGTM!The note retrieval logic properly uses
findNotesForDateto gather all notes/events for each day, including recurring items. The separation into events and regular notes with count tracking enables the enhanced day-level indicators. The O(n×d) complexity (notes × days) is reasonable for calendar rendering.
171-217: LGTM!The multi-event border styling uses a creative backgroundImage gradient approach to support border-radius, since
borderImagedoesn't support it. This limitation is properly documented in the comments (lines 172-173). The implementation correctly applies:
- Gradient borders for multiple events (excluding today)
- Single-color borders for single events
- Proper styling precedence (event borders override highlight styling)
240-306: LGTM!The day header indicators are well-designed:
- Multi-entry badge shows count when multiple notes/events exist
- Single event/note displays with appropriate color styling (event color vs orange for notes)
- Clickable interaction is properly gated on
selectedPresetIdto prevent conflicts with preset toggling- Clear visual hierarchy with truncation and opacity transitions
app/page.tsx (5)
150-268: LGTM!The note submission and list handlers are well-implemented:
handleNoteSubmitproperly extended to accept event metadata (type, color, recurring pattern/interval)- Compare mode data correctly reloaded after mutations
handleEditNoteFromListsmoothly transitions from list to edit dialoghandleDeleteNoteFromListproperly updates state and closes dialog when no notes remain- All handlers maintain data consistency across normal and compare modes
511-556: LGTM!The day interaction handlers consistently use
findNotesForDateto retrieve all notes/events for a date:
- Right-click, note icon click, and long-press all follow the same pattern
- Shows notes list dialog when notes exist (threshold >= 1), allowing users to add more
- Opens direct edit dialog when no notes exist
- Properly centralizes per-date note retrieval including recurring items
784-852: LGTM!The compare mode interaction handlers properly adapt the note workflow for multi-calendar scenarios:
- Use
findNotesForDateon the specific calendar's notes- Set
compareNoteCalendarIdto track which calendar is being edited- Follow the same threshold pattern as normal mode
- Data reloading is handled by the note submission wrappers
1204-1280: LGTM!The empty state now properly renders the DialogManager, enabling calendar creation and other dialog operations even when no calendars exist. This improves UX by ensuring consistent dialog availability across all app states.
1477-1482: LGTM!All three DialogManager instances (empty state, compare mode, and main) consistently pass the new notes list dialog props. The integration is complete and ensures uniform note/event management behavior across all application modes.
lib/event-utils.ts (2)
3-59: LGTM!The
matchesRecurringEventfunction correctly implements recurring pattern logic with fixes for previously identified issues:
- Switch case declarations are now properly wrapped in blocks (lines 23-40, 42-54)
- Month-based patterns use year-aware calculation (
eventYear * 12 + eventMonth) to correctly handle year boundaries (lines 49-51)- Week-based patterns normalize dates to midnight before calculating day differences
- Both patterns verify
targetDate >= eventDatebefore checking intervalsThe implementation properly addresses all past review concerns.
61-134: LGTM!The find functions are well-designed:
findEventsForDatefilters for event-type notes with exact or recurring matchesfindNotesForDatefilters all notes with exact matches, plus recurring matches for events only (line 108)- Exact date matching properly compares year, month, and date
- Legacy wrappers provide backward compatibility by returning the first match
- Clear separation of concerns between event-specific and general note retrieval
messages/de.json (2)
121-126: LGTM! Proper use of informal 'du' form and template parameters.The updated translations correctly use the informal imperative forms ("drücke", "mache") as required by the coding guidelines. The template-based format for create/edit strings with
{item}parameter follows the proper pattern for reusable translations.
127-143: No action needed. The Italian translation file (messages/it.json) is present in the repository and already contains all the new keys required by this change. The coding guideline requirement to add new keys to all three language files (messages/{de,en,it}.json) has been satisfied.Likely an incorrect or invalid review comment.
messages/en.json (1)
121-143: LGTM! English translations are clear and consistent with German file.The English translations follow the same structure and key organization as the German file, properly using template parameters for dynamic values. The text is natural and grammatically correct.
Note: The missing Italian translations have already been flagged in the
messages/de.jsonreview.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 23 out of 24 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
app/api/notes/[id]/route.ts:144
- Similar to the POST route, the PUT route lacks validation for the type, recurringPattern, and recurringInterval fields. The type should be validated to be either "note" or "event", the recurringPattern should be validated to be one of the expected values, and recurringInterval should be validated as a positive integer when recurringPattern is custom.
// Determine the final type value
const finalType = type !== undefined ? type : existingNote.type;
const [updated] = await db
.update(calendarNotes)
.set({
note,
type: finalType,
// Clear event-specific fields when converting to note
color:
finalType === "note"
? null
: color !== undefined
? color
: existingNote.color,
recurringPattern:
finalType === "note"
? "none"
: recurringPattern !== undefined
? recurringPattern
: existingNote.recurringPattern,
recurringInterval:
finalType === "note"
? null
: recurringInterval !== undefined
? recurringInterval
: existingNote.recurringInterval,
updatedAt: new Date(),
})
.where(eq(calendarNotes.id, id))
.returning();
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
components/note-sheet.tsx (1)
357-366: Validate and clamp interval input.The interval input accepts values from 1-52 via the
maxattribute, but theonChangehandler doesn't enforce this limit. Users can type values exceeding 52 (e.g., 999), which bypasses the intended constraint.🔎 Proposed fix to clamp input value
<Input type="number" min={1} max={52} value={recurringInterval} - onChange={(e) => - setRecurringInterval(parseInt(e.target.value) || 1) - } + onChange={(e) => { + const raw = parseInt(e.target.value, 10); + if (Number.isNaN(raw)) { + setRecurringInterval(1); + return; + } + setRecurringInterval(Math.min(Math.max(raw, 1), 52)); + }} className="w-20" />
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
components/calendar-compare-sheet.tsx(2 hunks)components/calendar-compare-view.tsx(2 hunks)components/note-sheet.tsx(4 hunks)components/ui/alert.tsx(1 hunks)lib/event-utils.ts(1 hunks)messages/de.json(1 hunks)messages/en.json(1 hunks)messages/it.json(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use English for all code, comments, and variable names
Write comments only for complex or non-obvious logic - prefer self-documenting variable names
Files:
components/calendar-compare-sheet.tsxcomponents/ui/alert.tsxcomponents/calendar-compare-view.tsxcomponents/note-sheet.tsxlib/event-utils.ts
messages/*.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
messages/*.json: Use next-intl for internationalization with messages inmessages/{de,en,it}.json- add new keys to all three language files
Organize translation keys inmessages/*.jsonas:common.*for CRUD operations with{item}parameter,validation.*for validation messages,form.*for reusable form labels, and feature-specific namespaces for feature keys
Files:
messages/en.jsonmessages/de.jsonmessages/it.json
messages/de.json
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
German translations must ALWAYS use informal 'du' form, never 'Sie'
Files:
messages/de.json
🧠 Learnings (12)
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use separate mobile calendar dialog with `showMobileCalendarDialog` prop for improved mobile UI/UX
Applied to files:
components/calendar-compare-sheet.tsxcomponents/calendar-compare-view.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*sheet*.tsx : Use `BaseSheet` component for simple forms (create, edit, settings) with gradient headers, border opacity styling, and sticky footer
Applied to files:
components/calendar-compare-sheet.tsxcomponents/note-sheet.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/calendar*.tsx : Calendar interactions: left-click toggles shift with selected preset (delete if exists, create if not), right-click opens note dialog with prevented default context menu
Applied to files:
components/calendar-compare-sheet.tsxmessages/en.jsoncomponents/calendar-compare-view.tsxcomponents/note-sheet.tsxmessages/de.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use Tailwind CSS 4, shadcn/ui components, and gradient styling patterns: gradient backgrounds (`from-primary/10 via-primary/5`), border opacity (`border-border/50`), consistent padding (`px-6 py-6`), and sticky footers
Applied to files:
components/ui/alert.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `ConfirmationDialog` component for confirmations - never use native JavaScript `confirm()`
Applied to files:
components/ui/alert.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/*.json : Use next-intl for internationalization with messages in `messages/{de,en,it}.json` - add new keys to all three language files
Applied to files:
messages/en.jsonmessages/de.jsonmessages/it.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/*.json : Organize translation keys in `messages/*.json` as: `common.*` for CRUD operations with `{item}` parameter, `validation.*` for validation messages, `form.*` for reusable form labels, and feature-specific namespaces for feature keys
Applied to files:
messages/en.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Always use existing custom hooks from `hooks/` instead of implementing custom fetch logic for CRUD operations on shifts, presets, notes, and calendars
Applied to files:
components/calendar-compare-view.tsxcomponents/note-sheet.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `getCachedPassword()`, `verifyAndCachePassword()`, `setCachedPassword()`, and `removeCachedPassword()` from `lib/password-cache.ts` for password handling
Applied to files:
components/calendar-compare-view.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Always use `useDirtyState` hook for tracking unsaved changes in forms and sheets
Applied to files:
components/note-sheet.tsx
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to messages/de.json : German translations must ALWAYS use informal 'du' form, never 'Sie'
Applied to files:
messages/de.json
📚 Learning: 2025-12-20T20:00:42.991Z
Learnt from: CR
Repo: panteLx/BetterShift PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-20T20:00:42.991Z
Learning: Applies to app/**/*.tsx : Use `formatDateToLocal()` utility for formatting dates to YYYY-MM-DD format in UI
Applied to files:
lib/event-utils.ts
🧬 Code graph analysis (3)
components/calendar-compare-sheet.tsx (1)
components/ui/alert.tsx (2)
Alert(58-58)AlertDescription(58-58)
components/calendar-compare-view.tsx (1)
components/ui/alert.tsx (2)
Alert(58-58)AlertDescription(58-58)
lib/event-utils.ts (1)
lib/db/schema.ts (1)
CalendarNote(164-164)
⏰ 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: build-dev
🔇 Additional comments (12)
components/ui/alert.tsx (1)
1-58: LGTM! Standard shadcn/ui Alert component.This is a well-implemented shadcn/ui Alert component following established patterns. The variant system, accessibility attributes (role="alert"), and forwardRef pattern are all correctly applied.
lib/event-utils.ts (2)
3-70: LGTM! Recurring event matching logic is correct.The function properly handles:
- Weekly recurrence with custom intervals (accounting for day-of-week and normalized dates)
- Monthly recurrence with custom intervals (year-aware month calculation)
- Edge cases where event day doesn't exist in target month (e.g., Jan 31 → Feb 28/29)
Past review concerns about year boundaries and switch declaration scoping have been addressed.
73-145: LGTM! Date filtering functions are well-structured.The helper functions correctly filter notes/events by date, handling both exact matches and recurring patterns. The legacy wrappers maintain backward compatibility by returning the first match.
messages/it.json (1)
121-144: LGTM! Italian translations are correct.The Italian translations for the new note and event features are accurate. The past issue with Spanish words ("Notas", "Eventos") has been corrected to proper Italian ("Note", "Eventi").
messages/de.json (1)
121-144: LGTM! German translations use correct informal 'du' form.The German translations for note and event features properly use the informal 'du' form throughout (e.g., "drücke", "mache"), consistent with the project's translation guidelines.
components/calendar-compare-sheet.tsx (1)
46-53: LGTM! Consistent Alert component usage.The mobile warning has been updated to use the standardized Alert component with appropriate warning styling and iconography.
components/calendar-compare-view.tsx (1)
157-164: LGTM! Consistent Alert component usage.The mobile warning implementation matches the pattern used in calendar-compare-sheet, maintaining consistency across the codebase.
messages/en.json (1)
121-144: LGTM! English translations are well-structured.The translation keys follow the project's organization guidelines with feature-specific namespaces and reusable parameters like
{item}and{count}.components/note-sheet.tsx (4)
28-72: LGTM! Comprehensive state management for notes and events.The extended
onSubmitsignature and state management properly support the new event features (type, color, recurring patterns) while maintaining a complete initial state reference for accurate change detection.
75-144: LGTM! Initialization and change detection are thorough.The initialization effect correctly normalizes recurring patterns (e.g., "custom-weeks" → "custom" + "weeks"), and change detection properly compares all fields in the composite state.
146-170: LGTM! Save handler correctly builds recurring pattern.The save handler properly reconstructs the pattern format (e.g., "custom" + "weeks" → "custom-weeks") and conditionally passes only relevant parameters based on the note type.
239-401: LGTM! Note/event editor UI is well-structured.The UI correctly adapts based on the selected type (note vs. event), showing appropriate fields for event metadata (color picker, recurring pattern) and using contextual labels and placeholders.
Adds first-class "event" items alongside free-form notes so users can create colored, recurring events and have them displayed/styled in the calendar.
Adds type, color, recurring pattern and interval fields to the data model and API; updates hooks and responses to create/update events. Extends the note editor with type selection, color presets and custom recurring intervals, and updates calendar rendering to surface event titles and border styling. Updates translations, README copy and UI dialog handling, and adds a small UI dependency for radio controls.
Benefits: enables distinct event semantics, visual differentiation, and recurring scheduling for calendar entries, improving usability for planned events versus simple notes.
Summary by CodeRabbit
New Features
Documentation
UI Components
✏️ Tip: You can customize this high-level summary in your review settings.