Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 72a5fe8

Browse files
committed
fix: surface service worker update prompt
1 parent 3b502b4 commit 72a5fe8

9 files changed

Lines changed: 109 additions & 3 deletions

File tree

.planning/REQUIREMENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Updated: 2026-04-27
9090
- [x] **PWA-05**: IndexedDB is not proxied through service worker.
9191
- [x] **PWA-06**: Outdated cache cleanup is enabled.
9292
- [x] **PWA-07**: Install prompt component exists.
93+
- [x] **PWA-08**: Service-worker update prompt renders and disables reload during an active survey.
9394
- [x] **A11Y-01**: Brand colors are checked for WCAG contrast.
9495
- [x] **A11Y-02**: 44px tap target baseline exists.
9596
- [ ] **A11Y-03**: Lighthouse accessibility gate runs in CI.

.planning/STATE.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ See `.planning/PROJECT.md`.
1111
## Current Position
1212

1313
Phase: 7
14-
Status: Launch Kit implemented locally; verification/deploy pending
15-
Last activity: 2026-04-27 - Added a functional viral marketing workbench that generates share artifacts, AI citation text, clinical pilot outreach, contributor prompts, and remix links from real app routes.
14+
Status: Launch Kit implemented and deployed; service-worker update prompt added locally for stale-client refresh
15+
Last activity: 2026-04-27 - Added a functional viral marketing workbench that generates share artifacts, AI citation text, clinical pilot outreach, contributor prompts, and remix links from real app routes; then added the SW update prompt so returning visitors can refresh into new launch surfaces.
1616

1717
Progress: [█████████░] 90%
1818

@@ -54,6 +54,7 @@ Phase 7 success means attention converts into functional use:
5454
- Aggregate submission is implemented but disabled by default and non-blocking.
5555
- Phase 6 turns the demo into an operator tool: synthetic outcomes planning and local config forging.
5656
- Phase 7 treats marketing as product functionality: share copy and launch briefs must be generated from working demo/proof/studio/forge/poster routes.
57+
- Returning visitors need a visible service-worker update prompt; otherwise old cached shells can hide new launch routes until a manual hard refresh.
5758

5859
## Open Blockers
5960

.planning/phases/07-viral-functionality-and-marketing-loop/07-SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
- Added locale keys for the new route.
1111
- Added `docs/VIRALITY-PLAYBOOK.md`.
1212
- Added a GitHub issue template for weird functional experiments.
13+
- Rendered the service-worker update prompt so returning visitors can refresh
14+
into new launch surfaces without reloading mid-survey.
1315
- Updated README, public roadmap, Curiosity Lab docs, requirements, roadmap,
1416
and project state.
1517

.planning/phases/07-viral-functionality-and-marketing-loop/07-VERIFICATION.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Automated
44

5-
Passed on 2026-04-27:
5+
Passed on 2026-04-27 after Launch Kit and SW update prompt changes:
66

77
```bash
88
npm run verify
@@ -28,6 +28,7 @@ Passed locally on 2026-04-27 at `http://127.0.0.1:5173/#/launch`:
2828
- Confirm artifact selector and default artifact render.
2929
- Confirm launch brief download action is present.
3030
- Desktop and mobile viewport accessibility snapshots rendered the route.
31+
- Route smoke still passed after adding the virtual PWA update-registration module.
3132

3233
## Deployment
3334

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ The working app includes:
2424
- Follow-up calendar export with local `.ics` generation.
2525
- Follow-up reminder scheduling helpers and in-app reminder banner.
2626
- PWA manifest, icons, service worker, and install prompt.
27+
- Service-worker update prompt so returning visitors can refresh into new routes without losing an active survey.
2728
- Optional aggregate submission module, disabled by default.
2829

2930
Remaining launch blockers:

docs/ARCHITECTURE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Routes:
4242
- `src/lib/aggregate/`: optional de-identified aggregate submit path, disabled by default.
4343
- `src/lib/pdf/`: snapshots the chart canvas and calls `window.print()`.
4444
- `src/lib/notifications/`: computes follow-up reminders and notification caps.
45+
- `src/routes/SwUpdatePrompt.svelte`: renders the service-worker refresh prompt and
46+
disables reload while a survey is active.
4547

