- Extract offline queue to src/lib/offline-queue.ts - Extract shared LogModal with time presets (Just now/5/15/30min/Custom) and smart default pre-fill from last log of same type - Replace ActivityScroller with TodaySummary (today's counts + last time) - Fix activity page: GET /api/logs without type param now returns all logs merged - Fix field naming: log.loggedAt / log.amount (camelCase throughout) - Add FAB to activity page for zero-navigation quick logging - Recent Activity shows 5 most recent entries with correct field names Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
38 lines
1 KiB
TypeScript
38 lines
1 KiB
TypeScript
export interface OfflineEntry {
|
|
id: string;
|
|
type: "feed" | "diaper" | "sleep";
|
|
data: any;
|
|
timestamp: number;
|
|
}
|
|
|
|
const KEY = "tia_offline_queue";
|
|
|
|
export function getOfflineQueue(): OfflineEntry[] {
|
|
if (typeof window === "undefined") return [];
|
|
try {
|
|
const d = localStorage.getItem(KEY);
|
|
return d ? JSON.parse(d) : [];
|
|
} catch { return []; }
|
|
}
|
|
|
|
export function addToOfflineQueue(entry: Omit<OfflineEntry, "id" | "timestamp">) {
|
|
const q = getOfflineQueue();
|
|
q.push({ ...entry, id: crypto.randomUUID(), timestamp: Date.now() });
|
|
localStorage.setItem(KEY, JSON.stringify(q));
|
|
}
|
|
|
|
export async function processOfflineQueue() {
|
|
const q = getOfflineQueue();
|
|
if (q.length === 0) return;
|
|
const failed: OfflineEntry[] = [];
|
|
for (const entry of q) {
|
|
try {
|
|
await fetch("/api/logs", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(entry.data),
|
|
});
|
|
} catch { failed.push(entry); }
|
|
}
|
|
localStorage.setItem(KEY, JSON.stringify(failed));
|
|
}
|