106 lines
3.5 KiB
TypeScript
106 lines
3.5 KiB
TypeScript
import { useState } from "react";
|
|
import { useTopics } from "../hooks/queries";
|
|
import { Edit, Trash2 } from "lucide-react";
|
|
import { useDeleteTopic } from "../hooks/mutations";
|
|
|
|
type PendingDelete = {
|
|
open: boolean;
|
|
topic: string;
|
|
};
|
|
|
|
export default function StateSection() {
|
|
const { data, isLoading } = useTopics();
|
|
const deleteTopic = useDeleteTopic();
|
|
const [pending, setPending] = useState<PendingDelete>({
|
|
open: false,
|
|
topic: "",
|
|
});
|
|
|
|
const handleDelete = (topic: string) => {
|
|
if (deleteTopic.isPending) return;
|
|
setPending({ open: true, topic });
|
|
};
|
|
|
|
const handleConfirmDelete = () => {
|
|
if (!pending.topic || deleteTopic.isPending) return;
|
|
deleteTopic.mutate(
|
|
{ topic: pending.topic, type: "state-reply" },
|
|
{
|
|
onSuccess: () => setPending({ open: false, topic: "" }),
|
|
onError: () => setPending({ open: false, topic: "" }),
|
|
},
|
|
);
|
|
};
|
|
|
|
const handleClose = () => {
|
|
if (deleteTopic.isPending) return;
|
|
setPending({ open: false, topic: "" });
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{isLoading &&
|
|
Array.from({ length: 3 }).map((_, index) => (
|
|
<div
|
|
key={`loading-${index}`}
|
|
className="bg-white border-b border-neutral-200 p-4 flex items-center justify-between"
|
|
>
|
|
<div className="h-4 w-40 animate-pulse rounded bg-neutral-200" />
|
|
<div className="flex gap-2">
|
|
<div className="h-4 w-4 animate-pulse rounded bg-neutral-200" />
|
|
<div className="h-4 w-4 animate-pulse rounded bg-neutral-200" />
|
|
</div>
|
|
</div>
|
|
))}
|
|
{data?.map((item, key) => (
|
|
<div
|
|
key={key}
|
|
className="bg-white border-b border-neutral-200 p-4 flex justify-between"
|
|
>
|
|
<h1>{item.topic}</h1>
|
|
<div className="flex gap-2 ">
|
|
<Edit className="text-neutral-300" size={18} />
|
|
<button
|
|
type="button"
|
|
onClick={() => handleDelete(item.topic)}
|
|
className="text-red-500 disabled:cursor-not-allowed disabled:opacity-60"
|
|
disabled={deleteTopic.isPending}
|
|
aria-label={`Hapus topic ${item.topic}`}
|
|
>
|
|
<Trash2 size={18} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
{pending.open && (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
|
|
<div className="w-full max-w-sm rounded-md bg-white p-4 shadow-lg transition-all duration-200 ease-out">
|
|
<h3 className="text-base font-semibold">Hapus Topic</h3>
|
|
<p className="mt-2 text-sm text-neutral-600">
|
|
Yakin ingin menghapus topic "{pending.topic}"?
|
|
</p>
|
|
<div className="mt-4 flex justify-end gap-2">
|
|
<button
|
|
type="button"
|
|
onClick={handleClose}
|
|
className="rounded-md border border-neutral-300 px-4 py-2 text-sm"
|
|
disabled={deleteTopic.isPending}
|
|
>
|
|
Batal
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={handleConfirmDelete}
|
|
className="rounded-md bg-red-500 px-4 py-2 text-sm text-white disabled:cursor-not-allowed disabled:opacity-70"
|
|
disabled={deleteTopic.isPending}
|
|
>
|
|
{deleteTopic.isPending ? "Menghapus..." : "Hapus"}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
}
|