Add delete to commission types and fix dragging

This commit is contained in:
2025-07-06 22:21:03 +02:00
parent 80891d152d
commit 34f3735f7f
4 changed files with 144 additions and 69 deletions

View File

@ -0,0 +1,19 @@
"use server"
import prisma from "@/lib/prisma"
export async function deleteCommissionType(typeId: string) {
await prisma.commissionTypeOption.deleteMany({
where: { typeId },
})
await prisma.commissionTypeExtra.deleteMany({
where: { typeId },
})
await prisma.commissionType.delete({
where: { id: typeId },
})
}

View File

@ -26,7 +26,7 @@ export default async function CommissionTypesEditPage({ params }: { params: { id
return ( return (
<div> <div>
<div className="flex gap-4 justify-between pb-8"> <div className="flex gap-4 justify-between pb-8">
<h1 className="text-2xl font-bold mb-4">New Commission Type</h1> <h1 className="text-2xl font-bold mb-4">Edit Commission Type</h1>
</div> </div>
<EditTypeForm type={commissionType} allOptions={options} allExtras={extras} /> <EditTypeForm type={commissionType} allOptions={options} allExtras={extras} />
</div> </div>

View File

@ -29,11 +29,15 @@ export default function SortableItemCard({ id, children }: Props) {
return ( return (
<div <div
ref={setNodeRef} ref={setNodeRef}
style={style} style={style}>
<div
{...attributes} {...attributes}
{...listeners} {...listeners}
className="cursor-grab" className="cursor-grab px-2 py-1 text-sm text-muted-foreground"
title="Drag to reorder"
> >
</div>
{children} {children}
</div> </div>
) )

View File

@ -1,8 +1,11 @@
"use client" "use client"
import { deleteCommissionType } from "@/actions/items/commissions/types/deleteType";
import { updateCommissionTypeSortOrder } from "@/actions/items/commissions/types/updateCommissionTypeSortOrder"; import { updateCommissionTypeSortOrder } from "@/actions/items/commissions/types/updateCommissionTypeSortOrder";
import SortableItemCard from "@/components/drag/SortableItemCard"; import SortableItemCard from "@/components/drag/SortableItemCard";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { CommissionExtra, CommissionOption, CommissionType, CommissionTypeExtra, CommissionTypeOption } from "@/generated/prisma"; import { CommissionExtra, CommissionOption, CommissionType, CommissionTypeExtra, CommissionTypeOption } from "@/generated/prisma";
import { import {
closestCenter, closestCenter,
@ -17,9 +20,9 @@ import {
rectSortingStrategy, rectSortingStrategy,
SortableContext SortableContext
} from "@dnd-kit/sortable"; } from "@dnd-kit/sortable";
import { PencilIcon } from "lucide-react"; import { PencilIcon, TrashIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useEffect, useState } from "react"; import { useEffect, useState, useTransition } from "react";
type CommissionTypeWithItems = CommissionType & { type CommissionTypeWithItems = CommissionType & {
options: (CommissionTypeOption & { options: (CommissionTypeOption & {
@ -33,6 +36,9 @@ type CommissionTypeWithItems = CommissionType & {
export default function ListTypes({ types }: { types: CommissionTypeWithItems[] }) { export default function ListTypes({ types }: { types: CommissionTypeWithItems[] }) {
const [items, setItems] = useState(types) const [items, setItems] = useState(types)
const [isMounted, setIsMounted] = useState(false) const [isMounted, setIsMounted] = useState(false)
const [dialogOpen, setDialogOpen] = useState(false)
const [deleteTargetId, setDeleteTargetId] = useState<string | null>(null)
const [isPending, startTransition] = useTransition()
useEffect(() => { useEffect(() => {
setIsMounted(true) setIsMounted(true)
@ -56,9 +62,20 @@ export default function ListTypes({ types }: { types: CommissionTypeWithItems[]
} }
} }
const confirmDelete = () => {
if (!deleteTargetId) return
startTransition(async () => {
await deleteCommissionType(deleteTargetId)
setItems((prev) => prev.filter((i) => i.id !== deleteTargetId))
setDialogOpen(false)
setDeleteTargetId(null)
})
}
if (!isMounted) return null if (!isMounted) return null
return ( return (
<>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}> <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<SortableContext items={items.map((i) => i.id)} strategy={rectSortingStrategy}> <SortableContext items={items.map((i) => i.id)} strategy={rectSortingStrategy}>
@ -106,14 +123,27 @@ export default function ListTypes({ types }: { types: CommissionTypeWithItems[]
</ul> </ul>
</div> </div>
</CardContent> </CardContent>
<CardFooter className="flex items-center justify-between"> <CardFooter className="flex flex-col gap-2">
<Link <Link
href={`/items/commissions/types/${type.id}/edit`} href={`/items/commissions/types/${type.id}/edit`}
className="text-sm text-primary hover:underline flex items-center gap-1" className="w-full"
> >
<Button variant="default" className="w-full flex items-center gap-2">
<PencilIcon className="h-4 w-4" /> <PencilIcon className="h-4 w-4" />
Edit Edit
</Button>
</Link> </Link>
<Button
variant="destructive"
className="w-full flex items-center gap-2"
onClick={() => {
setDeleteTargetId(type.id)
setDialogOpen(true)
}}
>
<TrashIcon className="h-4 w-4" />
Delete
</Button>
</CardFooter> </CardFooter>
</Card> </Card>
</SortableItemCard > </SortableItemCard >
@ -121,5 +151,27 @@ export default function ListTypes({ types }: { types: CommissionTypeWithItems[]
</SortableContext> </SortableContext>
</DndContext> </DndContext>
</div > </div >
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete this commission type?</DialogTitle>
</DialogHeader>
<p>This action cannot be undone. Are you sure you want to continue?</p>
<DialogFooter>
<Button variant="outline" onClick={() => setDialogOpen(false)}>
Cancel
</Button>
<Button
variant="destructive"
disabled={isPending}
onClick={confirmDelete}
>
Confirm Delete
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
); );
} }