added duplicate shot
Deploy / deploy (push) Successful in 2m28s

This commit is contained in:
twotalesanimation
2026-05-20 18:20:45 +02:00
parent c801d929af
commit 05475a6c19
4 changed files with 164 additions and 3 deletions
@@ -154,7 +154,7 @@ export function ProjectTabsClient({
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
{shots.map((shot) => (
<ShotCard key={shot.id} shot={shot} projectId={projectId} />
<ShotCard key={shot.id} shot={shot} projectId={projectId} canManage={canManage} />
))}
</div>
)}
@@ -20,10 +20,12 @@ import {
Settings,
ListTodo,
Video,
Copy,
} from "lucide-react";
import type { ShotWithDetails } from "@/types";
import { ShotSettingsTab } from "@/components/shots/ShotSettingsTab";
import { FootageViewer } from "@/components/shots/FootageViewer";
import { duplicateShot } from "@/actions/shots";
const STATUS_CONFIG: Record<
string,
@@ -43,9 +45,12 @@ const PRIORITY_CONFIG: Record<string, { label: string; dot: string }> = {
CRITICAL: { label: "Critical", dot: "bg-red-500" },
};
import { useToast } from "@/components/ui/use-toast";
export default function ShotDetailPage() {
const params = useParams<{ id: string; shotId: string }>();
const router = useRouter();
const { toast } = useToast();
const [shot, setShot] = useState<ShotWithDetails | null>(null);
const [projectName, setProjectName] = useState<string>("");
const [loading, setLoading] = useState(true);
@@ -53,6 +58,7 @@ export default function ShotDetailPage() {
const [tasks, setTasks] = useState<any[]>([]);
const [artists, setArtists] = useState<any[]>([]);
const [canManage, setCanManage] = useState(false);
const [isDuplicating, setIsDuplicating] = useState(false);
const [activeTab, setActiveTab] = useState<"tasks" | "footage" | "settings">("tasks");
const fetchShot = async () => {
@@ -80,6 +86,20 @@ export default function ShotDetailPage() {
fetchShot();
}, [params.shotId]);
const handleDuplicate = async () => {
if (!shot) return;
setIsDuplicating(true);
try {
const { shot: newShot } = await duplicateShot(shot.id);
toast({ title: "Shot duplicated", description: `Created ${newShot.shotCode}` });
router.push(`/projects/${params.id}/shots/${newShot.id}`);
} catch (e) {
toast({ title: "Duplicate failed", description: e instanceof Error ? e.message : undefined, variant: "destructive" });
} finally {
setIsDuplicating(false);
}
};
if (loading) {
return (
<div className="flex items-center justify-center h-64">
@@ -172,7 +192,20 @@ export default function ShotDetailPage() {
</div>
</div>
{canManage && (
<div className="ml-auto shrink-0">
<Button
variant="outline"
size="sm"
onClick={handleDuplicate}
disabled={isDuplicating}
className="gap-2"
>
<Copy className="h-3.5 w-3.5" />
{isDuplicating ? "Duplicating…" : "Duplicate Shot"}
</Button>
</div>
)}
</div>
<Separator />