feat(idaa): add /idaa/clear-caches page for Novi iframe cache reset
Clears all IDB databases, localStorage, and sessionStorage for the prod-idaa.oneskyit.com origin when loaded as an iframe inside www.idaa.org. Targets the partitioned storage bucket used by IDAA Novi iframes — direct navigation to the site clears a different partition and has no effect. Uses Novi-safe styling (explicit bg/text surfaces, no bare h1 elements, inline styles on links) to survive Bootstrap v3 CSS injected by Novi. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
138
src/routes/idaa/clear-caches/+page.svelte
Normal file
138
src/routes/idaa/clear-caches/+page.svelte
Normal file
@@ -0,0 +1,138 @@
|
||||
<script lang="ts">
|
||||
import { browser } from '$app/environment';
|
||||
import { TriangleAlert, CircleCheck, Loader } from '@lucide/svelte';
|
||||
|
||||
type StepStatus = 'pending' | 'running' | 'done' | 'error';
|
||||
|
||||
interface ClearStep {
|
||||
label: string;
|
||||
status: StepStatus;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
let steps: ClearStep[] = $state([
|
||||
{ label: 'IndexedDB databases', status: 'pending', detail: '' },
|
||||
{ label: 'Local storage', status: 'pending', detail: '' },
|
||||
{ label: 'Session storage', status: 'pending', detail: '' }
|
||||
]);
|
||||
|
||||
let overall_done = $state(false);
|
||||
let had_error = $state(false);
|
||||
|
||||
async function clear_all_caches() {
|
||||
// IDB — enumerate and delete every database on this origin
|
||||
steps[0].status = 'running';
|
||||
try {
|
||||
const db_list = await indexedDB.databases();
|
||||
for (const db of db_list) {
|
||||
if (db.name) indexedDB.deleteDatabase(db.name);
|
||||
}
|
||||
steps[0].status = 'done';
|
||||
steps[0].detail = `${db_list.length} database${db_list.length !== 1 ? 's' : ''} cleared`;
|
||||
} catch (e) {
|
||||
steps[0].status = 'error';
|
||||
steps[0].detail = String(e);
|
||||
had_error = true;
|
||||
}
|
||||
|
||||
// localStorage
|
||||
steps[1].status = 'running';
|
||||
try {
|
||||
localStorage.clear();
|
||||
steps[1].status = 'done';
|
||||
steps[1].detail = 'Cleared';
|
||||
} catch (e) {
|
||||
steps[1].status = 'error';
|
||||
steps[1].detail = String(e);
|
||||
had_error = true;
|
||||
}
|
||||
|
||||
// sessionStorage
|
||||
steps[2].status = 'running';
|
||||
try {
|
||||
sessionStorage.clear();
|
||||
steps[2].status = 'done';
|
||||
steps[2].detail = 'Cleared';
|
||||
} catch (e) {
|
||||
steps[2].status = 'error';
|
||||
steps[2].detail = String(e);
|
||||
had_error = true;
|
||||
}
|
||||
|
||||
overall_done = true;
|
||||
|
||||
// Notify parent window (Novi page) that the clear is complete.
|
||||
// The Novi page can optionally listen for this to show a confirmation to the member.
|
||||
try {
|
||||
window.parent.postMessage({ ae_cache_cleared: true, had_error }, '*');
|
||||
} catch (_) {
|
||||
// not in an iframe — ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Run once on mount. Reads no reactive state so $effect never re-fires.
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
clear_all_caches();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Explicit bg+text surfaces so Bootstrap v3 (injected by Novi in iframe context) cannot
|
||||
cause white-on-white. h1/h2 are avoided — Bootstrap targets bare heading elements. -->
|
||||
<div class="mx-auto mt-8 flex max-w-sm flex-col items-center gap-6 rounded-lg bg-white py-10 text-center text-gray-900 dark:bg-gray-900 dark:text-gray-100">
|
||||
{#if !overall_done}
|
||||
<Loader size={40} class="animate-spin text-blue-500" />
|
||||
<div class="text-xl font-semibold">
|
||||
Clearing saved data…
|
||||
</div>
|
||||
{:else if had_error}
|
||||
<TriangleAlert size={40} class="text-warning-500" />
|
||||
<div class="text-xl font-semibold">
|
||||
Cleared with some errors
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
Most caches were cleared. Close this tab and reload the IDAA pages to
|
||||
get the latest version.
|
||||
</p>
|
||||
{:else}
|
||||
<CircleCheck size={40} class="text-success-500" />
|
||||
<div class="text-xl font-semibold">
|
||||
All caches cleared
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
Close this tab and reload the IDAA pages to get the latest version.
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
<ul class="w-full rounded border border-gray-200 text-left text-sm dark:border-gray-700">
|
||||
{#each steps as step (step.label)}
|
||||
<li
|
||||
class="flex items-center justify-between gap-2 border-b border-gray-100 px-3 py-2 last:border-b-0 dark:border-gray-700">
|
||||
<span class="text-gray-700 dark:text-gray-300">{step.label}</span>
|
||||
<span class="flex items-center gap-1 text-xs">
|
||||
{#if step.status === 'pending'}
|
||||
<span class="text-gray-400">—</span>
|
||||
{:else if step.status === 'running'}
|
||||
<Loader size="0.85em" class="animate-spin text-blue-400" />
|
||||
{:else if step.status === 'done'}
|
||||
<CircleCheck size="0.85em" class="text-success-500" />
|
||||
<span class="text-gray-600 dark:text-gray-400">{step.detail}</span>
|
||||
{:else if step.status === 'error'}
|
||||
<TriangleAlert size="0.85em" class="text-error-500" />
|
||||
<span class="text-error-500">{step.detail}</span>
|
||||
{/if}
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
{#if overall_done}
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300">
|
||||
If you were having trouble with the IDAA
|
||||
<a href="https://www.idaa.org/idaa-meetings" style="color:#2563eb;text-decoration:underline;" class="text-blue-600 underline">Meeting List</a>,
|
||||
<a href="https://www.idaa.org/idaa-archives" style="color:#2563eb;text-decoration:underline;" class="text-blue-600 underline">Archives</a>, or
|
||||
<a href="https://www.idaa.org/idaa-bulletin-board" style="color:#2563eb;text-decoration:underline;" class="text-blue-600 underline">Bulletin Board</a>,
|
||||
please try once more. We apologize for the inconvenience, and thank you for your patience while we work to improve the IDAA experience!
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user