Fastwhisper / frontend /src /components /PendingResolve.tsx
Mbonea's picture
Overhaul journal UI: pending resolve sheet, gold FAB nav, and Home week score.
709db16
Raw
History Blame Contribute Delete
2.58 kB
/** Shared pending-resolve queue: Home banner / Log after-save / Entry detail. */
import { createContext } from "preact";
import { useCallback, useContext, useMemo, useState } from "preact/hooks";
import type { ComponentChildren } from "preact";
import { listPending, type Entry } from "../api";
import { ResolvePendingSheet } from "./ResolvePendingSheet";
type PendingApi = {
openResolve: (entries?: Entry[]) => void;
openResolveId: (id: string, fallback?: Entry) => void;
refreshPendingSignal: number;
bumpRefresh: () => void;
};
const PendingContext = createContext<PendingApi | null>(null);
export function usePendingResolve(): PendingApi {
const ctx = useContext(PendingContext);
if (!ctx) throw new Error("usePendingResolve requires PendingResolveProvider");
return ctx;
}
export function PendingResolveProvider({ children }: { children: ComponentChildren }) {
const [queue, setQueue] = useState<Entry[]>([]);
const [open, setOpen] = useState(false);
const [refreshPendingSignal, setRefresh] = useState(0);
const bumpRefresh = useCallback(() => {
setRefresh((n) => n + 1);
}, []);
const openResolve = useCallback(async (entries?: Entry[]) => {
if (entries && entries.length) {
setQueue(entries);
setOpen(true);
return;
}
try {
const data = await listPending(50);
if (!data.items.length) return;
setQueue(data.items);
setOpen(true);
} catch {
// leave closed
}
}, []);
const openResolveId = useCallback(async (id: string, fallback?: Entry) => {
if (fallback && fallback.id === id) {
setQueue([fallback]);
setOpen(true);
return;
}
try {
const data = await listPending(50);
const hit = data.items.find((item) => item.id === id);
const rest = data.items.filter((item) => item.id !== id);
setQueue(hit ? [hit, ...rest] : fallback ? [fallback, ...rest] : rest);
setOpen(true);
} catch {
if (fallback) {
setQueue([fallback]);
setOpen(true);
}
}
}, []);
const api = useMemo(
() => ({ openResolve, openResolveId, refreshPendingSignal, bumpRefresh }),
[openResolve, openResolveId, refreshPendingSignal, bumpRefresh],
);
return (
<PendingContext.Provider value={api}>
{children}
<ResolvePendingSheet
open={open}
queue={queue}
onClose={() => {
setOpen(false);
setQueue([]);
}}
onQueueChange={setQueue}
onResolved={bumpRefresh}
/>
</PendingContext.Provider>
);
}