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%
4.0 KB · 83 lines tsx
Raw Blame History
1'use client';23import { useActionState } from 'react';4import { cancelChangeEmailAction, confirmChangeEmailAction, startChangeEmailAction, updateProfileAction } from '@/lib/auth/account-actions';5import { idle } from '@/lib/auth/state';6import { CodeInput, Field, FormMessage, Select, SubmitButton, TextArea, TextInput } from '@/components/account/form';78export function ProfileForm({ user }: { user: { name: string | null; handle: string | null; bio: string | null; displayCurrency: string } }) {9  const [state, action] = useActionState(updateProfileAction, idle);10  return (11    <form action={action} className="space-y-4" noValidate>12      <FormMessage state={state} />13      <div className="grid gap-4 sm:grid-cols-2">14        <Field label="Name" name="name" error={state.fieldErrors?.name}>15          <TextInput name="name" defaultValue={user.name ?? ''} maxLength={80} autoComplete="name" />16        </Field>17        <Field label="Public handle" name="handle" error={state.fieldErrors?.handle} hint="3–24 chars, letters/numbers/hyphens. Unlocks /u/handle.">18          <div className="flex items-center">19            <span className="rounded-l-md border border-r-0 border-border bg-sunken px-2.5 py-2 text-sm text-subtle">/u/</span>20            <TextInput name="handle" id="handle" defaultValue={user.handle ?? ''} className="rounded-l-none" placeholder="yourname" autoCapitalize="off" />21          </div>22        </Field>23      </div>24      <Field label="Bio" name="bio" error={state.fieldErrors?.bio} hint="Up to 280 characters.">25        <TextArea name="bio" defaultValue={user.bio ?? ''} maxLength={280} placeholder="What do you collect?" />26      </Field>27      <Field label="Display currency" name="displayCurrency" hint="Historical sales keep their native currency; this only changes the display conversion.">28        <Select name="displayCurrency" defaultValue={user.displayCurrency} className="sm:max-w-[200px]">29          {['USD', 'CAD', 'EUR', 'GBP', 'JPY'].map((c) => (30            <option key={c} value={c}>31              {c}32            </option>33          ))}34        </Select>35      </Field>36      <SubmitButton pendingText="Saving…">Save profile</SubmitButton>37    </form>38  );39}4041export function ChangeEmailForm({ pendingEmail }: { pendingEmail: string | null }) {42  const [start, startAction] = useActionState(startChangeEmailAction, idle);43  const [confirm, confirmAction] = useActionState(confirmChangeEmailAction, idle);44  const pending = (start.data?.pendingEmail as string | undefined) ?? pendingEmail;45  if (pending && !confirm.ok) {46    return (47      <div className="space-y-4">48        <p className="text-sm text-muted">49          Enter the code we sent to <span className="font-medium text-fg">{pending}</span>.50        </p>51        <form action={confirmAction} className="space-y-3" noValidate>52          <FormMessage state={confirm} />53          <CodeInput name="code" autoSubmit={false} label="Confirmation code" />54          <div className="flex gap-2">55            <SubmitButton pendingText="Confirming…">Confirm new e-mail</SubmitButton>56          </div>57        </form>58        <form action={cancelChangeEmailAction}>59          <SubmitButton variant="ghost" className="h-8 text-xs">60            Cancel change61          </SubmitButton>62        </form>63      </div>64    );65  }66  return (67    <form action={startAction} className="space-y-4" noValidate>68      <FormMessage state={confirm.ok ? confirm : start} />69      <div className="grid gap-4 sm:grid-cols-2">70        <Field label="New e-mail" name="newEmail" error={start.fieldErrors?.newEmail}>71          <TextInput name="newEmail" type="email" autoComplete="email" required />72        </Field>73        <Field label="Current password" name="password" error={start.fieldErrors?.password}>74          <TextInput name="password" type="password" autoComplete="current-password" required />75        </Field>76      </div>77      <SubmitButton variant="secondary" pendingText="Sending code…">78        Send confirmation code79      </SubmitButton>80    </form>81  );82}83