Capture canvas preview when admin sends design to customer

Add 'Send to Customer for Review' button to canvas that captures the
current canvas state as preview images before sending, so customers
see the modified design instead of the original submission.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andymick
2026-07-18 19:19:38 +01:00
co-authored by Claude Haiku 4.5
parent b97d015cd1
commit 87b269e57c
3 changed files with 76 additions and 16 deletions
+62 -2
View File
@@ -493,12 +493,14 @@ export default function DesignCanvas({
initialDesignJson,
initialColor,
initialSize,
designId,
}: {
product: ProductDTO;
isAdminEditing?: boolean;
initialDesignJson?: string;
initialColor?: string;
initialSize?: string | null;
designId?: string;
}) {
const [color, setColor] = useState(initialColor ?? product.colors[0]);
const [size, setSize] = useState<string | null>(initialSize ?? (product.sizes[0] ?? null));
@@ -1037,6 +1039,52 @@ export default function DesignCanvas({
});
};
const handleSendToCustomerForReview = async (id: string) => {
if (!stageBackRef.current || !stageFrontRef.current) return;
setSubmittingForApproval(true);
try {
// Capture front preview
const frontStage = stageFrontRef.current;
const frontGuides = frontStage.find('.printGuide');
frontGuides.forEach((g) => g.hide());
const frontDataUrl = frontStage.toDataURL({ pixelRatio: 2 });
frontGuides.forEach((g) => g.show());
// Capture back preview if exists
let backDataUrl: string | null = null;
if (hasBack && stageBackRef.current) {
const backStage = stageBackRef.current;
const backGuides = backStage.find('.printGuide');
backGuides.forEach((g) => g.hide());
backDataUrl = backStage.toDataURL({ pixelRatio: 2 });
backGuides.forEach((g) => g.show());
}
// Send to API with the new preview images
const res = await fetch(`/api/designs/${id}/send-to-customer`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
designPreviewUrl: frontDataUrl,
designPreviewUrlBack: backDataUrl,
}),
});
if (res.ok) {
setSubmissionMessage('✓ Design sent to customer for review!');
setTimeout(() => setSubmissionMessage(null), 5000);
} else {
setSubmissionMessage('✗ Failed to send design');
}
} catch (err) {
console.error('Error sending design:', err);
setSubmissionMessage('✗ Error sending design');
} finally {
setSubmittingForApproval(false);
}
};
function renderPhoto(v: 'front' | 'back') {
const colorPhoto = v === 'front' ? product.colorPhotos[color] : product.colorPhotosBack[color];
if (colorPhoto) {
@@ -1564,12 +1612,24 @@ export default function DesignCanvas({
>
Add to bag <Price cents={((elementsFront.length > 0 || elementsBack.length > 0) ? effectivePriceForPersonalised : product.effectivePrice) * quantity} />
</button>
) : isAdminEditing ? (
<button
onClick={() => handleSendToCustomerForReview(params?.id || '')}
disabled={submittingForApproval}
className={`flex-1 px-6 py-3 text-sm font-medium transition-colors ${
submittingForApproval
? 'bg-muted text-muted/50 cursor-not-allowed'
: 'bg-clay text-paper hover:bg-clay-dark'
}`}
>
{submittingForApproval ? 'Sending…' : 'Send to Customer for Review'}
</button>
) : (
<button
onClick={handleSubmitForApproval}
disabled={isAdminEditing || elementsFront.length === 0 && elementsBack.length === 0 || submittingForApproval || approvalStatus === 'PENDING'}
disabled={elementsFront.length === 0 && elementsBack.length === 0 || submittingForApproval || approvalStatus === 'PENDING'}
className={`flex-1 px-6 py-3 text-sm font-medium transition-colors ${
isAdminEditing || elementsFront.length === 0 && elementsBack.length === 0 || submittingForApproval || approvalStatus === 'PENDING'
elementsFront.length === 0 && elementsBack.length === 0 || submittingForApproval || approvalStatus === 'PENDING'
? 'bg-muted text-muted/50 cursor-not-allowed'
: 'bg-clay text-paper hover:bg-clay-dark'
}`}