import { useId, useState } from "react"; import { Dialog } from "#/components/dialog"; import { Button } from "#/components/ui/button"; import { Checkbox } from "#/components/ui/checkbox"; import { Input } from "#/components/ui/input"; import { SidebarInset, SidebarProvider } from "#/components/ui/sidebar"; import { Textarea } from "#/components/ui/textarea"; import { TooltipProvider } from "#/components/ui/tooltip"; import { WorkspaceNavigation } from "#/components/workspace-navigation"; import { useUrlState } from "#/features/navigation/use-url-state"; import { type JournalEntry as Entry, type EntryKind, entryKindLabels, useWorkspaceState, } from "#/features/workspace/workspace-state"; type Draft = Pick; const emptyDraft: Draft = { kind: "メモ", text: "", source: "", occurredAt: "" }; const kinds: EntryKind[] = ["メモ", "再開地点", "服薬", "体重"]; function formatTime(value: string | undefined) { if (!value) return "Unknown"; return new Date(value).toLocaleString("en-US", { year: "numeric", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit", }); } export function JournalPage() { const { entries, setEntries } = useWorkspaceState(); const [draft, setDraft] = useState(emptyDraft); const [search, updateSearch] = useUrlState(); const correcting = entries.find((entry) => entry.id === search.entry); const reviewing = search.review; const setCorrecting = (entry: Entry | null) => updateSearch({ entry: entry?.id }); const setReviewing = (open: boolean) => updateSearch({ review: open || undefined }); const [selected, setSelected] = useState>(new Set()); const superseded = new Set(entries.map((entry) => entry.correctionOf)); const current = entries.filter((entry) => !superseded.has(entry.id)); function append(value: Draft, correctionOf?: string) { setEntries((previous) => [ { ...value, text: value.text.trim(), source: value.source.trim(), id: crypto.randomUUID(), recordedAt: new Date().toISOString(), correctionOf, }, ...previous, ]); } return (

Journal

{ append(draft); setDraft(emptyDraft); }} submitLabel="Save entry" />
{entries.length === 0 &&

No entries yet

} {entries.map((entry) => (
{entryKindLabels[entry.kind]} {superseded.has(entry.id) && ( Original )} {entry.correctionOf && ( Correction )} {!superseded.has(entry.id) && ( )}

{entry.text} {entry.kind === "体重" ? " kg" : ""}

Occurred: {formatTime(entry.occurredAt)} · Recorded:{" "} {formatTime(entry.recordedAt)}

{(entry.kind === "体重" || entry.source) && (

Source: {entry.source || "Unknown"}

)}
))}
{correcting && ( setCorrecting(null)} onSave={(value) => { append(value, correcting.id); setCorrecting(null); }} /> )} {reviewing && ( setReviewing(false)} >

Select the entries to include. Nothing is sent externally.

{current.map((entry) => ( ))}