feat(06-05): global session-expiry interstitial via QueryCache/MutationCache onError

- Add sessionExpired boolean + setSessionExpired action to Zustand calendarStore
- main.tsx: construct QueryClient with QueryCache+MutationCache onError (v5 pattern, not defaultOptions.onError)
- onGlobalError: checks instanceof SessionExpiredError, calls setSessionExpired(true) via store.getState()
- CalendarShell: read sessionExpired from store; render AuthSplash(state=redirecting, 'Session expired', 'Signing you back in…')
- CalendarShell: useEffect fires clearLoginRedirect + maybeRedirectToLogin after 1.5s when sessionExpired (one-shot guard re-armed)
- Context7 /tanstack/query confirmed v5 QueryCache/MutationCache constructor + onError signature
This commit is contained in:
Lucas Berger
2026-06-10 11:32:45 -04:00
parent e7b34a5ce2
commit 139ef00ed4
3 changed files with 79 additions and 2 deletions
+22 -1
View File
@@ -10,11 +10,32 @@ import './styles/index.css'
import React from 'react'
import ReactDOM from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { QueryClient, QueryClientProvider, QueryCache, MutationCache } from '@tanstack/react-query'
import App from './App.js'
import { ErrorBoundary } from './components/ErrorBoundary.js'
import { SessionExpiredError } from './api/client.js'
import { useCalendarStore } from './store/calendarStore.js'
/**
* Global session-expiry error handler (D-11, Plan 06-05).
*
* When any query or mutation throws a SessionExpiredError, arm the interstitial
* via the Zustand store's imperative getter — safe to call outside React since
* Zustand's create() returns a store with a .getState() API.
*
* QueryCache and MutationCache onError callbacks are the correct v5 pattern for
* global error handling (NOT defaultOptions.onError, which was removed in v5).
* Confirmed via Context7 /tanstack/query docs for v5.101.0.
*/
function onGlobalError(error: unknown): void {
if (error instanceof SessionExpiredError) {
useCalendarStore.getState().setSessionExpired(true)
}
}
const queryClient = new QueryClient({
queryCache: new QueryCache({ onError: onGlobalError }),
mutationCache: new MutationCache({ onError: onGlobalError }),
defaultOptions: {
queries: {
retry: 1,