9ba2996022
Adds a "Save offline" button on the recipe page that force-refetches the current page so the service worker's cache picks up a fresh copy right now, plus a small IndexedDB-backed list (lib/offline-db.ts) of what's been saved. The /offline fallback page now reads that list and renders it instead of being a dead end with just a "go back" link. Also fixes the service worker's network-first fetch handler, which never wrote successful responses into its cache -- meaning the existing offline page's claim that "recently visited recipes are available" was never actually true. It populates the cache on every successful GET now. Background sync: marking a batch-cook dish as cooked while offline (the only existing mark-cooked call site in the app) now queues the request in IndexedDB instead of just failing, and registers a Background Sync (public/sw.js's "sync" listener replays the queue) for Chromium; lib/offline-queue.ts's online-event fallback covers Safari/Firefox, which never fire that event at all. Both replay paths read/write the same IndexedDB store so either one drains it. Also removes apps/web/public/manifest.json, a stale static manifest that layout.tsx used to link to before the previous commit pointed it at the real generated route (app/manifest.ts) -- it had gone unnoticed and unused since. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import { getSavedRecipesOffline, type SavedRecipe } from "@/lib/offline-db";
|
|
|
|
export default function OfflinePage() {
|
|
const [saved, setSaved] = useState<SavedRecipe[] | null>(null);
|
|
|
|
useEffect(() => {
|
|
getSavedRecipesOffline().then(setSaved).catch(() => setSaved([]));
|
|
}, []);
|
|
|
|
return (
|
|
<div className="flex min-h-screen flex-col items-center justify-center gap-4 p-8 text-center">
|
|
<h1 className="text-2xl font-semibold">You're offline</h1>
|
|
<p className="max-w-sm text-muted-foreground">
|
|
Recipes you've saved for offline, or recently visited, are available below. Connect to the internet to load new content.
|
|
</p>
|
|
|
|
{saved && saved.length > 0 && (
|
|
<ul className="w-full max-w-sm space-y-2 text-left">
|
|
{saved.map((r) => (
|
|
<li key={r.id}>
|
|
<Link
|
|
href={`/recipes/${r.id}`}
|
|
className="block rounded-md border px-3 py-2 text-sm hover:bg-accent"
|
|
>
|
|
{r.title}
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
|
|
<Link
|
|
href="/recipes"
|
|
className="mt-2 underline underline-offset-4 hover:text-primary"
|
|
>
|
|
Back to my recipes
|
|
</Link>
|
|
</div>
|
|
);
|
|
}
|