Fastwhisper / frontend /src /components /ResolvePendingSheet.tsx
Mbonea's picture
Overhaul journal UI: pending resolve sheet, gold FAB nav, and Home week score.
709db16
Raw
History Blame Contribute Delete
3.05 kB
/** Bottom sheet to finish a pending entry: Worked | Partial | Failed. */
import { useEffect, useState } from "preact/hooks";
import { patchEntry, type Entry } from "../api";
import { Button } from "./Button";
import { ResultChips, type ResolveResult } from "./ResultChips";
import { Sheet } from "./Sheet";
import { useToast } from "./Toast";
type Props = {
open: boolean;
queue: Entry[];
onClose: () => void;
onQueueChange: (next: Entry[]) => void;
onResolved: () => void;
};
export function ResolvePendingSheet({
open,
queue,
onClose,
onQueueChange,
onResolved,
}: Props) {
const toast = useToast();
const current = queue[0] ?? null;
const [result, setResult] = useState<ResolveResult | null>(null);
const [remedy, setRemedy] = useState("");
const [busy, setBusy] = useState(false);
useEffect(() => {
if (!current) return;
setResult(null);
setRemedy(current.remedy || "");
}, [current?.id]);
if (!open) return null;
const save = async () => {
if (!current || !result) return;
setBusy(true);
try {
await patchEntry(current.id, { result, remedy: remedy.trim() });
toast.show("Saved");
onResolved();
const rest = queue.slice(1);
if (rest.length) {
onQueueChange(rest);
} else {
onClose();
}
} catch (err) {
toast.show(err instanceof Error ? err.message : "Could not save", "error");
} finally {
setBusy(false);
}
};
return (
<Sheet
open={open}
title="Finish entry"
onClose={onClose}
tall
>
{current ? (
<div class="resolve-sheet stack">
<div class="resolve-snippet surface-card">
{current.activity ? (
<p class="muted resolve-activity">{current.activity}</p>
) : null}
<p>{current.happened}</p>
</div>
<div>
<span class="field-label">Result</span>
<ResultChips
value={result}
excludePending
onChange={(value) => setResult(value as ResolveResult)}
/>
</div>
<div>
<label class="field-label" for="resolve-remedy">
Remedy
</label>
<input
id="resolve-remedy"
class="field-input"
type="text"
value={remedy}
placeholder="What did you try?"
onInput={(e) => setRemedy((e.target as HTMLInputElement).value)}
/>
</div>
{queue.length > 1 ? (
<p class="muted">{queue.length - 1} more pending after this</p>
) : null}
<div class="resolve-sticky">
<Button
disabled={busy || !result}
onClick={save}
className="btn-large"
>
{busy ? "Saving…" : "Save result"}
</Button>
</div>
</div>
) : (
<p class="muted">Nothing pending.</p>
)}
</Sheet>
);
}