4648
## Data Model
4749

src/App.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import Poster from './routes/Poster.svelte';
1313
import LocaleSwitcher from './routes/LocaleSwitcher.svelte';
1414
import InAppReminderBanner from './routes/InAppReminderBanner.svelte';
15+
import SwUpdatePrompt from './routes/SwUpdatePrompt.svelte';
1516
import {
1617
loadPracticeConfig,
1718
applyBrandingToDocument,
@@ -141,6 +142,8 @@
141142
</div>
142143
</header>
143144

145+
<SwUpdatePrompt {t} busy={route === 'survey'} />
146+
144147
<main>
145148
{#if route === 'home'}
146149
<InAppReminderBanner {t} onstart={() => navigate('survey')} />

src/pwa.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
declare module 'virtual:pwa-register' {
2+
export interface RegisterSWOptions {
3+
immediate?: boolean;
4+
onNeedRefresh?: () => void;
5+
onOfflineReady?: () => void;
6+
onRegisteredSW?: (swUrl: string, registration: ServiceWorkerRegistration | undefined) => void;
7+
onRegisterError?: (error: unknown) => void;
8+
}
9+
10+
export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise<void>;
11+
}

src/routes/SwUpdatePrompt.svelte

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<script lang="ts">
2+
import { onMount } from 'svelte';
3+
import { registerSW } from 'virtual:pwa-register';
4+
5+
type T = (k: string, p?: Record<string, string | number>) => string;
6+
7+
interface Props {
8+
t: T;
9+
busy: boolean;
10+
}
11+
12+
let { t, busy }: Props = $props();
13+
let visible = $state(false);
14+
let updateSW = $state<((reloadPage?: boolean) => Promise<void>) | null>(null);
15+
16+
onMount(() => {
17+
updateSW = registerSW({
18+
immediate: true,
19+
onNeedRefresh() {
20+
visible = true;
21+
},
22+
});
23+
});
24+
25+
async function reload(): Promise<void> {
26+
if (!updateSW || busy) return;
27+
await updateSW(true);
28+
}
29+
30+
function dismiss(): void {
31+
visible = false;
32+
}
33+
</script>
34+
35+
{#if visible}
36+
<aside class="sw-update" role="status" aria-live="polite">
37+
<div>
38+
<strong>{t('swupdate.title')}</strong>
39+
<p>{busy ? t('swupdate.body.busy') : t('swupdate.body.ready')}</p>
40+
</div>
41+
<div class="actions">
42+
<button class="primary" disabled={busy} onclick={() => { void reload(); }}>
43+
{t('swupdate.cta')}
44+
</button>
45+
<button onclick={dismiss}>{t('swupdate.dismiss')}</button>
46+
</div>
47+
</aside>
48+
{/if}
49+
50+
<style>
51+
.sw-update {
52+
max-width: var(--max-content);
53+
margin: 0.75rem auto 0;
54+
border: 1px solid var(--accent);
55+
border-radius: 8px;
56+
padding: 0.9rem 1rem;
57+
display: grid;
58+
gap: 0.75rem;
59+
background: var(--bg);
60+
}
61+
.sw-update strong {
62+
display: block;
63+
margin-bottom: 0.15rem;
64+
}
65+
.sw-update p {
66+
margin: 0;
67+
color: var(--muted);
68+
font-size: 0.9rem;
69+
}
70+
.actions {
71+
display: flex;
72+
flex-wrap: wrap;
73+
gap: 0.5rem;
74+
}
75+
.actions button {
76+
padding: 0.5rem 0.8rem;
77+
}
78+
@media (min-width: 560px) {
79+
.sw-update {
80+
grid-template-columns: 1fr auto;
81+
align-items: center;
82+
}
83+
}
84+
</style>

0 commit comments

Comments
 (0)