Skip to content

Conversation

@domhhv
Copy link
Owner

@domhhv domhhv commented Jan 29, 2026

Summary by CodeRabbit

Release Notes

  • New Features
    • Added Day Calendar view with an hourly timeline (0–23) displaying occurrences grouped by habit and hour, including DST support.
    • Added navigation buttons in Month and Week calendar views to directly access the day view.
    • Day view includes a persistent date picker sidebar, day notes management, and daily habit summaries.

✏️ Tip: You can customize this high-level summary in your review settings.

@domhhv domhhv self-assigned this Jan 29, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new day calendar view feature that displays an hourly timeline with DST handling, date-picker sidebar, and occurrence/note management. It includes the new DayCalendar component, supporting page and routing, a shared useCurrentTime hook, and navigation buttons in existing month/week calendar views to link to the day view.

Changes

Cohort / File(s) Summary
Day View Feature
src/components/calendar/DayCalendar.tsx, src/pages/DayCalendarPage.tsx, src/App.tsx
Introduces DayCalendar component with hourly timeline (0–23), DST handling (skipped/duplicated hours), per-hour occurrence grouping, day-note management, date-picker sidebar, and responsive mobile top bar. New route /calendar/day/:year?/:month?/:day? added to routing. URL parameters sync with focused date using time zone-aware defaults.
Navigation Updates
src/components/calendar/MonthCalendarCell.tsx, src/components/calendar/WeekCalendar.tsx
Adds "Open day" button in month cell header and week day column headers, linking to day view via react-router Link. MonthCalendarCell button is desktop-only; WeekCalendar button visible on all breakpoints.
Shared Hook
src/hooks/use-current-time.ts
New useCurrentTime React custom hook that initializes state with current Date, updates every 60 seconds, and cleans up interval on unmount.
Barrel Exports
src/components/calendar/index.ts, src/pages/index.ts, src/hooks/index.ts, src/components/calendar/WeekCalendar.tsx
Exports CalendarNavigationButtons and DayCalendar from calendar barrel; exports DayCalendarPage from pages barrel; re-exports useCurrentTime from hooks barrel. WeekCalendar switches from local useCurrentTime hook to importing shared hook.

Sequence Diagram

sequenceDiagram
    actor User
    participant Calendar as Day Calendar UI
    participant DatePicker as Date Picker<br/>(Sidebar)
    participant Timeline as Hourly Timeline
    participant Drawer as Note/Occurrence<br/>Drawer

    User->>Calendar: Navigate to /calendar/day/:year/:month/:day
    Calendar->>DatePicker: Sync focusedDate from URL (or use today)
    Calendar->>Timeline: Fetch occurrences & notes for focused date
    Calendar->>Timeline: Compute DST type & transition hour
    Calendar->>Timeline: Group occurrences by hour & habit
    Timeline->>Timeline: Mark skipped/duplicated hours (if DST)
    Calendar->>Timeline: Render hourly slots (0-23) with occurrences
    User->>DatePicker: Select different date
    DatePicker->>Calendar: Update focusedDate & URL params
    Calendar->>Timeline: Refresh occurrences for new date
    User->>Timeline: Click "Add note" or "Log occurrence"
    Timeline->>Drawer: Open note/occurrence drawer
    User->>Drawer: Create/edit entry
    Drawer->>Calendar: Save & refresh display
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 A hoppy day awaits,
Hour by hour in rabbit sight,
DST transitions we celebrate,
Sidebar hopping, timeline bright!
Day by day, the calendar sings, 🗓️✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the primary change: adding a new day mode to the calendar component with dedicated page, routing, and UI integration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

@relativeci
Copy link

relativeci bot commented Jan 29, 2026

#190 Bundle Size — 1.84MiB (+0.53%).

5d9e68e(current) vs ef0520a main#189(baseline)

Warning

Bundle contains 2 duplicate packages – View duplicate packages

Bundle metrics  Change 3 changes Regression 1 regression
                 Current
#190
     Baseline
#189
Regression  Initial JS 1.09MiB(+0.72%) 1.08MiB
No change  Initial CSS 0B 0B
Change  Cache Invalidation 100% 87.06%
No change  Chunks 8 8
No change  Assets 9 9
Change  Modules 6676(+0.04%) 6673
No change  Duplicate Modules 0 0
No change  Duplicate Code 0% 0%
No change  Packages 223 223
No change  Duplicate Packages 2 2
Bundle size by type  Change 2 changes Regression 2 regressions
                 Current
#190
     Baseline
