138 lines
7.4 KiB
TypeScript
138 lines
7.4 KiB
TypeScript
import React, { useRef, useState, forwardRef, useImperativeHandle } from 'react';
|
|
import { toPng } from 'html-to-image';
|
|
import axios from 'axios';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
interface ProcessGuideGeneratorProps {
|
|
projectId?: string;
|
|
project?: { id: string } | null; // Alternative to projectId
|
|
onImageGenerated?: (path: string) => void;
|
|
onGenerate?: () => void; // Alias for backward compatibility
|
|
shopName?: string;
|
|
}
|
|
|
|
export interface ProcessGuideRef {
|
|
generate: () => Promise<void>;
|
|
}
|
|
|
|
export const ProcessGuideGenerator = forwardRef<ProcessGuideRef, ProcessGuideGeneratorProps>(({ projectId, project, onImageGenerated, onGenerate, shopName = "MrStitchPrintStudio" }, ref) => {
|
|
const resolvedProjectId = projectId || project?.id;
|
|
const { t } = useTranslation();
|
|
const elementRef = useRef<HTMLDivElement>(null);
|
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
generate: handleGenerate
|
|
}));
|
|
|
|
const handleGenerate = async () => {
|
|
if (!elementRef.current) return;
|
|
setIsGenerating(true);
|
|
|
|
try {
|
|
// Give fonts time to load visually if needed, though usually not an issue with simple fonts
|
|
const dataUrl = await toPng(elementRef.current, { cacheBust: true, pixelRatio: 1 });
|
|
|
|
// Upload to server
|
|
const response = await axios.post(`/api/projects/${projectId}/assets/upload`, {
|
|
file: dataUrl,
|
|
type: 'mockup', // Treated as mockup
|
|
folder: 'mockups',
|
|
filename: `process_guide_${Date.now()}.png`
|
|
}, {
|
|
headers: {
|
|
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
|
}
|
|
});
|
|
|
|
if (response.data.success) {
|
|
onImageGenerated(response.data.asset.path);
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error('Failed to generate process guide:', err);
|
|
throw err; // Re-throw to let parent know
|
|
} finally {
|
|
setIsGenerating(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="relative overflow-hidden w-[500px] h-[500px] bg-white">
|
|
{/* This container is what gets captured. It must be visible in DOM but can be hidden by parent overflow/opacity. */}
|
|
{/* We strictly render ONLY the capture content here. Extra UI is removed. */}
|
|
<div
|
|
ref={elementRef}
|
|
className="w-[500px] h-[500px] bg-[#F5EBE0] text-[#4A3B32] flex flex-col items-center justify-between p-12 shrink-0"
|
|
style={{ fontFamily: 'Inter, sans-serif' }}
|
|
>
|
|
{/* HEADER */}
|
|
<h1 className="text-4xl font-bold uppercase tracking-wide mt-4">HOW IT WORKS</h1>
|
|
|
|
{/* STEPS ROW */}
|
|
<div className="flex justify-between w-full mt-8">
|
|
{/* STEP 1 */}
|
|
<div className="flex flex-col items-center text-center w-1/3 px-2">
|
|
<div className="mb-4">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-16 h-16">
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 3h1.386c.51 0 .955.343 1.087.835l.383 1.437M7.5 14.25a3 3 0 0 0-3 3h15.75m-12.75-3h11.218c1.121-2.3 2.1-4.684 2.924-7.138a60.114 60.114 0 0 0-16.536-1.84M7.5 14.25 5.106 5.272M6 20.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm12.75 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="font-bold text-lg mb-1">ADD TO CART</h3>
|
|
<p className="text-xs leading-tight opacity-80">Select your digital product and add it to your cart.</p>
|
|
</div>
|
|
|
|
{/* STEP 2 */}
|
|
<div className="flex flex-col items-center text-center w-1/3 px-2 border-l border-r border-[#4A3B32]/10">
|
|
<div className="mb-4">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-16 h-16">
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="font-bold text-lg mb-1">CHECKOUT</h3>
|
|
<p className="text-xs leading-tight opacity-80">Complete payment to securely confirm your purchase.</p>
|
|
</div>
|
|
|
|
{/* STEP 3 */}
|
|
<div className="flex flex-col items-center text-center w-1/3 px-2">
|
|
<div className="mb-4">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-16 h-16">
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="font-bold text-lg mb-1">DOWNLOAD</h3>
|
|
<p className="text-xs leading-tight opacity-80">Access your download link in the receipt email.</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* IMPORTANT NOTICE */}
|
|
<div className="w-full text-left mt-8">
|
|
<h4 className="font-bold uppercase text-sm mb-1">IMPORTANT:</h4>
|
|
<p className="text-xs">• This is an <span className="font-bold">INSTANT DOWNLOAD</span>. No physical items will be shipped or sent.</p>
|
|
</div>
|
|
|
|
{/* FOOTER */}
|
|
<div className="relative mt-auto w-full">
|
|
{/* Speech Bubble effect */}
|
|
<div className="bg-white/50 p-6 rounded-2xl relative">
|
|
<h4 className="font-bold text-sm mb-2">Thank you for stopping by!</h4>
|
|
<p className="text-[10px] leading-relaxed opacity-90">
|
|
Our goal is to create products that inspire, uplift, and add a touch of positivity to your life.
|
|
We hope you find joy in our products, and if you have any questions or feedback, we'd love to hear from you!
|
|
</p>
|
|
{/* Triangle */}
|
|
<div className="absolute -bottom-3 left-8 w-0 h-0 border-l-[10px] border-l-transparent border-t-[15px] border-t-white/50 border-r-[10px] border-r-transparent"></div>
|
|
</div>
|
|
|
|
<div className="mt-6 ml-8 font-bold text-sm opacity-80">
|
|
{shopName}
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|
|
|
|
ProcessGuideGenerator.displayName = 'ProcessGuideGenerator';
|