Files
NextChair/manager/src/app/dashboard/[slug]/delete/delete-business-form.tsx
T
Stefan Lazic 17eee5b932
CI / ci (push) Canceled after 0s
Updates 1
The session built:

Appointments page: a single list, newest first.
Block Time: edit and delete.
Customer CSV export: with barber notes excluded.
Guest-link regression test: a test that an appointment id alone is rejected, plus fixes to the stale docs.

It built the scheduler, job runner with live progress, backup and restore, and the health alerts. Its own report says a real delete-and-restore on throwaway Docker passed, but I haven’t repeated that. It also says real SMTP and large dumps were not exercised. The manager image needs rebuilding for the backups to work, because it now installs 7zip.
2026-10-17 22:29:00 +01:00

69 lines
2.5 KiB
TypeScript

"use client";
import Link from "next/link";
import { useActionState, useState } from "react";
import { JobProgress } from "../../job-progress";
import { PassphraseNotice } from "../../passphrase-notice";
import { deleteBusinessAction, type DeleteBusinessState } from "./actions";
const initialState: DeleteBusinessState = { error: null, jobId: null, newPassphrase: null };
export function DeleteBusinessForm({ slug }: { slug: string }) {
const boundAction = deleteBusinessAction.bind(null, slug);
const [state, formAction, isPending] = useActionState(boundAction, initialState);
const [confirmation, setConfirmation] = useState("");
const canDelete = confirmation === slug;
if (state.jobId) {
return (
<div className="space-y-4">
{state.newPassphrase && <PassphraseNotice passphrase={state.newPassphrase} />}
<JobProgress jobId={state.jobId} refreshOnFinish={false}>
<Link href="/dashboard" className="inline-block rounded-md bg-ink px-4 py-2 text-sm font-semibold text-white">
Back to businesses
</Link>
</JobProgress>
</div>
);
}
return (
<form action={formAction} className="space-y-4">
<label className="flex items-start gap-2 text-sm">
<input type="checkbox" name="finalBackup" defaultChecked className="mt-0.5" />
<span>
Take a final backup first <span className="text-muted">(recommended — kept on this server after the business is gone; deleting stops if the backup fails)</span>
</span>
</label>
<div>
<label htmlFor="confirmation" className="block text-sm font-medium text-muted">
Type <span className="font-mono font-semibold text-ink">{slug}</span> to confirm
</label>
<input
id="confirmation"
name="confirmation"
type="text"
autoComplete="off"
autoCorrect="off"
spellCheck={false}
value={confirmation}
onChange={(e) => setConfirmation(e.target.value)}
className="mt-1 w-full rounded-md border border-line px-3 py-2 font-mono text-sm"
/>
</div>
{state.error && (
<p role="alert" className="text-sm font-medium text-danger">
{state.error}
</p>
)}
<button
type="submit"
disabled={!canDelete || isPending}
className="w-full rounded-md bg-danger py-2 text-sm font-semibold text-white disabled:opacity-40"
>
{isPending ? "Starting…" : "Delete Business"}
</button>
</form>
);
}