diff --git a/components/shoot-log/NewSetupDialog.tsx b/components/shoot-log/NewSetupDialog.tsx index f94a92b..4bc2fab 100644 --- a/components/shoot-log/NewSetupDialog.tsx +++ b/components/shoot-log/NewSetupDialog.tsx @@ -26,7 +26,7 @@ interface Props { shootDayId: string; open: boolean; onOpenChange: (open: boolean) => void; - onCreated: (setup: { id: string; name: string }) => void; + onCreated: (setup: { id: string; name: string }) => Promise | void; } export function NewSetupDialog({ shootDayId, open, onOpenChange, onCreated }: Props) { diff --git a/components/shoot-log/NewShootDayDialog.tsx b/components/shoot-log/NewShootDayDialog.tsx index a90906f..8de98ab 100644 --- a/components/shoot-log/NewShootDayDialog.tsx +++ b/components/shoot-log/NewShootDayDialog.tsx @@ -30,7 +30,7 @@ interface Props { projectId: string; open: boolean; onOpenChange: (open: boolean) => void; - onCreate: (day: { id: string; date: string; unit: string; label: string | null }) => void; + onCreate: (day: { id: string; date: string; unit: string; label: string | null }) => Promise | void; } export function NewShootDayDialog({ projectId, open, onOpenChange, onCreate }: Props) { diff --git a/components/shoot-log/ShootLogClient.tsx b/components/shoot-log/ShootLogClient.tsx index cbfa8a2..66661c4 100644 --- a/components/shoot-log/ShootLogClient.tsx +++ b/components/shoot-log/ShootLogClient.tsx @@ -1,9 +1,8 @@ "use client"; -import { useState, useCallback, useRef } from "react"; +import { useState, useCallback } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { Clapperboard, Loader2 } from "lucide-react"; -import { cn } from "@/lib/utils"; import { TakeListPanel } from "./TakeListPanel"; import { TakeEditorPanel, type FullTake } from "./TakeEditorPanel"; import { NewShootDayDialog } from "./NewShootDayDialog"; @@ -24,17 +23,23 @@ interface Props { } export function ShootLogClient({ projects }: Props) { + const queryClient = useQueryClient(); + const [projectId, setProjectId] = useState(projects[0]?.id ?? ""); const [selectedTakeId, setSelectedTakeId] = useState(null); const [selectedSetupId, setSelectedSetupId] = useState(null); + // Which day to auto-expand in the left panel after creation + const [expandDayId, setExpandDayId] = useState(null); + // Dialog state const [newDayOpen, setNewDayOpen] = useState(false); const [newSetupDayId, setNewSetupDayId] = useState(null); - // Refresh token to force TakeListPanel to refetch - const [refreshToken, setRefreshToken] = useState(0); - const refresh = useCallback(() => setRefreshToken((t) => t + 1), []); + // ── Invalidate the days list ─────────────────────────────────────────────── + const invalidateDays = useCallback(() => { + queryClient.invalidateQueries({ queryKey: ["shoot-log-days", projectId] }); + }, [queryClient, projectId]); // ── Fetch selected take ──────────────────────────────────────────────────── const { data: takeData, isLoading: takeLoading } = useQuery<{ take: FullTake }>({ @@ -74,7 +79,7 @@ export function ShootLogClient({ projects }: Props) { const prevTakeNav = currentIdx > 0 ? allTakesInSetup[currentIdx - 1] : null; const nextTakeNav = currentIdx < allTakesInSetup.length - 1 ? allTakesInSetup[currentIdx + 1] : null; - // ── Actions ──────────────────────────────────────────────────────────────── + // ── Create a take ────────────────────────────────────────────────────────── const createTake = useCallback( async (setupId: string, initialData?: object) => { const res = await fetch(`/api/shoot-log/setups/${setupId}/takes`, { @@ -83,34 +88,78 @@ export function ShootLogClient({ projects }: Props) { body: JSON.stringify(initialData ?? {}), }); if (!res.ok) throw new Error("Failed to create take"); - const { take } = await res.json(); - refresh(); - setSelectedTakeId(take.id); + const { take: newTake } = await res.json(); + invalidateDays(); + setSelectedTakeId(newTake.id); setSelectedSetupId(setupId); }, - [refresh] + [invalidateDays] ); + // ── After shoot day creation: auto-create Setup A + Take 1 ──────────────── + const handleDayCreated = useCallback( + async (day: { id: string }) => { + try { + // Create Setup A + const setupRes = await fetch(`/api/shoot-log/days/${day.id}/setups`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name: "A" }), + }); + if (!setupRes.ok) throw new Error(); + const { setup } = await setupRes.json(); + + // Create Take 1 + const takeRes = await fetch(`/api/shoot-log/setups/${setup.id}/takes`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({}), + }); + if (!takeRes.ok) throw new Error(); + const { take: newTake } = await takeRes.json(); + + invalidateDays(); + setExpandDayId(day.id); + setSelectedTakeId(newTake.id); + setSelectedSetupId(setup.id); + } catch { + // Day was created but setup/take failed — still refresh + invalidateDays(); + setExpandDayId(day.id); + } + }, + [invalidateDays] + ); + + // ── After new setup creation ─────────────────────────────────────────────── + const handleSetupCreated = useCallback( + async (setup: { id: string }) => { + invalidateDays(); + setNewSetupDayId(null); + await createTake(setup.id); + }, + [invalidateDays, createTake] + ); + + // ── Duplicate take ───────────────────────────────────────────────────────── const handleDuplicate = useCallback(async () => { if (!take) return; - // Build initial data from current take (omit id, notes, attachments) - const { id, takeNumber, attachments, setup, createdById, createdAt, updatedAt, ...rest } = take as FullTake & Record; - void id; void takeNumber; void attachments; void setup; void createdById; void createdAt; void updatedAt; - - // Increment clip name + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { id, takeNumber, attachments, setup, createdById, createdAt, updatedAt, ...rest } = + take as FullTake & Record; const clipName = incrementClipName(take.clipName); const initial = { ...rest, clipName, supervisorNotes: null, continuityNotes: null, vfxRequirements: null }; - await createTake(take.setupId, initial); }, [take, createTake]); + // ── Delete take ──────────────────────────────────────────────────────────── const handleDelete = useCallback(async () => { if (!selectedTakeId) return; if (!confirm("Delete this take? This cannot be undone.")) return; await fetch(`/api/shoot-log/takes/${selectedTakeId}`, { method: "DELETE" }); setSelectedTakeId(null); - refresh(); - }, [selectedTakeId, refresh]); + invalidateDays(); + }, [selectedTakeId, invalidateDays]); // ── Render ───────────────────────────────────────────────────────────────── if (!projectId) { @@ -132,10 +181,11 @@ export function ShootLogClient({ projects }: Props) {