Skip to content

feat(blocks): add calendar view scheduling modes#434

Merged
Shooksie merged 2 commits intomainfrom
block-calendar-view-20260413
Apr 13, 2026
Merged

feat(blocks): add calendar view scheduling modes#434
Shooksie merged 2 commits intomainfrom
block-calendar-view-20260413

Conversation

@Shooksie
Copy link
Copy Markdown
Contributor

Summary

  • Expand CalendarView with month, week, and day scheduling views.
  • Add event creation UI plus drag-to-reschedule callbacks for CRM activity scheduling and SaaS admin workflows.
  • Update Storybook examples, docs block snippet, and registry dependencies.

Verification

  • pnpm build
  • pnpm lint
  • pnpm typecheck
  • pnpm test -- --run
  • CI=true HOME=/Users/samishukri/ao-templates/tmp-health-home bash /Users/samishukri/ao-templates/scripts/repo-health.sh design-system

Notes

  • repo-health audit reported 9 existing dependency vulnerabilities (5 moderate, 4 high); update-deps follow-up queue command was blocked by local sandbox permissions.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 13, 2026

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

Project Deployment Actions Updated (UTC)
design-system Ready Ready Preview, Comment Apr 13, 2026 9:44pm

Request Review

@Shooksie
Copy link
Copy Markdown
Contributor Author

PR Review: design-system#434 — feat(blocks): add calendar view scheduling modes

CI: All pass ✓ | Diff: +878/-268 | Verdict: Needs Changes

Great architecture overall — the component decomposition, DnD integration, and controlled/uncontrolled view state pattern are well done. A few real bugs need fixing before merge.


P1 — Fix before merge

1. Events outside 8am–7pm are invisible in week/day views
hourSlots = Array.from({ length: 12 }, (_, i) => i + 8) covers hours 8–19 only. A 7am standup or 9pm event is silently unrendered in week/day views.
Fix: Expand to Array.from({ length: 24 }, (_, i) => i) (or 7–22) with a scrollable container defaulting to business hours.

2. No end-before-start validation in create dialog
handleSubmit guards empty title but not invalid time range. When end < start, eventDuration() returns 0 and rescheduleEvent() permanently drops endDate on the next drag — silent data corruption with no user feedback.
Fix: Add if (!allDay && fromDateAndTime(dateValue, endTime) <= fromDateAndTime(dateValue, startTime)) { /* show error */ return; }

3. Date-only ISO strings off-by-one in UTC− timezones
new Date('2025-01-15') parses as UTC midnight. For US/Canada/South America users (UTC−1 to UTC−12, ~40% of global users), the event appears on Jan 14.
Fix in toDate():

return value instanceof Date ? value : new Date(
  typeof value === 'string' && !value.includes('T') ? value + 'T00:00:00' : value
);

4. fromDateAndTime() produces Invalid Date silently
Cleared/empty HTML date input → split('-').map(Number)[NaN]new Date(NaN, ...). Downstream date-fns calls throw or return garbage. Add isValid() check in handleSubmit before calling onCreate.


P2 — Important but non-blocking

5. Props race condition: useEffect([events]) overwrites optimistic local state
Any parent re-render with a new events array reference resets calendarEvents, discarding locally created/rescheduled events that haven't been persisted upstream. Gate with a isDragging/isPendingCreate ref, or document the behavior clearly.

6. Midnight-spanning events invisible in week/day view
sameDayEvents() only checks isSameDay(getEventStart(event), date). A 10pm–2am event never appears on the second day's slots.

7. Keyboard DnD accessibility gap
useDraggable correctly adds aria-roledescription and DnD live-region hooks, but only PointerSensor is registered. Keyboard-only users see the affordance announced but can't use it. Add KeyboardSensor or remove the ARIA attribute until keyboard DnD is supported.


P3 — Informational (no block)

  • Month view day-of-week headers use currentWeekDays instead of monthDays.slice(0, 7) — possible column misalignment
  • Color <select> / all-day <input> should use DS Select/Checkbox for dark mode consistency
  • hourSlots magic numbers → CALENDAR_START_HOUR = 8, CALENDAR_HOUR_COUNT = 12
  • createEventId()crypto.randomUUID() (available in all modern browsers + Node 16+) avoids SSR hydration mismatch
  • Unit tests for pure utility functions (rescheduleEvent, fromDateAndTime, sameDayEvents) would catch the timezone and duration edge cases above before they reach production

The P1s are quick fixes (30–60 min total). P2s can be follow-up issues.

- Expand hourSlots from 8–19 to full 0–23 range so early/late events
  are visible; use CALENDAR_BUSINESS_HOUR constant for all-day placement
- Add end-before-start guard in handleSubmit — shows inline error and
  blocks create when endDate <= startDate (was silently creating
  zero-duration event and permanently dropping endDate on reschedule)
- Fix toDate() UTC off-by-one: append T00:00:00 to date-only ISO strings
  so they parse in local time, not UTC midnight (Jan 15 shown as Jan 14
  in UTC- timezones)
- Add isValid() guard for empty HTML date input in handleSubmit — was
  silently passing Invalid Date to onCreate
- Bonus: scroll week/day views to business hours on mount; add
  KeyboardSensor to DnD for accessibility

Verified: pnpm build pass (ESM + CJS + DTS)
@Shooksie
Copy link
Copy Markdown
Contributor Author

Rework complete — all P1 bugs fixed

Addressed all P1 issues from review in commit 453248b:

P1 fixes:

  1. Events outside 8am–7pm invisible — Expanded hourSlots from 12 slots (8–19) to full 24-hour range (0–23). Week and day views now scroll to business hours by default via weekScrollRef/dayScrollRef + useEffect. Replaced magic number 8 with CALENDAR_BUSINESS_HOUR constant throughout.

  2. No end-before-start validation — Added guard in handleSubmit: when endDate <= startDate, surfaces an inline error message via timeError state (with role="alert") and blocks the create call. Prevents the silent data corruption on reschedule.

  3. Date-only ISO strings off-by-one in UTC− timezones — Fixed toDate() to append T00:00:00 to date-only strings before new Date() parse, ensuring local-time interpretation instead of UTC midnight.

  4. fromDateAndTime() produces Invalid Date silently — Added isValid() check in handleSubmit before calling onCreate. Empty/cleared inputs no longer reach the calendar.

P2 fix (bonus):

  • Keyboard DnD accessibility — Added KeyboardSensor to useSensors so keyboard-only users can actually drag events (previously aria-roledescription was announced but non-functional).

Verification: pnpm build passes (ESM + CJS + DTS). pnpm lint passes (0 errors).

@Shooksie Shooksie merged commit 5b47ab8 into main Apr 13, 2026
4 checks passed
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