@@ -392,3 +392,90 @@ export async function getShotsByProject(projectId: string) {
|
||||
orderBy: [{ sequence: "asc" }, { shotCode: "asc" }],
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Footage Plates ────────────────────────────────────────────────────────────
|
||||
|
||||
const addFootagePlateSchema = z.object({
|
||||
shotId: z.string().min(1),
|
||||
fileUrl: z.string().url(),
|
||||
fileKey: z.string().default(""),
|
||||
fileName: z.string().default(""),
|
||||
fileSize: z.number().int().positive().optional(),
|
||||
label: z.string().max(100).default(""),
|
||||
});
|
||||
|
||||
export async function addFootagePlate(raw: unknown) {
|
||||
const session = await auth();
|
||||
if (!session?.user) throw new Error("Unauthorized");
|
||||
|
||||
const data = addFootagePlateSchema.parse(raw);
|
||||
|
||||
// Determine next sortOrder
|
||||
const last = await db.footagePlate.findFirst({
|
||||
where: { shotId: data.shotId },
|
||||
orderBy: { sortOrder: "desc" },
|
||||
select: { sortOrder: true },
|
||||
});
|
||||
|
||||
const plate = await db.footagePlate.create({
|
||||
data: {
|
||||
shotId: data.shotId,
|
||||
fileUrl: data.fileUrl,
|
||||
fileKey: data.fileKey,
|
||||
fileName: data.fileName,
|
||||
fileSize: data.fileSize != null ? BigInt(data.fileSize) : null,
|
||||
label: data.label,
|
||||
sortOrder: (last?.sortOrder ?? -1) + 1,
|
||||
},
|
||||
});
|
||||
|
||||
const shot = await db.shot.findUnique({ where: { id: data.shotId }, select: { projectId: true } });
|
||||
if (shot) {
|
||||
revalidatePath(`/projects/${shot.projectId}`);
|
||||
revalidatePath(`/projects/${shot.projectId}/shots/${data.shotId}`);
|
||||
}
|
||||
|
||||
return { success: true, plate: { ...plate, fileSize: plate.fileSize?.toString() ?? null } };
|
||||
}
|
||||
|
||||
export async function removeFootagePlate(plateId: 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 plate = await db.footagePlate.findUnique({
|
||||
where: { id: plateId },
|
||||
include: { shot: { select: { projectId: true } } },
|
||||
});
|
||||
if (!plate) throw new Error("Plate not found");
|
||||
|
||||
await db.footagePlate.delete({ where: { id: plateId } });
|
||||
|
||||
revalidatePath(`/projects/${plate.shot.projectId}`);
|
||||
revalidatePath(`/projects/${plate.shot.projectId}/shots/${plate.shotId}`);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
export async function renameFootagePlate(plateId: string, label: 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 trimmed = label.trim().slice(0, 100);
|
||||
|
||||
const plate = await db.footagePlate.update({
|
||||
where: { id: plateId },
|
||||
data: { label: trimmed },
|
||||
include: { shot: { select: { projectId: true } } },
|
||||
});
|
||||
|
||||
revalidatePath(`/projects/${plate.shot.projectId}`);
|
||||
revalidatePath(`/projects/${plate.shot.projectId}/shots/${plate.shotId}`);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user