SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
2.9 KB · 57 lines tsx
Raw Blame History
1'use client';23import { useActionState } from 'react';4import { createCollectionAction, updateCollectionAction } from '@/lib/account/actions';5import { idle } from '@/lib/auth/state';6import { Field, FormMessage, Select, SubmitButton, TextArea, TextInput } from '@/components/account/form';78const KINDS = [9  ['collection', 'Collection'],10  ['wishlist', 'Wishlist (with budget)'],11  ['vault', 'Vault / storage'],12  ['sold', 'Sold archive'],13] as const;1415export function CreateCollectionForm() {16  const [state, action] = useActionState(createCollectionAction, idle);17  return <CollectionFields state={state} action={action} submitLabel="Create collection" />;18}1920export function EditCollectionForm({ collection }: { collection: { id: string; name: string; description: string | null; kind: string; budgetUsd: number | null; color: string | null } }) {21  const [state, action] = useActionState(updateCollectionAction, idle);22  return <CollectionFields state={state} action={action} submitLabel="Save changes" initial={collection} />;23}2425function CollectionFields({ state, action, submitLabel, initial }: { state: import('@/lib/auth/state').ActionState; action: (fd: FormData) => void; submitLabel: string; initial?: { id: string; name: string; description: string | null; kind: string; budgetUsd: number | null; color: string | null } }) {26  return (27    <form action={action} className="space-y-4" noValidate>28      {initial ? <input type="hidden" name="collectionId" value={initial.id} /> : null}29      <FormMessage state={state} />30      <div className="grid gap-4 sm:grid-cols-[minmax(0,2fr)_minmax(0,1fr)_minmax(0,1fr)_80px]">31        <Field label="Name" name="name" error={state.fieldErrors?.name}>32          <TextInput name="name" required maxLength={80} defaultValue={initial?.name ?? ''} placeholder="e.g. Vintage Pokémon, Watch box, 2025 pickups" />33        </Field>34        <Field label="Type" name="kind">35          <Select name="kind" defaultValue={initial?.kind ?? 'collection'}>36            {KINDS.map(([v, l]) => (37              <option key={v} value={v}>38                {l}39              </option>40            ))}41          </Select>42        </Field>43        <Field label="Budget (USD, optional)" name="budgetUsd" error={state.fieldErrors?.budgetUsd}>44          <TextInput name="budgetUsd" type="number" min={0} step="1" defaultValue={initial?.budgetUsd ?? ''} placeholder="wishlists" />45        </Field>46        <Field label="Colour" name="color">47          <input type="color" name="color" defaultValue={initial?.color ?? '#1f3a8a'} className="h-10 w-full cursor-pointer rounded-md border border-border bg-elevated p-1 md:h-9" />48        </Field>49      </div>50      <Field label="Description (optional)" name="description">51        <TextArea name="description" maxLength={500} defaultValue={initial?.description ?? ''} placeholder="What lives here?" className="min-h-[60px]" />52      </Field>53      <SubmitButton pendingText="Saving…">{submitLabel}</SubmitButton>54    </form>55  );56}57