update api
This commit is contained in:
64
docs/migration-tanstack-query.md
Normal file
64
docs/migration-tanstack-query.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Migration path: `useApi` → TanStack Query
|
||||
|
||||
The current data layer is intentionally dependency-free: a thin `useApi` hook over plain
|
||||
service functions, with a mock-adapter flip in `http.js`. This is enough for the foundation,
|
||||
but as the number of integrated screens grows we'll want request deduplication, caching,
|
||||
background refetch, and mutation state. [TanStack Query](https://tanstack.com/query) is the
|
||||
intended destination. This document records how to get there without a rewrite.
|
||||
|
||||
## What stays (the important part)
|
||||
|
||||
Nothing in `src/services/*` changes. The service functions (`getDashboard`, `getBookings`,
|
||||
`assignMiler`, …) are already framework-agnostic `() => Promise<T>` calls that branch
|
||||
mock/real inside `http.js`. TanStack Query wraps these — it does not replace them. The DTO
|
||||
typedefs in `services/dto.js` remain the contract.
|
||||
|
||||
## What changes
|
||||
|
||||
`hooks/useApi.js` is the only abstraction that maps onto Query. Today:
|
||||
|
||||
```js
|
||||
const { data, loading, error, refetch } = useApi(getDashboard, [], { refreshMs: 30000 });
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```js
|
||||
const { data, isLoading: loading, error, refetch } = useQuery({
|
||||
queryKey: ['admin', 'dashboard'],
|
||||
queryFn: getDashboard,
|
||||
refetchInterval: 30000,
|
||||
});
|
||||
```
|
||||
|
||||
`AsyncBoundary` keeps working unchanged — it only consumes `{ loading, error, onRetry }`.
|
||||
|
||||
### Recommended sequencing
|
||||
|
||||
1. Add deps: `@tanstack/react-query` (+ devtools). Wrap the app in `<QueryClientProvider>` in
|
||||
`main.jsx`, just inside `AuthProvider`.
|
||||
2. **Shim, don't sweep.** Re-implement `useApi` internally with `useQuery`, deriving a stable
|
||||
`queryKey` from the fetcher + deps. Every existing page keeps calling `useApi` and instantly
|
||||
gains caching/dedup. This is the lowest-risk step and can ship on its own.
|
||||
3. Migrate page-by-page from the `useApi` shim to direct `useQuery` calls with explicit
|
||||
`queryKey`s (needed for cache invalidation and cross-screen sharing).
|
||||
4. Convert writes (`assignMiler`, `assignVehicle`, `updateBookingStatus`) to `useMutation`
|
||||
with `onSuccess: () => queryClient.invalidateQueries(...)`, replacing the current
|
||||
OpsStore optimistic-overlay pattern where a real backend now persists the change.
|
||||
5. Replace the `realtime.js` polling placeholder with a WebSocket/SSE source that calls
|
||||
`queryClient.setQueryData(...)` on each message — Query becomes the single cache the socket
|
||||
pushes into.
|
||||
|
||||
## Query key conventions (when we get there)
|
||||
|
||||
| Data | Key |
|
||||
| --- | --- |
|
||||
| Dashboard | `['admin','dashboard']` |
|
||||
| Bookings list | `['admin','bookings', filters]` |
|
||||
| Booking detail | `['admin','bookings', id]` |
|
||||
| Milers | `['admin','milers']` |
|
||||
| Consignments | `['admin','consignments']` |
|
||||
| Health | `['health']` |
|
||||
|
||||
Keeping keys hierarchical lets a mutation invalidate `['admin','bookings']` and refresh both
|
||||
the list and any open detail view.
|
||||
Reference in New Issue
Block a user