RJBULK-APP/components/tables/delivery-notes-table-actions.tsx
SJCoetz 1efa979443 feat: initial setup of rj bulk supplies backoffice app
Adds complete initial codebase for the RJ Bulk Supplies fuel delivery backoffice:
- Authentication pages and protected route layouts
- Customer, supplier, fuel purchase, and delivery note management
- Custom reporting and customer statement sending tools
- Full UI component library and Tailwind styling
- Server actions, API routes, and PocketBase integration
- Development scripts and project configuration updates
- Updated README and package metadata
2026-07-19 20:38:16 +02:00

137 lines
4.3 KiB
TypeScript

"use client";
import { useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { MoreHorizontal, Eye, Pencil, Trash2, CheckCheck } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Select } from "@/components/ui/select";
import { deleteDeliveryNote, updateStatus } from "@/actions/delivery-notes";
import { DELIVERY_STATUSES, type DeliveryStatus } from "@/lib/types";
import { toast } from "sonner";
import Link from "next/link";
interface Props {
id: string;
status?: string;
}
export function DeliveryNotesTableActions({ id, status }: Props) {
const router = useRouter();
const [statusOpen, setStatusOpen] = useState(false);
const [deleteOpen, setDeleteOpen] = useState(false);
const [newStatus, setNewStatus] = useState(status || "Pending");
const [pending, startTransition] = useTransition();
function onUpdateStatus() {
startTransition(async () => {
const res = await updateStatus(id, newStatus);
if (res.ok) {
toast.success("Status updated");
setStatusOpen(false);
router.refresh();
} else {
toast.error(res.error);
}
});
}
function onDelete() {
startTransition(async () => {
const res = await deleteDeliveryNote(id);
if (res.ok) {
toast.success("Note deleted");
setDeleteOpen(false);
router.refresh();
} else {
toast.error(res.error);
}
});
}
return (
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem asChild>
<Link href={`/delivery-notes/${id}`}>
<Eye className="mr-2 h-4 w-4" /> View
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href={`/delivery-notes/${id}/edit`}>
<Pencil className="mr-2 h-4 w-4" /> Edit
</Link>
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setStatusOpen(true)}>
<CheckCheck className="mr-2 h-4 w-4" /> Update status
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => setDeleteOpen(true)} className="text-destructive focus:text-destructive">
<Trash2 className="mr-2 h-4 w-4" /> Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Dialog open={statusOpen} onOpenChange={setStatusOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Update status</DialogTitle>
<DialogDescription>Change the status of this delivery note.</DialogDescription>
</DialogHeader>
<div className="py-2">
<Select
value={newStatus}
onChange={(e) => setNewStatus(e.target.value)}
options={DELIVERY_STATUSES.map((s) => ({ value: s, label: s }))}
/>
</div>
<DialogFooter>
<Button variant="ghost" onClick={() => setStatusOpen(false)} disabled={pending}>
Cancel
</Button>
<Button onClick={onUpdateStatus} disabled={pending}>
{pending ? "Saving…" : "Update"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog open={deleteOpen} onOpenChange={setDeleteOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete this delivery note?</DialogTitle>
<DialogDescription>This cannot be undone.</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="ghost" onClick={() => setDeleteOpen(false)} disabled={pending}>
Cancel
</Button>
<Button variant="destructive" onClick={onDelete} disabled={pending}>
{pending ? "Deleting…" : "Delete"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}