Client UX: toast system, confirm dialogs, load-error banners, nav fix, 404 page

- New ToastProvider/useToast (self-built, no dep): success/error toasts replace
  all five alert() calls, with server error messages surfaced
- New ConfirmProvider/useConfirm promise-based dialog replaces all six
  window.confirm sites, showing what is being deleted; Escape/overlay cancels
- Dashboard + BreedingCalendar loaders use Promise.allSettled with a
  danger banner + Retry instead of silently blanking on fetch failure
- Settings load failure now surfaces a toast instead of vanishing
- Fix BreedingCalendar females list: read paginated {data} shape (was .dogs,
  so 'Start Heat Cycle' never listed any females)
- Nav links highlight on detail routes (/dogs/123, /pedigree/5)
- Catch-all 404 route with link back to Dashboard

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jason Stedwell
2026-07-06 14:55:32 -05:00
parent 31b1d903f4
commit 55d636b512
12 changed files with 338 additions and 56 deletions
+7 -2
View File
@@ -9,13 +9,18 @@ export function SettingsProvider({ children }) {
kennel_tagline: '',
})
const [loading, setLoading] = useState(true)
// Surfaced by consumers inside the ToastProvider (this provider sits above it)
const [loadError, setLoadError] = useState(false)
useEffect(() => {
axios.get('/api/settings')
.then(res => {
setSettings(prev => ({ ...prev, ...res.data }))
})
.catch(() => {})
.catch((err) => {
console.error('Failed to load settings:', err)
setLoadError(true)
})
.finally(() => setLoading(false))
}, [])
@@ -25,7 +30,7 @@ export function SettingsProvider({ children }) {
}
return (
<SettingsContext.Provider value={{ settings, saveSettings, loading }}>
<SettingsContext.Provider value={{ settings, saveSettings, loading, loadError }}>
{children}
</SettingsContext.Provider>
)