From 932de22c97708d0d29b498cd2e30485b9d7b0480 Mon Sep 17 00:00:00 2001 From: Gemini AI Date: Sun, 28 Dec 2025 02:23:30 +0400 Subject: [PATCH] feat(google-ads): Add product URLs and animated progress messages - Products now support custom URLs for linking ads and AI research - Added animated progress messages with fun AI statements during generation - Progress bar shows cycling status updates in EN/RU/HE - Enhanced UX with bouncing dots and gradient progress indicator --- components/GoogleAdsGenerator.tsx | 156 ++++++++++++++++++++++++------ 1 file changed, 129 insertions(+), 27 deletions(-) diff --git a/components/GoogleAdsGenerator.tsx b/components/GoogleAdsGenerator.tsx index 28203a7..2a16aab 100644 --- a/components/GoogleAdsGenerator.tsx +++ b/components/GoogleAdsGenerator.tsx @@ -37,7 +37,7 @@ export default function GoogleAdsGenerator() { // Input states const [websiteUrl, setWebsiteUrl] = useState(""); - const [products, setProducts] = useState([""]); + const [products, setProducts] = useState<{ name: string; url: string }[]>([{ name: "", url: "" }]); const [targetAudience, setTargetAudience] = useState(""); const [budgetMin, setBudgetMin] = useState("500"); const [budgetMax, setBudgetMax] = useState("2000"); @@ -48,9 +48,45 @@ export default function GoogleAdsGenerator() { const [expandedSections, setExpandedSections] = useState(["keywords"]); const [isMagicThinking, setIsMagicThinking] = useState(false); + const [progressMessage, setProgressMessage] = useState(""); + const [progressIndex, setProgressIndex] = useState(0); + const selectedModel = selectedModels[selectedProvider]; const models = availableModels[selectedProvider] || modelAdapter.getAvailableModels(selectedProvider); + // Fun progress messages + const progressMessages = language === "ru" ? [ + "🔍 Изучаю ваш сайт...", + "🧠 Анализирую конкурентов...", + "💡 Генерирую гениальные идеи...", + "📊 Исследую рыночные тренды...", + "🎯 Определяю целевую аудиторию...", + "✨ Создаю магию рекламы...", + "🚀 Почти готово, потерпите...", + "📝 Пишу убедительные тексты...", + "🔥 Оптимизирую для конверсий..." + ] : language === "he" ? [ + "🔍 בודק את האתר שלך...", + "🧠 מנתח מתחרים...", + "💡 מייצר רעיונות גאוניים...", + "📊 חוקר מגמות שוק...", + "🎯 מזהה קהל יעד...", + "✨ יוצר קסם פרסום...", + "🚀 כמעט שם, רק רגע...", + "📝 כותב טקסטים משכנעים...", + "🔥 מייעל להמרות..." + ] : [ + "🔍 Studying your website...", + "🧠 Analyzing competitors...", + "💡 Generating brilliant ideas...", + "📊 Researching market trends...", + "🎯 Identifying target audience...", + "✨ Creating advertising magic...", + "🚀 Almost there, hang tight...", + "📝 Writing persuasive copy...", + "🔥 Optimizing for conversions..." + ]; + const toggleSection = (section: string) => { setExpandedSections((prev) => prev.includes(section) ? prev.filter((s) => s !== section) : [...prev, section] @@ -74,6 +110,27 @@ export default function GoogleAdsGenerator() { } }, [selectedProvider]); + // Cycle through progress messages while generating + useEffect(() => { + if (isProcessing || isMagicThinking) { + setProgressMessage(progressMessages[0]); + setProgressIndex(0); + + const interval = setInterval(() => { + setProgressIndex(prev => { + const nextIndex = (prev + 1) % progressMessages.length; + setProgressMessage(progressMessages[nextIndex]); + return nextIndex; + }); + }, 2500); + + return () => clearInterval(interval); + } else { + setProgressMessage(""); + setProgressIndex(0); + } + }, [isProcessing, isMagicThinking, language]); + const loadAvailableModels = async () => { const fallbackModels = modelAdapter.getAvailableModels(selectedProvider); setAvailableModels(selectedProvider, fallbackModels); @@ -88,14 +145,14 @@ export default function GoogleAdsGenerator() { } }; - const addProduct = () => setProducts([...products, ""]); + const addProduct = () => setProducts([...products, { name: "", url: "" }]); const removeProduct = (index: number) => { const newProducts = products.filter((_, i) => i !== index); - setProducts(newProducts.length ? newProducts : [""]); + setProducts(newProducts.length ? newProducts : [{ name: "", url: "" }]); }; - const updateProduct = (index: number, value: string) => { + const updateProduct = (index: number, field: "name" | "url", value: string) => { const newProducts = [...products]; - newProducts[index] = value; + newProducts[index] = { ...newProducts[index], [field]: value }; setProducts(newProducts); }; @@ -104,9 +161,9 @@ export default function GoogleAdsGenerator() { setError("Please enter a website URL"); return; } - const filteredProducts = products.filter(p => p.trim() !== ""); + const filteredProducts = products.filter(p => p.name.trim() !== ""); if (filteredProducts.length === 0) { - setError("Please add at least one product or service"); + setError(language === "ru" ? "Добавьте хотя бы один продукт или услугу" : language === "he" ? "הוסף לפחות מוצר או שירות אחד" : "Please add at least one product or service"); return; } @@ -125,8 +182,13 @@ export default function GoogleAdsGenerator() { console.log("[GoogleAdsGenerator] Starting generation...", { selectedProvider, selectedModel }); try { + // Convert products to strings with optional URLs for AI context + const productStrings = filteredProducts.map(p => + p.url ? `${p.name} (URL: ${p.url})` : p.name + ); + const result = await modelAdapter.generateGoogleAds(websiteUrl, { - productsServices: filteredProducts, + productsServices: productStrings, targetAudience, budgetRange: { min: parseInt(budgetMin), max: parseInt(budgetMax), currency: "USD" }, campaignDuration: duration, @@ -194,9 +256,9 @@ export default function GoogleAdsGenerator() { setError("Please enter a website URL"); return; } - const firstProduct = products.find(p => p.trim() !== ""); + const firstProduct = products.find(p => p.name.trim() !== ""); if (!firstProduct) { - setError("Please add at least one product to promote"); + setError(language === "ru" ? "Добавьте хотя бы один продукт" : language === "he" ? "הוסף לפחות מוצר אחד" : "Please add at least one product to promote"); return; } @@ -213,9 +275,14 @@ export default function GoogleAdsGenerator() { setGoogleAdsResult(null); try { + // Pass product with URL for enhanced AI research + const productString = firstProduct.url + ? `${firstProduct.name} (Product URL for research: ${firstProduct.url})` + : firstProduct.name; + const result = await modelAdapter.generateMagicWand( websiteUrl, - firstProduct, + productString, parseInt(budgetMax), selectedProvider, selectedModel @@ -605,25 +672,33 @@ export default function GoogleAdsGenerator() {
-
+
{products.map((product, index) => ( -
+
+
+ updateProduct(index, "name", e.target.value)} + className="text-sm" + /> + {products.length > 1 && ( + + )} +
updateProduct(index, e.target.value)} - className="text-sm" + placeholder={language === "ru" ? "URL страницы продукта (необязательно)" : language === "he" ? "כתובת URL של עמוד המוצר (אופציונלי)" : "Product page URL (optional)"} + value={product.url} + onChange={(e) => updateProduct(index, "url", e.target.value)} + className="text-xs text-muted-foreground" /> - {products.length > 1 && ( - - )}
))}
+ + {/* Progress Messages */} + {(isProcessing || isMagicThinking) && progressMessage && ( +
+
+
+ + + +
+

+ {progressMessage} +

+
+
+
+
+
+ + {progressIndex + 1}/{progressMessages.length} + +
+
+ )}