@@ -40,7 +40,7 @@ export async function GET(
|
|||||||
task: {
|
task: {
|
||||||
include: {
|
include: {
|
||||||
project: { select: { id: true, name: true, code: true } },
|
project: { select: { id: true, name: true, code: true } },
|
||||||
shot: { select: { shotCode: true } },
|
shot: { select: { id: true, shotCode: true, highResKey: true, highResFilename: true } },
|
||||||
asset: { select: { assetCode: true, name: true } },
|
asset: { select: { assetCode: true, name: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -78,10 +78,17 @@ export async function GET(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Resolve the shot that has the high-res file (comes from version.shot OR version.task.shot)
|
||||||
|
const highResShot = version.shot ?? (version.task as any)?.shot ?? null;
|
||||||
|
|
||||||
const serializedVersion = {
|
const serializedVersion = {
|
||||||
...version,
|
...version,
|
||||||
fileSize: version.fileSize?.toString() ?? null,
|
fileSize: version.fileSize?.toString() ?? null,
|
||||||
// Expose only whether a high-res file exists, never the storage key
|
// Top-level high-res fields so the client works for both shot and task versions
|
||||||
|
hasHighRes: !!(highResShot?.highResKey),
|
||||||
|
highResShotId: highResShot?.highResKey ? (highResShot.id ?? null) : null,
|
||||||
|
highResFilename: highResShot?.highResFilename ?? null,
|
||||||
|
// Expose only whether a high-res file exists on the shot relation, never the storage key
|
||||||
shot: version.shot
|
shot: version.shot
|
||||||
? {
|
? {
|
||||||
...version.shot,
|
...version.shot,
|
||||||
@@ -90,6 +97,17 @@ export async function GET(
|
|||||||
highResKey: undefined,
|
highResKey: undefined,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
|
task: version.task
|
||||||
|
? {
|
||||||
|
...version.task,
|
||||||
|
shot: (version.task as any)?.shot
|
||||||
|
? {
|
||||||
|
...((version.task as any).shot),
|
||||||
|
highResKey: undefined, // strip storage key
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
return NextResponse.json({ version: serializedVersion, comments });
|
return NextResponse.json({ version: serializedVersion, comments });
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ interface Version {
|
|||||||
duration: number | null;
|
duration: number | null;
|
||||||
approvalStatus: string;
|
approvalStatus: string;
|
||||||
notes: string | null;
|
notes: string | null;
|
||||||
|
// Top-level high-res flags (normalised from either shot or task.shot)
|
||||||
|
hasHighRes?: boolean;
|
||||||
|
highResShotId?: string | null;
|
||||||
|
highResFilename?: string | null;
|
||||||
shot?: {
|
shot?: {
|
||||||
id: string;
|
id: string;
|
||||||
shotCode: string;
|
shotCode: string;
|
||||||
@@ -66,7 +70,7 @@ interface Version {
|
|||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
project: { id: string; name: string; code: string };
|
project: { id: string; name: string; code: string };
|
||||||
shot?: { shotCode: string } | null;
|
shot?: { id: string; shotCode: string } | null;
|
||||||
asset?: { assetCode: string; name: string } | null;
|
asset?: { assetCode: string; name: string } | null;
|
||||||
} | null;
|
} | null;
|
||||||
}
|
}
|
||||||
@@ -205,10 +209,11 @@ export default function ClientReviewPage({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDownloadHighRes = async () => {
|
const handleDownloadHighRes = async () => {
|
||||||
if (!version?.shot?.id || !token) return;
|
const shotId = version?.highResShotId ?? version?.shot?.id;
|
||||||
|
if (!shotId || !token) return;
|
||||||
setDownloadingHighRes(true);
|
setDownloadingHighRes(true);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/client/${token}/shots/${version.shot.id}/highres/download`);
|
const res = await fetch(`/api/client/${token}/shots/${shotId}/highres/download`);
|
||||||
if (!res.ok) throw new Error("Could not get download link");
|
if (!res.ok) throw new Error("Could not get download link");
|
||||||
const { url } = await res.json();
|
const { url } = await res.json();
|
||||||
// Open the presigned URL — the Content-Disposition header forces a download
|
// Open the presigned URL — the Content-Disposition header forces a download
|
||||||
@@ -384,14 +389,14 @@ export default function ClientReviewPage({
|
|||||||
<CheckCircle2 className="h-3.5 w-3.5" />
|
<CheckCircle2 className="h-3.5 w-3.5" />
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
{version.shot?.hasHighRes && (
|
{(version.hasHighRes || version.shot?.hasHighRes) && (
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="h-8 text-xs gap-1 text-sky-400 border-sky-500/30 hover:bg-sky-500/10"
|
className="h-8 text-xs gap-1 text-sky-400 border-sky-500/30 hover:bg-sky-500/10"
|
||||||
disabled={downloadingHighRes}
|
disabled={downloadingHighRes}
|
||||||
onClick={handleDownloadHighRes}
|
onClick={handleDownloadHighRes}
|
||||||
title={version.shot.highResFilename ?? "Download high-res file"}
|
title={version.highResFilename ?? version.shot?.highResFilename ?? "Download high-res file"}
|
||||||
>
|
>
|
||||||
<Download className="h-3.5 w-3.5" />
|
<Download className="h-3.5 w-3.5" />
|
||||||
<span className="hidden sm:inline">{downloadingHighRes ? "Getting link…" : "High Res"}</span>
|
<span className="hidden sm:inline">{downloadingHighRes ? "Getting link…" : "High Res"}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user