Files
suaveplan/openspec/changes/enterprise-react-calendar/tasks.md
2026-05-27 23:29:53 +01:00

4.1 KiB

Tasks: enterprise-react-calendar

Change ID: enterprise-react-calendar Package: @suaveplan/react-calendar Target path: react/forms/react-calendar Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/events, @suaveplan/datetime, @suaveplan/react-translate


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree per proposal layout.
  • Write package.json at 0.1.0 with "sideEffects": false, exports map.
  • Dependencies: @suaveplan/error workspace:^, @suaveplan/events workspace:^, @suaveplan/datetime workspace:^, @suaveplan/react-translate workspace:^, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build.
  • Write tsconfig.json, vitest.config.ts, scripts.

2. Error codes and types

  • Define CalendarError extending SuaveplanError; codes: CALENDAR_INVALID_EVENT, CALENDAR_VIEW_NOT_SUPPORTED.
  • Define all types in src/types/calendar.types.ts: CalendarView, CalendarEvent, CalendarEventMap, CalendarConfig, CalendarProps, CalendarViewProps, CalendarHeaderProps, DateRange, NavigationDirection, UseCalendarReturn.
  • Write CalendarEventSchema Zod schema.

3. Hook — useCalendar

  • State: view: CalendarView, currentDate: Date, events: Map<string, CalendarEvent[]> (keyed by yyyy-MM-dd).
  • Date math via @suaveplan/datetime addDuration, startOf, endOf; optional timeZone in config.
  • Exposes: navigate(direction: NavigationDirection), setView(view), addEvent(event), removeEvent(id), updateEvent(id, partial), getEventsForDate(date), getEventsForRange(start, end), visibleRange: DateRange.
  • Emits @suaveplan/events events: event:added, event:removed, event:updated, view:changed, navigation — uses @suaveplan/events EventBus.
  • OTel calendar.navigate span on navigate().
  • Write use-calendar.test.tsx (≤500 lines): navigate months/weeks/days, add/remove/update events, getEventsForDate O(1) verified, timeZone option. { timeout: 10000 }.
  • Write use-calendar.md.

4. Components

CalendarHeader

  • Prev/Next/Today buttons + view switcher. useTranslation for all copy.
  • Write test, stories (all-navigations, view-switching), md.

CalendarMonthView

  • 6-week grid; renders CalendarEvent chips per day cell; handles overflow with "+N more".
  • Write test, stories (default, with-events, empty), md.

CalendarWeekView

  • 7-column time grid; positions events by start/end time.
  • Write test, stories, md.

CalendarDayView

  • Single-day time grid.
  • Write test, stories, md.

CalendarAgendaView

  • List of upcoming events grouped by date.
  • Write test, stories, md.

Calendar

  • Composes Header + active view; controlled/uncontrolled; "use client" at entry.
  • Write test, stories (month, week, day, agenda, with-events, empty, playground), md.

5. E2E

  • e2e/calendar.spec.ts — Playwright:
    • Click "Next" in month view, verify date header advances by 1 month.
    • Add event programmatically, verify chip appears in correct day cell.
    • Switch to week view, verify current week shown.

6. Verify and publish

  • bunx turbo lint typecheck test --filter=@suaveplan/react-calendar — green.
  • bunx turbo test:coverage --filter=@suaveplan/react-calendar — 100%.
  • bun scripts/publish.ts --package @suaveplan/react-calendar.
  • Archive change folder.