From 2020f59152a780253f5e709c387a6891be466f9f Mon Sep 17 00:00:00 2001 From: twotalesanimation <80506065+twotalesanimation@users.noreply.github.com> Date: Sun, 24 May 2026 01:13:21 +0200 Subject: [PATCH] added delete shots --- actions/shots.ts | 20 +++++++++ components/shots/ShotSettingsTab.tsx | 67 ++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/actions/shots.ts b/actions/shots.ts index ef86f21..e45ea3d 100644 --- a/actions/shots.ts +++ b/actions/shots.ts @@ -459,6 +459,26 @@ export async function removeFootagePlate(plateId: string) { return { success: true }; } +export async function deleteShot(shotId: string) { + const session = await auth(); + if (!session?.user) throw new Error("Unauthorized"); + + const role = session.user.role as string; + if (!["ADMIN", "PRODUCER", "SUPERVISOR"].includes(role)) throw new Error("Insufficient permissions"); + + const shot = await db.shot.findUnique({ + where: { id: shotId }, + select: { projectId: true }, + }); + if (!shot) throw new Error("Shot not found"); + + await db.shot.delete({ where: { id: shotId } }); + + revalidatePath(`/projects/${shot.projectId}`); + + return { success: true, projectId: shot.projectId }; +} + export async function renameFootagePlate(plateId: string, label: string) { const session = await auth(); if (!session?.user) throw new Error("Unauthorized"); diff --git a/components/shots/ShotSettingsTab.tsx b/components/shots/ShotSettingsTab.tsx index 352c2a9..152cdeb 100644 --- a/components/shots/ShotSettingsTab.tsx +++ b/components/shots/ShotSettingsTab.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useRef } from "react"; +import { useRouter } from "next/navigation"; import Image from "next/image"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -17,9 +18,9 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { updateShot } from "@/actions/shots"; +import { updateShot, deleteShot } from "@/actions/shots"; import { useToast } from "@/components/ui/use-toast"; -import { Upload, X, Film, ImageIcon } from "lucide-react"; +import { Upload, X, Film, ImageIcon, Trash2 } from "lucide-react"; const settingsSchema = z.object({ shotCode: z.string().min(1, "Required").max(120).regex(/^[A-Z0-9_]+$/i, "Alphanumeric and underscores only"), @@ -54,14 +55,18 @@ interface ShotSettingsTabProps { dueDate: Date | string | null; artistId: string | null; thumbnailUrl: string | null; + projectId: string; }; artists: Artist[]; onSaved?: () => void; } export function ShotSettingsTab({ shot, artists, onSaved }: ShotSettingsTabProps) { + const router = useRouter(); const { toast } = useToast(); const [isSaving, setIsSaving] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + const [confirmDelete, setConfirmDelete] = useState(false); const [thumbnailFile, setThumbnailFile] = useState(null); const [thumbnailPreview, setThumbnailPreview] = useState(shot.thumbnailUrl ?? null); const [clearThumbnail, setClearThumbnail] = useState(false); @@ -142,6 +147,19 @@ export function ShotSettingsTab({ shot, artists, onSaved }: ShotSettingsTabProps } }; + const handleDelete = async () => { + setIsDeleting(true); + try { + await deleteShot(shot.id); + toast({ title: "Shot deleted" }); + router.push(`/projects/${shot.projectId}`); + } catch (e) { + toast({ title: "Failed to delete shot", description: e instanceof Error ? e.message : undefined, variant: "destructive" }); + setIsDeleting(false); + setConfirmDelete(false); + } + }; + return (
@@ -302,6 +320,49 @@ export function ShotSettingsTab({ shot, artists, onSaved }: ShotSettingsTabProps {isSaving ? "Saving…" : "Save Changes"}
-
+ {/* Danger Zone */} +
+
+ + Danger Zone +
+ + {confirmDelete ? ( +
+

+ This will permanently delete {shot.shotCode} including all tasks, versions, footage, and annotations. This cannot be undone. +

+
+ + +
+
+ ) : ( + + )} +
); }