import { useState } from 'react' import { Alert } from '@/components/ui/Alert' import { Button } from '@/components/ui/Button' import { TextArea } from '@/components/ui/TextArea' import { TextField } from '@/components/ui/TextField' import { errorMessage } from '@/lib/api' import { formatObservedAt, today, useCreateJournalEntry, useDeleteJournalEntry, useJournal, useUpdateJournalEntry, type JournalEntry, } from '@/lib/journal' import type { EditorObject } from './types' import { objectDisplayName } from './kinds' /** * The garden's journal: write an entry, read the season back. * * Notes get written standing in the garden holding a phone, usually one-handed. * If it takes more than a couple of taps from looking at a bed to typing a * sentence, the log stays empty — so the composer is open by default rather than * behind an "add" button, and selecting a bed pre-scopes it to that bed. */ export function JournalPanel({ gardenId, canEdit, currentUserId, isOwner, objects, scopeObjectId, onScopeChange, }: { gardenId: number canEdit: boolean currentUserId?: number isOwner: boolean objects: EditorObject[] /** Which bed the panel is filtered to, if any. */ scopeObjectId: number | null onScopeChange: (id: number | null) => void }) { const filter = scopeObjectId != null ? { objectId: scopeObjectId } : {} const journal = useJournal(gardenId, filter) const entries = journal.data?.pages.flatMap((p) => p.entries) ?? [] const scopedObject = objects.find((o) => o.id === scopeObjectId) ?? null return (

Journal

{objects.length > 0 && ( )}
{canEdit && ( )} {journal.isPending &&

Loading…

} {journal.isError && entries.length === 0 && ( {errorMessage(journal.error, 'Could not load the journal.')} )} {journal.isSuccess && entries.length === 0 && (

{scopedObject ? `Nothing written about ${objectDisplayName(scopedObject)} yet.` : 'Nothing written yet. This is where what happened goes — when something went in, what came up, what the frost got. Next year you get to read it back.'}

)}
    {entries.map((e) => ( ))}
{journal.hasNextPage && ( )} {journal.isError && entries.length > 0 && (

{errorMessage(journal.error, "Couldn't load older entries.")}

)}
) } function Composer({ gardenId, objectId, scopeLabel, }: { gardenId: number objectId: number | null scopeLabel: string | null }) { const create = useCreateJournalEntry(gardenId) const [body, setBody] = useState('') // Editable so an observation can be backdated: you write up Saturday on Sunday. const [observedAt, setObservedAt] = useState(today()) const [error, setError] = useState(null) const submit = () => { const text = body.trim() if (!text) return setError(null) create.mutate( { body: text, observedAt, objectId: objectId ?? undefined }, { onSuccess: () => { setBody('') setObservedAt(today()) }, onError: (err) => setError(errorMessage(err, "Couldn't save that note.")), }, ) } return (