- App.tsx: BrowserRouter with /calendar, /lists, /lists/:listId routes; / redirects to /calendar - BottomTabBar.tsx: fixed-bottom 56px tab bar with Calendar + Lists NavLinks, active accent - AppNav.tsx: add Calendar/Lists NavLinks to desktop sidebar (≥768px) - ListsIndex.tsx: full-height surface with isLoading/isError/empty state branches; "+ New List" FAB placeholder - ListDetail.tsx: placeholder stub for /lists/:listId (Plan 04-04 fills in) - listsStore.ts: Zustand UI-only store (activeTab, createListSheetOpen) - listsClient.ts: fetchLists + List/ListItem types (initial; Plans 04-02/03 expand) - Fix Wave-0 RED stubs: add vitest imports so stubs execute (todo) not error on import - Fix CalendarShell.test.tsx: wrap renderWithClient in MemoryRouter (AppNav uses NavLink)
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
/**
|
|
* Typed API client for the FamilySync lists API.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
const BASE = '/api'
|
|
|
|
async function apiFetch(path: string, init?: RequestInit): Promise<Response> {
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
credentials: 'include',
|
|
...init,
|
|
})
|
|
if (!res.ok) throw new Error(`${init?.method ?? 'GET'} ${path} failed: ${res.status}`)
|
|
return res
|
|
}
|
|
|
|
// ── Types ──────────────────────────────────────────────────────────────────
|
|
|
|
export interface List {
|
|
id: number
|
|
name: string
|
|
isShared: boolean
|
|
ownerId: number
|
|
}
|
|
|
|
export interface ListItem {
|
|
id: number
|
|
listId: number
|
|
text: string
|
|
checked: boolean
|
|
rank: string
|
|
}
|
|
|
|
export interface ListsResponse {
|
|
lists: List[]
|
|
}
|
|
|
|
// ── Functions ──────────────────────────────────────────────────────────────
|
|
|
|
export async function fetchLists(): Promise<ListsResponse> {
|
|
return apiFetch('/lists').then((r) => r.json() as Promise<ListsResponse>)
|
|
}
|