@@ -90,6 +90,100 @@ export async function createShot(data: z.infer<typeof createShotSchema>) {
|
||||
return { success: true, shot };
|
||||
}
|
||||
|
||||
// ── Duplicate Shot ────────────────────────────────────────────────────────────
|
||||
|
||||
export async function duplicateShot(sourceShotId: string) {
|
||||
const session = await auth();
|
||||
if (!session?.user) throw new Error("Unauthorized");
|
||||
if (!["ADMIN", "PRODUCER", "SUPERVISOR"].includes(session.user.role)) {
|
||||
throw new Error("Insufficient permissions");
|
||||
}
|
||||
|
||||
// Load source shot with tasks
|
||||
const source = await db.shot.findUnique({
|
||||
where: { id: sourceShotId },
|
||||
include: {
|
||||
tasks: {
|
||||
select: {
|
||||
title: true,
|
||||
description: true,
|
||||
type: true,
|
||||
priority: true,
|
||||
estimatedHours: true,
|
||||
sortOrder: true,
|
||||
dueDate: true,
|
||||
assignedArtistId: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!source) throw new Error("Shot not found");
|
||||
|
||||
const project = await db.project.findUnique({
|
||||
where: { id: source.projectId },
|
||||
select: { showId: true, projectType: true },
|
||||
});
|
||||
if (!project?.showId) throw new Error("Project has no Show ID");
|
||||
|
||||
// Determine next shot number in same scene/episode scope
|
||||
const scopeWhere = {
|
||||
projectId: source.projectId,
|
||||
scene: source.scene,
|
||||
...(project.projectType === "EPISODIC" ? { episode: source.episode } : {}),
|
||||
};
|
||||
|
||||
const maxShot = await db.shot.findFirst({
|
||||
where: scopeWhere,
|
||||
orderBy: { shotNumber: "desc" },
|
||||
select: { shotNumber: true },
|
||||
});
|
||||
|
||||
const shotNumber = (maxShot?.shotNumber ?? 0) + 10;
|
||||
const paddedNumber = shotNumber.toString().padStart(4, "0");
|
||||
|
||||
const shotCode =
|
||||
project.projectType === "EPISODIC" && source.episode
|
||||
? `${project.showId}_${source.episode}_${source.scene}_${paddedNumber}`
|
||||
: `${project.showId}_${source.scene}_${paddedNumber}`;
|
||||
|
||||
const newShot = await db.shot.create({
|
||||
data: {
|
||||
shotCode,
|
||||
scene: source.scene,
|
||||
episode: source.episode,
|
||||
shotNumber,
|
||||
sequence: source.sequence,
|
||||
description: source.description,
|
||||
projectId: source.projectId,
|
||||
artistId: source.artistId,
|
||||
priority: source.priority,
|
||||
fps: source.fps,
|
||||
frameStart: source.frameStart,
|
||||
frameEnd: source.frameEnd,
|
||||
dueDate: source.dueDate,
|
||||
thumbnailUrl: source.thumbnailUrl,
|
||||
// Duplicate tasks — reset status and schedule fields
|
||||
tasks: {
|
||||
create: source.tasks.map((t) => ({
|
||||
title: t.title,
|
||||
description: t.description,
|
||||
type: t.type,
|
||||
priority: t.priority,
|
||||
estimatedHours: t.estimatedHours,
|
||||
sortOrder: t.sortOrder,
|
||||
dueDate: t.dueDate,
|
||||
assignedArtistId: t.assignedArtistId,
|
||||
projectId: source.projectId,
|
||||
status: "TODO" as const,
|
||||
})),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
revalidatePath(`/projects/${source.projectId}`);
|
||||
return { success: true, shot: newShot };
|
||||
}
|
||||
|
||||
// ── Update Shot ───────────────────────────────────────────────────────────────
|
||||
|
||||
const updateShotSchema = z.object({
|
||||
|
||||
Reference in New Issue
Block a user