csa-dashboard-sementara/csa-dashboard/app/(dashboard)/cms/buckets/page.tsx

144 lines
5.7 KiB
TypeScript

"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { DataTable } from "@/components/data-table/data-table";
import { useBucketList, useCreateBucket, useDeleteBucket } from "@/modules/cms/bucket/hooks";
import { useToast } from "@/hooks/use-toast";
import { Plus, Trash } from "lucide-react";
import { ColumnDef } from "@tanstack/react-table";
import { Bucket } from "@/modules/cms/bucket/schemas";
export default function BucketsPage() {
const { toast } = useToast();
const { data, isLoading } = useBucketList();
const createMutation = useCreateBucket();
const deleteMutation = useDeleteBucket();
const [open, setOpen] = useState(false);
const [bucketName, setBucketName] = useState("");
const [deleteBucket, setDeleteBucket] = useState<{ name: string; id: string } | null>(null);
const handleCreate = async () => {
if (!bucketName) return;
try {
await createMutation.mutateAsync({ bucketName });
toast({ title: "Bucket created", description: "Bucket created successfully" });
setOpen(false);
setBucketName("");
} catch (error) {
toast({ title: "Create failed", variant: "destructive" });
}
};
const handleDelete = async () => {
if (!deleteBucket) return;
try {
await deleteMutation.mutateAsync(deleteBucket.name);
toast({ title: "Bucket deleted", description: "Bucket has been deleted successfully" });
setDeleteBucket(null);
} catch (error) {
toast({ title: "Delete failed", variant: "destructive" });
setDeleteBucket(null);
}
};
const columns: ColumnDef<Bucket>[] = [
{ accessorKey: "name", header: "Bucket Name" },
{ accessorKey: "policy", header: "Policy" },
{
id: "actions",
cell: ({ row }) => (
<Button
variant="ghost"
size="icon"
onClick={() => setDeleteBucket({ name: row.original.name, id: row.original.name })}
>
<Trash className="h-4 w-4 text-destructive" />
</Button>
),
},
];
const buckets = data?.data || [];
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">CMS Buckets</h1>
<p className="text-muted-foreground">Manage storage buckets</p>
</div>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>
<Plus className="mr-2 h-4 w-4" />
Create Bucket
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create Bucket</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="bucketName">Bucket Name</Label>
<Input
id="bucketName"
value={bucketName}
onChange={(e) => setBucketName(e.target.value)}
placeholder="my-bucket"
/>
</div>
<Button onClick={handleCreate} disabled={createMutation.isPending}>
{createMutation.isPending ? "Creating..." : "Create"}
</Button>
</div>
</DialogContent>
</Dialog>
</div>
{isLoading ? (
<div>Loading...</div>
) : (
<DataTable columns={columns} data={buckets} searchKey="name" />
)}
<AlertDialog open={!!deleteBucket} onOpenChange={(open) => !open && setDeleteBucket(null)}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Bucket</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete bucket &quot;{deleteBucket?.name}&quot;? This action cannot be undone and will remove all data in this bucket.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={handleDelete}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
);
}