Add sync error logging, extend error flash, fix unload saves

- Log workforce sync errors to backend stdout so they appear in docker logs
- Extend error flash from 5s to 15s so errors are readable
- Replace sendBeacon (POST-only) with keepalive fetch (PUT) on unload —
  sendBeacon was hitting 404s on all three unload saves

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-22 14:19:38 +00:00
parent c7066521ff
commit 18e24efbeb
14485 changed files with 1836116 additions and 33 deletions

View file

@ -157,7 +157,7 @@ export function Planner() {
function flash(text: string, err = false) {
if (saveMsgTimer.current) clearTimeout(saveMsgTimer.current)
setSaveMsg({ text, err })
saveMsgTimer.current = setTimeout(() => setSaveMsg(null), err ? 5000 : 2500)
saveMsgTimer.current = setTimeout(() => setSaveMsg(null), err ? 15000 : 2500)
}
function stampLastReviewed() {
@ -212,18 +212,19 @@ export function Planner() {
}
}, [wfShifts])
// Beacon save on unload
// Keepalive save on unload (sendBeacon only supports POST but routes are PUT)
useEffect(() => {
function keepalivePut(path: string, body: unknown) {
fetch(path, {
method: 'PUT', keepalive: true, credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
}
function onUnload() {
if (staff.length) {
navigator.sendBeacon('/hk-planner/api/config/staff', JSON.stringify({ staff_data: staff }))
}
if (Object.keys(pickup).length) {
navigator.sendBeacon('/hk-planner/api/config/pickup', JSON.stringify({ pickup_data: pickup }))
}
if (adjustments.length) {
navigator.sendBeacon('/hk-planner/api/config/adjustments', JSON.stringify({ adjustments }))
}
if (staff.length) keepalivePut('/hk-planner/api/config/staff', { staff_data: staff })
if (Object.keys(pickup).length) keepalivePut('/hk-planner/api/config/pickup', { pickup_data: pickup })
if (adjustments.length) keepalivePut('/hk-planner/api/config/adjustments', { adjustments })
}
window.addEventListener('beforeunload', onUnload)
return () => window.removeEventListener('beforeunload', onUnload)