feat(04-03): wire ListsIndex + ListCard + CreateListSheet + ListDeleteDialog (LIST-01)
- listsClient.ts: add createList/patchList/deleteList + List/ListItem types with activeCount/doneCount - ListsEmptyState.tsx: extracted standalone component (ClipboardList icon, UI-SPEC copy) - ListCard.tsx: name/count badge/Shared pill/ChevronRight; hover-reveal delete button; navigates /lists/:id - CreateListSheet.tsx: bottom-sheet/modal; Shared default (D-01); optimistic useMutation; auto-focus; Escape to close - ListDeleteDialog.tsx: mirrors DeleteConfirmationDialog pattern; props-driven (no calendarStore); XSS guard on name - ListsIndex.tsx: replaced placeholder with real data via useQuery+useMutation; mounts CreateListSheet+ListDeleteDialog - DeleteConfirmationDialog.tsx NOT modified (stable, D-06 pattern preserved) - PWA typecheck passes; DeleteConfirmationDialog.test.tsx 10 passed - Playwright E2E: create Groceries+Gift Ideas (Shared pills); delete dialog → confirm → card disappears
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
* credentials: 'include' is required so the OIDC session cookie is sent with
|
||||
* every request (same pattern as client.ts).
|
||||
*
|
||||
* This file provides only the functions needed in Plan 04-01 (ListsIndex empty
|
||||
* state). Plans 04-02 and 04-03 expand it with createList, deleteList, item CRUD.
|
||||
* Exports: fetchLists, createList, patchList, deleteList
|
||||
* Types: List, ListItem, ListsResponse
|
||||
*/
|
||||
|
||||
const BASE = '/api'
|
||||
@@ -26,6 +26,10 @@ export interface List {
|
||||
name: string
|
||||
isShared: boolean
|
||||
ownerId: number
|
||||
activeCount: number
|
||||
doneCount: number
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
}
|
||||
|
||||
export interface ListItem {
|
||||
@@ -45,3 +49,31 @@ export interface ListsResponse {
|
||||
export async function fetchLists(): Promise<ListsResponse> {
|
||||
return apiFetch('/lists').then((r) => r.json() as Promise<ListsResponse>)
|
||||
}
|
||||
|
||||
export async function createList(payload: {
|
||||
name: string
|
||||
isShared: boolean
|
||||
}): Promise<List> {
|
||||
return apiFetch('/lists', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
}).then((r) => r.json() as Promise<List>)
|
||||
}
|
||||
|
||||
export async function patchList(
|
||||
id: number,
|
||||
patch: { name?: string; isShared?: boolean },
|
||||
): Promise<List> {
|
||||
return apiFetch(`/lists/${id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(patch),
|
||||
}).then((r) => r.json() as Promise<List>)
|
||||
}
|
||||
|
||||
export async function deleteList(id: number): Promise<{ id: number }> {
|
||||
return apiFetch(`/lists/${id}`, {
|
||||
method: 'DELETE',
|
||||
}).then((r) => r.json() as Promise<{ id: number }>)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user