Description
Users working on invoice drafts in areas with intermittent connectivity lose all their work when the connection drops and a form submission fails. This issue implements comprehensive offline draft auto-save using IndexedDB (via idb) that persists the full form state every 5 seconds while the user types, detects network availability changes, queues pending saves, and on reconnection uploads the draft to the server. A recovery banner on page load alerts users when an unsaved local draft exists and offers to restore it.
Technical Context
Create hooks/useOfflineDraftAutosave.ts that uses idb to open an invoiceDrafts object store. The hook serialises the current react-hook-form watch() state every 5 seconds via setInterval and writes it to IndexedDB under the key draft-[userId]-[draftId]. Monitor network status via window.addEventListener('online'|'offline'). When online, flush pending drafts to POST /api/invoices/drafts and clear the IndexedDB entry on success. On /invoice/new mount, check for existing local drafts and render components/invoice/DraftRecoveryBanner.tsx with "Restore Draft" and "Discard" options. Restoring calls form.reset() with the recovered data. Multiple draft tabs (same user, different invoices) must coexist in IndexedDB without collision using UUID-based draft keys.
Acceptance Criteria
Description
Users working on invoice drafts in areas with intermittent connectivity lose all their work when the connection drops and a form submission fails. This issue implements comprehensive offline draft auto-save using IndexedDB (via
idb) that persists the full form state every 5 seconds while the user types, detects network availability changes, queues pending saves, and on reconnection uploads the draft to the server. A recovery banner on page load alerts users when an unsaved local draft exists and offers to restore it.Technical Context
Create
hooks/useOfflineDraftAutosave.tsthat usesidbto open aninvoiceDraftsobject store. The hook serialises the currentreact-hook-formwatch()state every 5 seconds viasetIntervaland writes it to IndexedDB under the keydraft-[userId]-[draftId]. Monitor network status viawindow.addEventListener('online'|'offline'). When online, flush pending drafts toPOST /api/invoices/draftsand clear the IndexedDB entry on success. On/invoice/newmount, check for existing local drafts and rendercomponents/invoice/DraftRecoveryBanner.tsxwith "Restore Draft" and "Discard" options. Restoring callsform.reset()with the recovered data. Multiple draft tabs (same user, different invoices) must coexist in IndexedDB without collision using UUID-based draft keys.Acceptance Criteria