Luis Ortega · Documents
Contracts and checks stored on Luis's employee record.
- Employment contract – Luis Ortega.pdfSigned 12 Jan 2024 · 312 KB
- NDA – Luis Ortega.pdfSigned 12 Jan 2024 · 128 KB
- Right to work check.pdfVerified 15 Jan 2024 · 2.1 MB
confirm-a-destructive-action.tsx
"use client";
import { useState } from "react";
import { LuFileText, LuTrash2 } from "react-icons/lu";
import { Alert, Button, Dialog } from "@nexera-ui/react";
interface Doc {
id: string;
name: string;
meta: string;
}
const DOCS: [Doc, ...Doc[]] = [
{ id: "d1", name: "Employment contract – Luis Ortega.pdf", meta: "Signed 12 Jan 2024 · 312 KB" },
{ id: "d2", name: "NDA – Luis Ortega.pdf", meta: "Signed 12 Jan 2024 · 128 KB" },
{ id: "d3", name: "Right to work check.pdf", meta: "Verified 15 Jan 2024 · 2.1 MB" },
];
/** Confirm a destructive action: name exactly what will be deleted, and what else goes with it, before deleting it. */
export default function ConfirmADestructiveAction() {
const [docs, setDocs] = useState<Doc[]>(DOCS);
const [pending, setPending] = useState<Doc>(DOCS[0]);
const [isOpen, setOpen] = useState(false);
const [deleted, setDeleted] = useState<string | null>(null);
const confirmDelete = () => {
setDocs((current) => current.filter((doc) => doc.id !== pending.id));
setDeleted(pending.name); // replace with your delete request
};
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<section aria-labelledby="destructive-docs-title" className="mx-auto grid max-w-3xl gap-4">
<header className="grid gap-1">
<h2 id="destructive-docs-title" className="text-heading-h2 text-primary">
Luis Ortega · Documents
</h2>
<p className="text-body-default text-secondary">
Contracts and checks stored on Luis's employee record.
</p>
</header>
{deleted ? (
<Alert
tone="success"
title={`Deleted “${deleted}”`}
description="This is a demo, so nothing was removed."
onDismiss={() => {
setDeleted(null);
}}
/>
) : null}
<ul className="m-0 list-none overflow-hidden rounded-xl border border-default bg-surface p-0">
{docs.map((doc) => (
<li
key={doc.id}
className="flex flex-wrap items-center gap-3 border-b border-subtle p-4 last:border-b-0"
>
<span
aria-hidden="true"
className="grid size-10 shrink-0 place-items-center rounded-md bg-sunken text-secondary"
>
<LuFileText />
</span>
<div className="grid min-w-0 flex-1 basis-40">
<a
href={`#${doc.id}`}
className="break-words text-body-strong text-primary underline underline-offset-4"
>
{doc.name}
</a>
<span className="text-body-small text-secondary">{doc.meta}</span>
</div>
<Button
size="sm"
variant="ghost"
leadingIcon={<LuTrash2 />}
onPress={() => {
setPending(doc);
setOpen(true);
}}
aria-label={`Delete ${doc.name}`}
>
Delete
</Button>
</li>
))}
{docs.length === 0 ? (
<li className="p-4 text-body-default text-secondary">No documents on this record.</li>
) : null}
</ul>
</section>
<Dialog
variant="destructive"
icon={<LuTrash2 />}
title={`Delete “${pending.name}”?`}
body="It will be removed from Luis Ortega's record and from the audit pack shared with Finance. You can't undo this."
primaryLabel="Delete document"
onPrimaryAction={confirmDelete}
secondaryLabel="Keep it"
isOpen={isOpen}
onOpenChange={setOpen}
/>
</div>
);
}
More states and system messages blocks
- Empty statesFirst use, no results and all done.
- Loading skeletonsPage and panel placeholders while data loads.
- Error pagesNot found, no access and something went wrong.
- Success confirmationA modal that confirms a finished task.
- ToastsShort confirmations with undo.
- Maintenance and offlineTell people about downtime or lost connection.
- Long-running jobProgress for exports, imports and uploads.