Vectrum
Sign In
75 lines · 2.5 KB · TypeScript
"use client";

import { useActionState, useState, type ReactNode } from "react";
import type { FormState } from "@/app/actions/types";
import { AlertIcon, TrashIcon } from "./icons";
import { TextField } from "./settings-fields";
import { PlateBody, PlateFooter } from "./settings-plate";
import { Alert, Button } from "./ui";

/** Deleting something for good: one red cap opens the type-to-confirm form, whose red cap does it. */
export function DeleteZone({
  action,
  confirmText,
  title,
  description,
  consequence,
  openLabel,
  confirmLabel,
}: {
  action: (prev: FormState, formData: FormData) => Promise<FormState>;
  /** What has to be typed to confirm; posted as `confirm`. */
  confirmText: string;
  title: string;
  description: string;
  /** What goes with it, said in red once the form is open. */
  consequence: ReactNode;
  openLabel: string;
  confirmLabel: string;
}) {
  const [state, formAction, pending] = useActionState(action, undefined);
  const [confirm, setConfirm] = useState("");
  const [open, setOpen] = useState(false);
  return (
    <>
      <div className="flex min-h-[52px] flex-wrap items-center gap-4 px-6 py-4">
        <div className="flex min-w-0 flex-1 flex-col gap-0.5">
          <p className="type-title text-ink">{title}</p>
          <p className="type-body text-ink2">{description}</p>
        </div>
        {!open && (
          <Button type="button" variant="danger" icon={<TrashIcon />} onClick={() => setOpen(true)}>
            {openLabel}
          </Button>
        )}
      </div>
      {open && (
        <form action={formAction}>
          <PlateBody className="pt-0">
            <p className="flex items-start gap-2 type-body text-red">
              <AlertIcon className="mt-px shrink-0" />
              <span>{consequence}</span>
            </p>
            <TextField
              className="max-w-xl"
              label={`To confirm, type “${confirmText}” below:`}
              name="confirm"
              value={confirm}
              onChange={(e) => setConfirm(e.target.value)}
              autoFocus
            />
            {state?.error && <Alert>{state.error}</Alert>}
          </PlateBody>
          <PlateFooter>
            <Button type="button" onClick={() => setOpen(false)}>
              Cancel
            </Button>
            <Button variant="danger" icon={<TrashIcon />} disabled={confirm !== confirmText || pending}>
              {pending ? "Deleting…" : confirmLabel}
            </Button>
          </PlateFooter>
        </form>
      )}
    </>
  );
}