#189
Regression  JS 1.6MiB (+0.58%) 1.59MiB
Regression  CSS 242.75KiB (+0.22%) 242.22KiB

Bundle analysis reportBranch feat/day-calendarProject dashboard


Generated by RelativeCIDocumentationReport issue

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

🤖 Fix all issues with AI agents
In `@src/components/calendar/DayCalendar.tsx`:
- Around line 67-71: Validate the URL params before constructing CalendarDate:
ensure year, month, day (the route params used to create paramsDate) are numeric
and within valid ranges (e.g., month 1–12, day 1–31 or use a month/day check) or
wrap the new CalendarDate(Number(year), Number(month), Number(day)) call in a
try-catch; on invalid input or exception, fall back to a safe value (e.g.,
today's date) or redirect to a canonical calendar route and log/handle the error
so CalendarDate construction in DayCalendar.tsx cannot throw for malformed
params.
🧹 Nitpick comments (2)
src/components/calendar/DayCalendar.tsx (1)

58-76: Potential infinite loop risk in URL parameter sync effect.

Including focusedDate in the dependency array while also calling setFocusedDate inside the effect can cause unnecessary re-renders. When focusedDate updates, the effect runs again, even though the params haven't changed.

Consider removing focusedDate from the dependency array and using a ref or comparing only param values:

♻️ Suggested refactor
   React.useEffect(() => {
     const currentDay = today(timeZone);

     const {
       day = currentDay.day,
       month = currentDay.month,
       year = currentDay.year,
     } = params;

     const paramsDate = new CalendarDate(
       Number(year),
       Number(month),
       Number(day)
     );

-    if (focusedDate.toString() !== paramsDate.toString()) {
-      setFocusedDate(toCalendarDate(paramsDate));
-    }
-  }, [params, timeZone, focusedDate]);
+    setFocusedDate((prev) => {
+      if (prev.toString() !== paramsDate.toString()) {
+        return toCalendarDate(paramsDate);
+      }
+      return prev;
+    });
+  }, [params, timeZone]);
src/hooks/use-current-time.ts (1)

8-16: Consider synchronizing the interval with clock minutes.

The current implementation starts the 60-second interval immediately on mount, which means the time could be up to 59 seconds out of sync if the component mounts mid-minute. For a current-time indicator, this might cause the indicator to appear misaligned briefly.

♻️ Optional: Sync to minute boundary
   React.useEffect(() => {
+    // Update immediately at next minute boundary, then every 60s
+    const msUntilNextMinute = (60 - new Date().getSeconds()) * 1000;
+    const timeout = setTimeout(() => {
+      setNow(new Date());
+      // Then set up the regular interval
+    }, msUntilNextMinute);
+
     const interval = setInterval(() => {
       setNow(new Date());
     }, 60_000);

     return () => {
+      clearTimeout(timeout);
       clearInterval(interval);
     };
   }, []);

This is a minor UX enhancement and can be deferred if not needed.

Comment on lines +67 to +71
const paramsDate = new CalendarDate(
Number(year),
Number(month),
Number(day)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider validating URL parameters before constructing CalendarDate.

If a user manually enters invalid URL parameters (e.g., /calendar/day/2026/13/45), the CalendarDate constructor may throw an error. Adding basic validation or a try-catch would improve robustness.

🛡️ Suggested defensive handling
+    try {
       const paramsDate = new CalendarDate(
         Number(year),
         Number(month),
         Number(day)
       );
+      setFocusedDate((prev) => {
+        if (prev.toString() !== paramsDate.toString()) {
+          return toCalendarDate(paramsDate);
+        }
+        return prev;
+      });
+    } catch {
+      // Invalid date params, keep current date
+    }
🤖 Prompt for AI Agents
In `@src/components/calendar/DayCalendar.tsx` around lines 67 - 71, Validate the
URL params before constructing CalendarDate: ensure year, month, day (the route
params used to create paramsDate) are numeric and within valid ranges (e.g.,
month 1–12, day 1–31 or use a month/day check) or wrap the new
CalendarDate(Number(year), Number(month), Number(day)) call in a try-catch; on
invalid input or exception, fall back to a safe value (e.g., today's date) or
redirect to a canonical calendar route and log/handle the error so CalendarDate
construction in DayCalendar.tsx cannot throw for malformed params.

@domhhv domhhv merged commit f670eb7 into main Jan 29, 2026
11 checks passed
@domhhv domhhv deleted the feat/day-calendar branch January 29, 2026 20:42
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.

2 participants