import { useState, useRef, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogOverlay, } from "./ui/dialog"; import { Button } from "./ui/button"; import { Sparkles, Upload, ImageIcon, X, Download, RotateCcw, CheckCircle, Share2, } from "lucide-react"; import { useRootData, useAuthToken } from "../hooks/use-root-data"; import { LoginRequiredDialog } from "./LoginRequiredDialog"; import { useMutation } from "@tanstack/react-query"; import { getApiBaseUrl } from "~/utils/api-config"; interface AIPromoteModalProps { isOpen: boolean; onClose: () => void; collectionId?: string; productId?: string; } export default function AIPromoteModal({ isOpen, onClose, collectionId, productId, }: AIPromoteModalProps) { const isProductMode = !!productId; const { user } = useRootData(); const token = useAuthToken(); const [selectedImage, setSelectedImage] = useState(null); const [imagePreview, setImagePreview] = useState(null); const [resultImage, setResultImage] = useState(null); const [isUploading, setIsUploading] = useState(false); const [isLoginDialogOpen, setIsLoginDialogOpen] = useState(false); const [loadingStep, setLoadingStep] = useState(0); const fileInputRef = useRef(null); // Loading steps messages const loadingSteps = [ { text: "در حال آماده‌سازی لباس...", icon: "👗" }, { text: "در حال اندازه‌گیری سایز شما...", icon: "📏" }, { text: "در حال دوختن لباس به اندازه شما...", icon: "✂️" }, { text: "در حال اتو کردن و مرتب کردن...", icon: "✨" }, { text: "در حال پرو کردن روی شما...", icon: "🎯" }, { text: "تقریباً آماده شده یخورده هم صبر کن...", icon: "⏳" }, ]; // Cycle through loading steps useEffect(() => { if (!isUploading) { setLoadingStep(0); return; } const interval = setInterval(() => { setLoadingStep((prev) => { // Stay on last step if we've gone through all if (prev >= loadingSteps.length - 1) return prev; return prev + 1; }); }, 4000); return () => clearInterval(interval); }, [isUploading, loadingSteps.length]); // AI Try-on mutation for collection const tryOnCollectionMutation = useMutation({ mutationFn: async ({ image, collectionId, }: { image: Blob; collectionId: string; }) => { if (!token) throw new Error("Authentication required"); const baseUrl = getApiBaseUrl(); const formData = new FormData(); formData.append("collection_id", collectionId); formData.append("image", image); const response = await fetch(`${baseUrl}/api/aifit/v1/try-on/`, { method: "POST", headers: { Authorization: `Bearer ${token}`, }, body: formData, }); if (!response.ok) { throw new Error(`API error: ${response.status}`); } // Response is binary PNG, convert to blob URL const blob = await response.blob(); return URL.createObjectURL(blob); }, }); // AI Try-on mutation for product const tryOnProductMutation = useMutation({ mutationFn: async ({ image, productId, }: { image: Blob; productId: string; }) => { if (!token) throw new Error("Authentication required"); const baseUrl = getApiBaseUrl(); const formData = new FormData(); formData.append("product_id", productId); formData.append("image", image); // AI processing can take a while, set 2 minute timeout const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 120000); try { const response = await fetch( `${baseUrl}/api/aifit/v1/try-on/product/`, { method: "POST", headers: { Authorization: `Bearer ${token}`, }, body: formData, signal: controller.signal, } ); clearTimeout(timeoutId); if (!response.ok) { const errorText = await response.text().catch(() => ""); console.error("API error response:", errorText); throw new Error(`API error: ${response.status}`); } // Response is binary PNG, convert to blob URL const blob = await response.blob(); console.log("Received blob:", blob.type, blob.size); return URL.createObjectURL(blob); } catch (error) { clearTimeout(timeoutId); if (error instanceof Error && error.name === "AbortError") { throw new Error( "درخواست زمان زیادی طول کشید. لطفا دوباره تلاش کنید." ); } throw error; } }, }); // Image Upload Handler const handleImageSelect = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { // Validate file type if (!file.type.startsWith("image/")) { alert("لطفا یک فایل تصویری انتخاب کنید"); return; } // Validate file size (max 10MB) if (file.size > 10 * 1024 * 1024) { alert("حجم فایل نباید بیشتر از 10 مگابایت باشد"); return; } setSelectedImage(file); // Create preview const reader = new FileReader(); reader.onloadend = () => { setImagePreview(reader.result as string); }; reader.readAsDataURL(file); } }; // Handle login required - close AI modal first, then show login const handleLoginRequired = () => { onClose(); // Close AI modal first // Small delay to let the modal close animation complete setTimeout(() => { setIsLoginDialogOpen(true); }, 150); }; // Handle AI Promote Submit const handleAIPromote = async () => { // Check if user is logged in if (!user) { handleLoginRequired(); return; } if (!selectedImage) { alert("لطفا ابتدا عکس خود را آپلود کنید"); return; } setIsUploading(true); try { console.log("Sending AI try-on request..."); let result; if (isProductMode && productId) { // Product try-on result = await tryOnProductMutation.mutateAsync({ image: selectedImage, productId, }); } else if (collectionId) { // Collection try-on result = await tryOnCollectionMutation.mutateAsync({ image: selectedImage, collectionId, }); } else { throw new Error("No product or collection ID provided"); } console.log("AI try-on completed successfully", result); // Result is already a blob URL from the mutation setResultImage(result); // Reset state // handleModalClose(); } catch (error) { console.error("Error in AI try-on:", error); alert("متاسفانه خطایی رخ داد. لطفا دوباره تلاش کنید."); } finally { setIsUploading(false); } }; // Reset modal state when closed const handleModalClose = () => { setSelectedImage(null); setImagePreview(null); setResultImage(null); setIsUploading(false); onClose(); }; // Reset to try again const handleTryAgain = () => { setResultImage(null); setSelectedImage(null); setImagePreview(null); }; // Download result image const handleDownload = () => { if (!resultImage) return; const link = document.createElement("a"); link.href = resultImage; link.download = `ai-tryon-${Date.now()}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); }; // Share result image const handleShare = async () => { if (!resultImage) return; try { // Convert blob URL to actual blob for sharing const response = await fetch(resultImage); const blob = await response.blob(); const file = new File([blob], `ai-tryon-${Date.now()}.png`, { type: "image/png", }); // Build product URL for sharing const siteUrl = typeof window !== "undefined" ? window.location.origin : "https://vitrown.com"; const productUrl = productId ? `${siteUrl}/product/${productId}` : siteUrl; const shareText = `ببین این لباس رو تن من چطور شده! 👗✨\n\nاین محصول رو از ویترون ببین:\n${productUrl}`; // Check if Web Share API is available and supports sharing files if (navigator.share && navigator.canShare?.({ files: [file] })) { await navigator.share({ title: "پرو کردن با هوش مصنوعی - ویترون", text: shareText, files: [file], }); } else { // Fallback: Copy image to clipboard or show message try { await navigator.clipboard.write([ new ClipboardItem({ "image/png": blob }), ]); alert( "تصویر در کلیپ‌بورد کپی شد! حالا میتونی توی هر اپلیکیشنی Paste کنی." ); } catch { // If clipboard also fails, just download handleDownload(); alert("تصویر دانلود شد. میتونی از گالری به اشتراک بذاری."); } } } catch (error) { console.error("Error sharing:", error); } }; return ( <> {/* Login Required Dialog - outside of main dialog to avoid overlap */} {/* Close Button */} {isProductMode ? "پرو کردن محصول با هوش مصنوعی" : "پرو کردن کالکشن با هوش مصنوعی"} {isProductMode ? "برای اینکه AI بتواند این محصول رو روی بدن شما نمایش بده، لطفا یک عکس قدی از خود را آپلود کنید." : "برای اینکه AI بتواد این کالکشن رو روی بدن شما نمایش بده، لطفا یک عکس قدی از خود را آپلود کنید."}
{resultImage ? ( // Result View
{/* Success Badge */}

پرو کردن با موفقیت انجام شد!

{/* Result Image */}
AI Try-on Result
{/* Action Buttons */}
{/* Share Button - Full Width */} {/* Download & Try Again */}
) : ( // Upload View <> {/* Image Upload Area */}
{imagePreview ? ( // Image Preview
Preview
) : ( // Upload Button )}
{/* Action Button or Loading State */} {isUploading ? ( // Loading State - replaces button and info boxes
{/* Animated Icon */}
{loadingSteps[loadingStep].icon}
{/* Loading Text */}

{loadingSteps[loadingStep].text}

{/* Progress Dots */}
{loadingSteps.map((_, index) => (
))}
{/* Step Counter */}

مرحله {loadingStep + 1} از {loadingSteps.length}

) : ( // Normal State - Button and Info boxes <> {/* Info Box */}

نکته: برای بهترین نتیجه، عکس باید در نورپردازی مناسب و با زمینه ساده باشه. AI با استفاده از این عکس،{" "} {isProductMode ? "این محصول" : "محصولات کالکشن"} رو روی بدن شما نمایش میده.

{/* Privacy Notice */}

حریم خصوصی شما مهمه: {" "} عکس‌های شما هیچ‌جا ذخیره نمیشه

)} )}
); }