Commit Graph

7 Commits

Author SHA1 Message Date
jubnl 2ae4a18466 fix: decouple IDB writes from network-data return path
QuotaExceededError from a full IndexedDB was being caught by the IIFE's
try/catch (after the earlier await-upsert change), causing repos to return
null/empty even when the network fetch succeeded. Fire-and-forget upserts
with .catch(()=>{}) ensure write failures never suppress fetched data.
2026-05-05 19:19:48 +02:00
jubnl f8fdb14627 fix: remove navigator.onLine guards and fix upsert races in all repos
navigator.onLine returns false transiently during service worker activation
(skipWaiting + clientsClaim), causing all repo refresh IIFEs to return null
immediately on first page load — leaving the UI with empty data until F5.

Fixes applied across all list repos (trip, day, place, packing, todo, budget,
reservation, accommodation, file):
- Drop navigator.onLine guard; let fetch fail naturally when truly offline
- Await all upsert calls (some were fire-and-forget, risking race conditions
  against subsequent reads and silent swallowed failures)
- Return Promise.resolve(null) instead of Promise.resolve(fresh) in the
  IDB-empty network path, so loadTrip's background refresh Promise.all
  resolves null and skips set({trip}), preventing a spurious reference change
  that was resetting the 1500ms splash timer

Tests updated: placeRepo and packingRepo "empty cache" tests now simulate
genuine network failure (HttpResponse.error) instead of relying on the
navigator.onLine guard that no longer exists; DashboardPage tests clear IDB
before each test and use a query-safe assertion after background refresh.
2026-05-05 18:04:15 +02:00
jubnl 69620e7276 feat: always-optimistic write pattern across all repos
All create/update/delete repo methods now write to IndexedDB optimistically
and fire mutationQueue.flush() as fire-and-forget, returning immediately
without waiting for the network. This eliminates the 8-second UX freeze
previously seen when the API was unreachable but navigator.onLine was true.

- Repos rewritten: trip, day, place, packing, todo, budget, accommodation,
  reservation, file — write methods never throw, always return optimistic data
- mutationQueue.flush() changed to iterative (one item per loop iteration)
  so mutations enqueued mid-flush (e.g. bulk check-all) are picked up
- fileRepo.toggleStar skips the IDB put when the file is not cached locally
- DayDetailPanel passes place_name into accommodationRepo.create so the
  optimistic accommodation renders the correct hotel label immediately
- Test suite updated throughout to reflect optimistic-first semantics:
  no more rollback assertions, IDB cleared in component test beforeEach hooks,
  FileManager tests switched from filesApi spy to MSW endpoint assertions
2026-05-05 02:14:39 +02:00
jubnl 3aa6b0952a fix: repair test suite after SWR offline-read changes
Add navigator.onLine guard to SWR refresh IIFEs so background
network calls don't fire in offline mode (prevents fake-IDB leakage
in tests via MSW default handlers).

Fix IDB isolation in affected test files by flushing pending macro
tasks then clearing IDB tables in beforeEach, so stale IDB writes
from previous tests' background IIFEs don't bleed into the next test.

Restore loadBudgetItems and refreshPlaces to apply background refresh
results to store state.

Move tags/categories API calls before the main Promise.all in
loadTrip so MSW handlers resolve during the await window.
2026-05-05 01:01:34 +02:00
jubnl a83b369cb7 fix: stale-while-revalidate for offline reads + axios timeout
navigator.onLine is unreliable on Android — returns true whenever any
network interface is up, regardless of actual reachability. This caused
all repo reads to take the API branch and either wait 5 s for the SW
NetworkFirst timeout (cache hit) or hang indefinitely (cache miss).

- All read repos (list/get) now return cached IndexedDB data instantly
  and carry a background refresh promise that resolves to fresh data or
  null on failure. Callers that opted in (loadTrip, loadTrips) apply
  fresh data silently when it arrives.
- tripStore.loadTrip: Promise.all now reads all 7 resources from
  IndexedDB (instant), fires network refreshes in background, sets
  isLoading: false immediately, then applies fresh data via a second
  Promise.all when ready. Tags/categories use upsertTags/upsertCategories.
- DashboardPage.loadTrips: same pattern — renders from cache instantly,
  silently updates trip list on refresh.
- axios timeout set to 8 s so requests can never hang indefinitely.
- SW networkTimeoutSeconds lowered from 5 to 2 as defence in depth.
2026-05-04 22:43:10 +02:00
jubnl 852f0085d1 feat: complete offline write support with mutation queue + runtime SW cache config
- Add offline CRUD to todoRepo, budgetRepo, reservationRepo, accommodationRepo,
  dayRepo, tripRepo, fileRepo with optimistic Dexie writes and mutation queue
- Wire all store slices (todo, budget, reservations, files, dayNotes, assignments,
  tripStore) through repos for offline-aware writes
- Cover archive/unarchive, file toggleStar/update/delete, assignment create/delete,
  day title/notes update offline paths
- Migrate service worker from generateSW to injectManifest (custom sw.ts) with
  runtime-configurable api-data (7d/500) and map-tiles (30d/1000) cache policies
- Add Settings → Offline cache configuration UI with save/reset and live SW postMessage
- Extend mutationQueue flush to cover all writable Dexie tables
2026-05-04 21:36:44 +02:00
jubnl 4e3b27c712 fix(offline): cache accommodations, trip members, tags, and categories for full offline support 2026-04-14 23:50:52 +02:00