Skip to content

Commit 7401538

Browse files
committed
feat(todo): add optional dueDate field with sessionStorage persistence and UI\n\n- types: add dueDate to Todo\n- storage: add serialize/parse utils and load/save with validation\n- context: load/save to sessionStorage; addTodo accepts optional dueDate\n- ui: DatePicker in TodoModal; show formatted due date and overdue styling in TodoItem\n- app: wrap with LocalizationProvider (AdapterDateFns)\n- tests: update modal and app tests; add sessionStorage tests
1 parent 16a10d4 commit 7401538

15 files changed

Lines changed: 639 additions & 66 deletions
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
Your task is to implement AIADT-39: Add Due Date field to todos, including persistence and UI updates. Follow this step-by-step plan.
2+
3+
## Objective and Non-goals
4+
5+
- Objective: Introduce an optional Due Date to the Todo model, allow users to set/edit/clear it in the modal, display it in the list, and persist the data in `sessionStorage` with validation and graceful handling of legacy/malformed data. Ensure all tests pass and coverage is at least current baseline.
6+
- Non-goals: Notifications/reminders, calendar sync, automatic sorting by due date, backend/API persistence.
7+
8+
## Architecture / Design Overview
9+
10+
- Data model: Extend `Todo` with `dueDate?: string` holding an ISO 8601 string; keep `createdAt: Date` in memory. Persist to `sessionStorage` by serializing `createdAt` to ISO string and storing `dueDate` as-is (string | undefined). Parse on load.
11+
- State management: Continue using `TodoProvider` state. Add load on mount and save on changes via storage utils.
12+
- UI: Add MUI X `DatePicker` to `TodoModal`. Display formatted due date under description in `TodoItem`. Overdue styling: show due date in `error.main` when overdue and not completed (date-only comparison).
13+
- i18n/formatting: Use `date-fns` `format(date, 'PP')` for locale-friendly rendering.
14+
- Providers: Wrap app in `LocalizationProvider` with `AdapterDateFns`.
15+
16+
## Detailed Steps (file-by-file)
17+
18+
1. Dependencies
19+
20+
- Install MUI X Date Pickers and date-fns:
21+
- `npm i @mui/x-date-pickers date-fns`
22+
- Ensure `@mui/material` is already present (it is).
23+
24+
2. Type changes
25+
26+
- Edit `src/types/Todo.ts`:
27+
- Add optional field: `dueDate?: string` (ISO 8601). Keep existing fields.
28+
29+
3. Storage utilities (new)
30+
31+
- Create `src/utils/sessionStorage.ts` with:
32+
- `const STORAGE_KEY = 'todos'`
33+
- `interface StoredTodo` where `createdAt` and `dueDate` are `string | undefined`.
34+
- `serializeTodos(todos: Todo[]): StoredTodo[]` converting `createdAt` to ISO via `toISOString()` and leaving `dueDate` as is.
35+
- `parseStoredTodos(items: StoredTodo[]): Todo[]` parsing `createdAt` back to `Date` and validating `dueDate`:
36+
- If `Number.isNaN(Date.parse(stored.dueDate))`, treat as `undefined`.
37+
- `loadTodosFromStorage(): Todo[]` with try/catch; on error return `[]`.
38+
- `saveTodosToStorage(todos: Todo[]): boolean` with try/catch; log `console.warn` on quota or other errors, return `false` if failed.
39+
- Compare dates by date-only using helper `toStartOfDay(date: Date): number` for overdue logic (export if needed by components).
40+
41+
4. Context updates
42+
43+
- Edit `src/contexts/TodoContextType.ts`:
44+
- Update `addTodo` signature to `addTodo: (title: string, description: string, dueDate?: string) => void`.
45+
- `editTodo` remains `Partial<Todo>`; will accept `dueDate` updates.
46+
47+
- Edit `src/contexts/TodoContext.tsx`:
48+
- Initialize state from storage: `const [todos, setTodos] = useState<Todo[]>(() => loadTodosFromStorage());`
49+
- `useEffect` to save on changes: `useEffect(() => { saveTodosToStorage(todos); }, [todos]);`
50+
- Update `addTodo(title, description, dueDate)` to set `dueDate` on the new todo and `createdAt: new Date()`.
51+
- Keep `editTodo` merging updates including `dueDate`.
52+
53+
5. App provider setup
54+
55+
- Edit `src/App.tsx`:
56+
- Import and wrap tree with `LocalizationProvider` from `@mui/x-date-pickers` and `AdapterDateFns` from `@mui/x-date-pickers/AdapterDateFns`.
57+
- Place `LocalizationProvider` outside `TodoProvider` (either is fine) so `DatePicker` works anywhere.
58+
59+
6. Modal UI and validation
60+
61+
- Edit `src/components/TodoModal/TodoModal.tsx`:
62+
- Expand `initialValues` to optionally include `dueDate?: string`.
63+
- Add local state `dueDate: Date | null`.
64+
- On open, initialize `dueDate` from `initialValues?.dueDate` (parse) or `null`.
65+
- Add MUI X `DatePicker` field with clearable behavior; when cleared, set `dueDate` to `null`.
66+
- On submit:
67+
- In create: call `addTodo(title.trim(), description.trim(), dueDate ? dueDate.toISOString() : undefined)`.
68+
- In edit: call `editTodo(id, { title, description, completed, dueDate: dueDate ? dueDate.toISOString() : undefined })`.
69+
- Basic validation: rely on `DatePicker` built-in validation. If it reports an error state, block submit (track an `isDateInvalid` flag from `onError`).
70+
71+
7. List item UI
72+
73+
- Edit `src/components/TodoList/TodoItem.tsx`:
74+
- Import `format` from `date-fns`.
75+
- Compute `isOverdue` by comparing date-only today vs dueDate.
76+
- Render secondary as a two-line block: description first; due date second when present using `format(new Date(todo.dueDate), 'PP')` with `sx` color `error.main` if overdue and not completed; otherwise `text.secondary`.
77+
78+
8. Tests
79+
80+
- Add a simple test utility wrapper for date pickers within affected tests or locally inline:
81+
- In tests rendering `TodoModal`, wrap with `LocalizationProvider` and `AdapterDateFns`.
82+
83+
- Update `src/__tests__/TodoModal.test.tsx`:
84+
- Wrap renders with `LocalizationProvider`.
85+
- Add a test to set a date in create mode, submit, and verify `addTodo` received ISO string for `dueDate`.
86+
- Add a test in edit mode to clear the date (if present) and verify `dueDate` becomes `undefined` in payload.
87+
88+
- Update/add `src/__tests__/TodoItem.test.tsx`:
89+
- Add a case where `dueDate` exists (future date) and assert formatted string is shown.
90+
- Add a case where `dueDate` is yesterday and `completed` is false; assert the date text is rendered (styling assertions can be minimal—presence is sufficient).
91+
92+
- Add `src/__tests__/sessionStorage.test.ts`:
93+
- Verify `save` stores ISO strings for `createdAt`/`dueDate`.
94+
- Verify `load` parses back to `Date` and treats malformed `dueDate` as `undefined`.
95+
- Verify legacy objects without `dueDate` are accepted.
96+
97+
- Update `src/__tests__/TodoContext.test.tsx` as needed:
98+
- Since `addTodo` now accepts an optional third param, existing calls continue to work.
99+
- Consider mocking storage utils to avoid flakiness and to assert `save` is called on mutating actions.
100+
101+
## Data / Schema Changes and Migrations
102+
103+
- In-memory `Todo` gains `dueDate?: string`.
104+
- Storage schema: Persisted `Todo` items include `createdAt: string` (ISO) and optional `dueDate: string`.
105+
- Migration: Loader treats missing/invalid `dueDate` as `undefined` and parses `createdAt` back to `Date`.
106+
107+
## API Contracts and External Integrations
108+
109+
- External libs: `@mui/x-date-pickers`, `date-fns`.
110+
- No backend/API changes.
111+
112+
## Feature Flags / Config
113+
114+
- None required. Overdue styling always enabled. If needed later, gate by an env var like `VITE_TODO_OVERDUE_BADGE=true`.
115+
116+
## Telemetry / Monitoring
117+
118+
- Log `console.warn` on storage save failures (e.g., quota exceeded). Keep UI silent per scope; use existing Alerts only where already present.
119+
120+
## Risks, Edge Cases, Rollback
121+
122+
- Risks:
123+
- Date parsing/format mismatch across locales—mitigated by storing ISO and using `date-fns` local formatting.
124+
- Storage quota: ensure failures do not break UI; state remains in memory for the session.
125+
- Tests may fail if `LocalizationProvider` is missing—wrap accordingly.
126+
- Edge Cases:
127+
- Malformed `dueDate` strings from storage; treat as `undefined`.
128+
- Time-zone: Compare using start-of-day for overdue logic.
129+
- Clearing the date should set `dueDate` to `undefined`.
130+
- Rollback:
131+
- Revert code changes; loader tolerates records with/without `dueDate`. Old stored data remains valid.
132+
133+
## Acceptance Criteria Mapping
134+
135+
- User can optionally pick a due date when creating a todo → DatePicker in create mode; save ISO string.
136+
- Existing todos without due date remain unaffected → Optional field and tolerant loader.
137+
- Editing a todo shows current due date and allows change/removal → Initialize from `initialValues`; clear sets `undefined`.
138+
- Due date shows in list in locale format → `format(..., 'PP')` in `TodoItem`.
139+
- Validation prevents submission of invalid dates → Rely on DatePicker and block submit on error.
140+
- Data persists and legacy data loads → Session storage utils with tolerant parsing.
141+
- All unit tests pass and coverage ≥ baseline → Updated and new tests as above.
142+
143+
## Step-by-step Edit Checklist (copy/paste ready)
144+
145+
1. Install deps
146+
147+
```bash
148+
npm i @mui/x-date-pickers date-fns
149+
```
150+
151+
2. Update types
152+
153+
- Edit `src/types/Todo.ts` to add `dueDate?: string`.
154+
155+
3. Add storage utils
156+
157+
- Create `src/utils/sessionStorage.ts` with `loadTodosFromStorage`, `saveTodosToStorage`, and helpers described above.
158+
159+
4. Wire persistence
160+
161+
- Edit `src/contexts/TodoContext.tsx` to load on init and save on `todos` change.
162+
- Update `addTodo` signature and usage to accept optional `dueDate`.
163+
164+
5. Wrap provider
165+
166+
- Edit `src/App.tsx` to wrap app with `LocalizationProvider`/`AdapterDateFns`.
167+
168+
6. Update modal
169+
170+
- Edit `src/components/TodoModal/TodoModal.tsx` to add `DatePicker`, manage `dueDate`, and send ISO string on submit.
171+
172+
7. Update list item
173+
174+
- Edit `src/components/TodoList/TodoItem.tsx` to render formatted due date and overdue styling.
175+
176+
8. Tests
177+
178+
- Update and add tests as specified (including a new `sessionStorage.test.ts`).
179+
180+
## Notes
181+
182+
- Follow project coding standards in `AI.md` and keep code clear and typed. Prefer explicit, readable code over cleverness.

package-lock.json

Lines changed: 114 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"@emotion/react": "^11.14.0",
1919
"@emotion/styled": "^11.14.1",
2020
"@mui/material": "^7.2.0",
21+
"@mui/x-date-pickers": "8.9.2",
22+
"date-fns": "4.1.0",
2123
"react": "^19.1.0",
2224
"react-dom": "^19.1.0",
2325
"uuid": "^11.1.0"

0 commit comments

Comments
 (0)