fix(review): Share with Client in the player shares the shot
Deploy / deploy (push) Successful in 4m14s

The review player's button only made the viewed version client-visible. It
never set shot.sharedWithClient, and the client portal lists only shared
shots (and only each task's latest version), so the button reported
"Shared with Client" while the client saw nothing. It also skipped the
internal approval the shot page requires.

For a version that belongs to a shot (directly or through its task), the
button now runs the shot page's shareWithClient: shot marked shared, latest
version of each task visible, status to Client Review. It is disabled with
an explanation until the shot is internally approved, and the player's
Approve Internally button now appears for task versions too, only while the
shot awaits approval. Asset versions keep the per-version share.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
twotalesanimation
2026-09-18 09:24:42 +02:00
parent 2b373737d8
commit 45459e4b12
3 changed files with 51 additions and 13 deletions
+13 -4
View File
@@ -56,6 +56,8 @@ interface ReviewPageClientProps {
shot?: {
id: string;
shotCode: string;
shotApprovalStatus: string;
sharedWithClient: boolean;
project: { id: string; name: string; code: string };
versions: {
id: string;
@@ -73,7 +75,7 @@ interface ReviewPageClientProps {
id: string;
title: string;
project: { id: string; name: string; code: string };
shot?: { id: string; shotCode: string } | null;
shot?: { id: string; shotCode: string; shotApprovalStatus: string; sharedWithClient: boolean } | null;
asset?: { id: string; assetCode: string; name: string } | null;
versions: {
id: string;
@@ -127,6 +129,11 @@ export function ReviewPageClient({
const [commentsOpen, setCommentsOpen] = useState(true);
const playerRef = useRef<ReviewPlayerRef>(null);
// The shot this version belongs to, directly or through its task. Approval
// and client sharing are shot-level: the client portal only lists shots
// marked sharedWithClient, so sharing has to go through the shot.
const reviewShot = version.shot ?? version.task?.shot ?? null;
const { toast } = useToast();
const router = useRouter();
@@ -194,7 +201,7 @@ export function ReviewPageClient({
};
const handleInternalApprove = async () => {
const shotId = version.shot?.id;
const shotId = reviewShot?.id;
if (!shotId) return;
setIsInternallyApproving(true);
try {
@@ -295,7 +302,8 @@ export function ReviewPageClient({
<ShareWithClientButton
versionId={version.id}
isAlreadyShared={version.isClientVisible}
onShared={() => {/* router.refresh() handled inside component */}}
shot={reviewShot}
onShared={() => router.refresh()}
/>
)}
@@ -320,7 +328,8 @@ export function ReviewPageClient({
<XCircle className="h-3 w-3" />
<span className="hidden sm:inline">Reject</span>
</Button>
{version.shot?.id && (
{/* Same rule as the shot page: only while the shot awaits internal approval. */}
{reviewShot?.shotApprovalStatus === "PENDING" && (
<Button
size="sm"
className="h-7 text-xs gap-1 bg-sky-600 hover:bg-sky-500 text-white"
+1 -1
View File
@@ -45,7 +45,7 @@ async function getReviewData(versionId: string) {
task: {
include: {
project: { select: { id: true, name: true, code: true } },
shot: { select: { id: true, shotCode: true } },
shot: { select: { id: true, shotCode: true, shotApprovalStatus: true, sharedWithClient: true } },
asset: { select: { id: true, assetCode: true, name: true } },
versions: {
orderBy: { versionNumber: "desc" },