import { useState, type KeyboardEvent } from 'react'
import { Alert } from '@/components/ui/Alert'
import { Button, IconButton } from '@/components/ui/Button'
import { TextAreaField, TextField } from '@/components/ui/Field'
import { errorMessage } from '@/lib/api'
import { cn } from '@/lib/cn'
import { today } from '@/lib/dates'
import {
formatObservedAt,
useCreateJournalEntry,
useDeleteJournalEntry,
useJournal,
useUpdateJournalEntry,
type JournalEntry,
type JournalFilter,
} from '@/lib/journal'
import type { EditorPlanting } from '@/lib/plantings'
import { objectDisplayName } from './kinds'
import { useEditorStore } from './store'
import type { EditorObject } from './types'
/** What a new note attaches to: the selection, else the focused bed, else the
* garden — and how to say it. */
export interface JournalAttach {
objectId?: number
plantingId?: number
label: string | null
}
/**
* The grow journal: entries newest first as cards (what it's about, when, the
* note), a one-line composer that attaches to whatever's selected — Enter
* submits — and, when the rail was opened from a bed's "N notes", a filter chip
* narrowing the list to that thing. Notes get written standing in the garden
* holding a phone, so the composer is never more than a tap away.
*/
export function JournalTab({
gardenId,
canEdit,
currentUserId,
isOwner,
objects,
plantings,
attach,
composerFirst = false,
large = false,
}: {
gardenId: number
canEdit: boolean
currentUserId?: number
isOwner: boolean
objects: EditorObject[]
plantings: EditorPlanting[]
attach: JournalAttach
/** Phone: the input above the entries (the thumb is at the bottom anyway). */
composerFirst?: boolean
large?: boolean
}) {
const scope = useEditorStore((s) => s.journalScope)
const setScope = useEditorStore((s) => s.setJournalScope)
const filter: JournalFilter = scope?.type === 'object' ? { objectId: scope.id } : scope?.type === 'plop' ? { plantingId: scope.id } : {}
const journal = useJournal(gardenId, filter)
const entries = journal.data?.pages.flatMap((p) => p.entries) ?? []
const scopeName =
scope?.type === 'object'
? objectDisplayName(objects.find((o) => o.id === scope.id) ?? { name: '', kind: 'object' })
: scope?.type === 'plop'
? 'one planting'
: null
const composer = canEdit && (
)
return (
}
{journal.isError && entries.length === 0 && {errorMessage(journal.error, 'Could not load the journal.')}}
{journal.isSuccess && entries.length === 0 && (
{scopeName
? `Nothing written about ${scopeName} 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.'}