Files
udyamlinc/public/sw.js
T
LincPayandClaude Opus 5 13c628fa4b feat(pwa): actually send the offline queue, and sync when the radio returns
syncPending() flipped entries from PENDING to SYNCED without sending
anything. The offline half of the promise worked — the owner could record a
sale with no signal and never saw a spinner — but the entry stopped at
localStorage and the lender never saw it.

It now posts to /app/ledger/sync and marks only the entries the server
accepted. It re-reads storage before writing rather than reusing the snapshot,
because the owner may have tapped save again while the request was in flight
and that entry must stay PENDING. A failure is deliberately silent: the
entries stay queued and go again next time, because from the owner's side
nothing has gone wrong, and losing a tap is the one failure this app cannot
have.

useAutoSync() drains the queue on the browser's `online` event and once on
mount — the app is commonly opened after connectivity returns rather than
while it is returning, in which case no online event ever fires.

The consent toggle now writes to the server instead of holding local state,
and the alerts screen renders the borrower's real reason codes from
/app/reasons. Where the request succeeds with nothing on record it says so;
inventing three sentences on the borrower's own screen would be a lie about
the one thing they are entitled to see.

Also fixes a month label that rendered blank on every live forecast point: a
${p.month} interpolation had been eaten by an earlier edit, so the strip only
displayed correctly when the API was unreachable and the demo generator took
over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 13:45:34 +05:30

55 lines
1.7 KiB
JavaScript

/*
* UdyamLinc service worker — app-shell precache + stale-while-revalidate.
*
* Scope of the offline promise (deck feature 7): the enterprise PWA must open,
* render and accept ledger entries with zero connectivity. Ledger writes are
* queued in localStorage by the app itself (see lib/ledgerStore.ts); this worker
* only guarantees the shell and its assets are reachable.
*/
const CACHE = 'udyamlinc-v2'
const SHELL = ['/', '/app', '/index.html', '/manifest.webmanifest', '/udyamlinc-tile.svg']
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(CACHE).then((c) => c.addAll(SHELL)).then(() => self.skipWaiting()))
})
self.addEventListener('activate', (event) => {
event.waitUntil(
caches
.keys()
.then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
.then(() => self.clients.claim()),
)
})
self.addEventListener('fetch', (event) => {
const req = event.request
if (req.method !== 'GET') return
const url = new URL(req.url)
// API calls are never served stale — the app falls back to its local store instead.
if (url.pathname.includes('/api/')) return
// Navigations: network first, fall back to the cached shell when offline.
if (req.mode === 'navigate') {
event.respondWith(fetch(req).catch(() => caches.match('/index.html')))
return
}
// Assets: cache first, refresh in the background.
event.respondWith(
caches.match(req).then((hit) => {
const network = fetch(req)
.then((res) => {
if (res.ok) {
const copy = res.clone()
caches.open(CACHE).then((c) => c.put(req, copy))
}
return res
})
.catch(() => hit)
return hit || network
}),
)
})