80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import { ShotStatus, ShotApprovalStatus, TaskStatus } from "@prisma/client";
|
|
import { db } from "@/lib/db";
|
|
import type { PrismaClient } from "@prisma/client";
|
|
|
|
type TxClient = Omit<
|
|
PrismaClient,
|
|
"$connect" | "$disconnect" | "$on" | "$transaction" | "$use" | "$extends"
|
|
>;
|
|
|
|
/**
|
|
* Derive shot status from tasks + shot-level approval fields.
|
|
*
|
|
* Priority order (highest → lowest):
|
|
* 1. REVISIONS — any task is CHANGES
|
|
* 2. COMPLETE — shotApprovalStatus === CLIENT_APPROVED
|
|
* 3. CLIENT_REVIEW — shotApprovalStatus === INTERNALLY_APPROVED && sharedWithClient
|
|
* 4. READY_FOR_CLIENT — shotApprovalStatus === INTERNALLY_APPROVED && !sharedWithClient
|
|
* 5. IN_PROGRESS — any task is TODO or IN_PROGRESS
|
|
* 6. INTERNAL_REVIEW — tasks exist but none blocking, approval still PENDING
|
|
* 7. WAITING — no tasks
|
|
*/
|
|
export function deriveShotStatus(
|
|
tasks: { status: TaskStatus }[],
|
|
shotApprovalStatus: ShotApprovalStatus,
|
|
sharedWithClient: boolean
|
|
): ShotStatus {
|
|
// 1. Changes requested — highest priority
|
|
if (tasks.some((t) => t.status === "CHANGES")) return "REVISIONS";
|
|
|
|
// 2. Client approved — terminal completion state
|
|
if (shotApprovalStatus === "CLIENT_APPROVED") return "COMPLETE";
|
|
|
|
// 3 & 4. Internally approved — client-facing states
|
|
if (shotApprovalStatus === "INTERNALLY_APPROVED") {
|
|
return sharedWithClient ? "CLIENT_REVIEW" : "READY_FOR_CLIENT";
|
|
}
|
|
|
|
// 5. Active work in progress (approval still PENDING)
|
|
if (tasks.some((t) => t.status === "TODO" || t.status === "IN_PROGRESS")) {
|
|
return "IN_PROGRESS";
|
|
}
|
|
|
|
// 6. All work done, awaiting internal approval
|
|
if (tasks.length > 0) return "INTERNAL_REVIEW";
|
|
|
|
// 7. No tasks yet
|
|
return "WAITING";
|
|
}
|
|
|
|
/**
|
|
* Query all tasks + approval fields for a shot, derive the correct ShotStatus,
|
|
* and persist it. Accepts an optional Prisma transaction client (tx).
|
|
*/
|
|
export async function recalcShotStatus(
|
|
shotId: string,
|
|
tx?: TxClient
|
|
): Promise<void> {
|
|
const client = tx ?? db;
|
|
|
|
const [tasks, shot] = await Promise.all([
|
|
client.task.findMany({
|
|
where: { shotId },
|
|
select: { status: true },
|
|
}),
|
|
client.shot.findUnique({
|
|
where: { id: shotId },
|
|
select: { shotApprovalStatus: true, sharedWithClient: true },
|
|
}),
|
|
]);
|
|
|
|
if (!shot) return;
|
|
|
|
const newStatus = deriveShotStatus(tasks, shot.shotApprovalStatus, shot.sharedWithClient);
|
|
|
|
await client.shot.update({
|
|
where: { id: shotId },
|
|
data: { status: newStatus },
|
|
});
|
|
}
|