"use client"; import { useState, useEffect, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import useStore from "@/lib/store"; import modelAdapter from "@/lib/services/adapter-instance"; import { Search, Target, DollarSign, Globe, Calendar, Zap, BarChart3, Layers, ShieldCheck, Loader2, Copy, Download, ExternalLink, MousePointer2, CheckCircle2, AlertCircle, Megaphone, Briefcase, TrendingUp, X, Plus } from "lucide-react"; import { cn } from "@/lib/utils"; import { GoogleAdsResult, GoogleAdsKeyword, GoogleAdCopy, GoogleAdsCampaign } from "@/types"; export default function GoogleAdsGenerator() { const { googleAdsResult, selectedProvider, selectedModels, availableModels, apiKeys, isProcessing, error, setGoogleAdsResult, setProcessing, setError, setAvailableModels, setSelectedModel, setSelectedProvider, } = useStore(); // Input states const [websiteUrl, setWebsiteUrl] = useState(""); const [products, setProducts] = useState([""]); const [targetAudience, setTargetAudience] = useState(""); const [budgetMin, setBudgetMin] = useState("500"); const [budgetMax, setBudgetMax] = useState("2000"); const [currency, setCurrency] = useState("USD"); const [duration, setDuration] = useState("30 days"); const [industry, setIndustry] = useState(""); const [activeTab, setActiveTab] = useState("input"); const [copied, setCopied] = useState(null); const selectedModel = selectedModels[selectedProvider]; const models = availableModels[selectedProvider] || modelAdapter.getAvailableModels(selectedProvider); useEffect(() => { if (typeof window !== "undefined") { loadAvailableModels(); } }, [selectedProvider]); const loadAvailableModels = async () => { const fallbackModels = modelAdapter.getAvailableModels(selectedProvider); setAvailableModels(selectedProvider, fallbackModels); try { const result = await modelAdapter.listModels(selectedProvider); if (result.success && result.data) { setAvailableModels(selectedProvider, result.data[selectedProvider] || fallbackModels); } } catch (error) { console.error("Failed to load models:", error); } }; const addProduct = () => setProducts([...products, ""]); const removeProduct = (index: number) => { const newProducts = products.filter((_, i) => i !== index); setProducts(newProducts.length ? newProducts : [""]); }; const updateProduct = (index: number, value: string) => { const newProducts = [...products]; newProducts[index] = value; setProducts(newProducts); }; const validateUrl = (url: string) => { try { new URL(url.startsWith("http") ? url : `https://${url}`); return true; } catch (e) { return false; } }; const handleGenerate = async () => { if (!websiteUrl.trim()) { setError("Please enter a website URL"); return; } if (!validateUrl(websiteUrl)) { setError("Please enter a valid URL"); return; } const filteredProducts = products.filter(p => p.trim() !== ""); if (filteredProducts.length === 0) { setError("Please add at least one product or service"); return; } const apiKey = apiKeys[selectedProvider]; const isQwenOAuth = selectedProvider === "qwen" && modelAdapter.hasQwenAuth(); if (!isQwenOAuth && (!apiKey || !apiKey.trim())) { setError(`Please configure your ${selectedProvider.toUpperCase()} API key in Settings`); return; } setProcessing(true); setError(null); setActiveTab("input"); try { const result = await modelAdapter.generateGoogleAds(websiteUrl, { productsServices: filteredProducts, targetAudience, budgetRange: { min: parseInt(budgetMin), max: parseInt(budgetMax), currency }, campaignDuration: duration, industry, language: "English" }, selectedProvider, selectedModel); if (result.success && result.data) { try { const parsedData = typeof result.data === 'string' ? JSON.parse(result.data) : result.data; const adsResult: GoogleAdsResult = { ...parsedData, id: Math.random().toString(36).substr(2, 9), websiteUrl, productsServices: filteredProducts, generatedAt: new Date(), rawContent: typeof result.data === 'string' ? result.data : JSON.stringify(result.data, null, 2) }; setGoogleAdsResult(adsResult); setActiveTab("keywords"); } catch (e) { console.error("Failed to parse ads data:", e); setError("Failed to parse the generated ads content. Please try again."); } } else { setError(result.error || "Failed to generate Google Ads campaign"); } } catch (err) { console.error("Ads Generation error:", err); setError(err instanceof Error ? err.message : "An error occurred"); } finally { setProcessing(false); } }; const handleCopy = async (text: string, id: string) => { await navigator.clipboard.writeText(text); setCopied(id); setTimeout(() => setCopied(null), 2000); }; const exportToCsv = () => { if (!googleAdsResult) return; let csvContent = "data:text/csv;charset=utf-8,"; csvContent += "Type,Category,Headline/Keyword,Description/Value,Details\n"; // Keywords googleAdsResult.keywords.primary.forEach(k => { csvContent += `Keyword,Primary,"${k.keyword}","${k.searchVolume || ''}","${k.competition || ''}"\n`; }); googleAdsResult.keywords.longTail.forEach(k => { csvContent += `Keyword,Long-Tail,"${k.keyword}","${k.searchVolume || ''}","${k.competition || ''}"\n`; }); googleAdsResult.keywords.negative.forEach(k => { csvContent += `Keyword,Negative,"${k.keyword}","",""\n`; }); // Ads googleAdsResult.adCopies.forEach((ad, i) => { ad.headlines.forEach((h, j) => { csvContent += `Ad Copy,Headline ${j + 1},"${h}","",""\n`; }); ad.descriptions.forEach((d, j) => { csvContent += `Ad Copy,Description ${j + 1},"${d}","",""\n`; }); }); const encodedUri = encodeURI(csvContent); const link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", `google_ads_${googleAdsResult.id}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); }; return (

Google Ads Gen PRO

Generate high-converting keywords, ad copy, and campaign structures with AI.

{googleAdsResult && (
)}
{/* Input Panel */}
Campaign Parameters Define your goals and target audience.
setWebsiteUrl(e.target.value)} className="bg-muted/30 focus-visible:ring-blue-500" />
{products.map((product, index) => (
updateProduct(index, e.target.value)} className="bg-muted/30 focus-visible:ring-blue-500" /> {products.length > 1 && ( )}
))}
$ setBudgetMin(e.target.value)} className="pl-7 bg-white h-9 text-sm" />
to
$ setBudgetMax(e.target.value)} className="pl-7 bg-white h-9 text-sm" />
setIndustry(e.target.value)} className="h-9 text-sm" />
setDuration(e.target.value)} className="h-9 text-sm" />
setTargetAudience(e.target.value)} className="h-9 text-sm" />
{(["qwen", "ollama", "zai"] as const).map((provider) => ( ))}
{error && (
{error}
)}

Quality Assurance

    {[ "Character limit enforcement", "Keyword relevance matching >85%", "Google Ads policy compliance", "Mobile optimization focus" ].map((item, i) => (
  • {item}
  • ))}
{/* Results Panel */}
{!googleAdsResult && !isProcessing && (

Ready to Launch?

Enter your website URL and products on the left to generate keyword research, ad copy, and a full campaign structure.

15+ Years Domain Knowledge Quality Score Optimization
)} {isProcessing && (

Analyzing Domain Content

Scanning {websiteUrl}, fetching search volumes, and drafting high-converting copy...

{[ { label: "Keywords", delay: "0s" }, { label: "Ad Copy", delay: "0.2s" }, { label: "Targeting", delay: "0.4s" }, { label: "ROI Modeling", delay: "0.6s" } ].map((item, i) => (
{item.label}
))}
)} {googleAdsResult && (
Keywords Ad Templates Campaigns Launch Guide {googleAdsResult.predictions && (
Est. CTR {googleAdsResult.predictions.estimatedCtr}
Conversions {googleAdsResult.predictions.estimatedConversions}
)}
Primary Keywords
{googleAdsResult.keywords.primary.map((item, i) => (
{item.keyword}
Vol: {item.searchVolume} CPC: {item.cpc}
{item.competition}
))}
Long-Tail Opportunities
{googleAdsResult.keywords.longTail.map((item, i) => (
{item.keyword} High Performance Match: {item.difficultyScore}%
{item.cpc}
))}
Negative Keyword List (Add these to Campaigns) Exclude these terms to prevent wasted spend on irrelevant clicks.
{googleAdsResult.keywords.negative.map((item, i) => ( {item.keyword} ))}
{googleAdsResult.adCopies.map((ad, i) => (
Ad Variation {i + 1} • {ad.campaignType}
{ad.mobileOptimized && ( Mobile Ready )}
{ad.headlines.map((h, j) => (
{h} {h.length}/30
))}
Ads • {ad.displayUrl}
{ad.descriptions.map((d, j) => (

{d}

{d.length}/90
))}
))}

A/B Testing Recommendation

Use dynamic keyword insertion for "Variation 1" and focus on emotion-based headlines for "Variation 2" to compare user engagement and CTR.

{googleAdsResult.campaigns.map((camp, i) => (
{camp.name} {camp.type.toUpperCase()} Targeting: {camp.targeting.locations?.join(', ') || 'Global'}
Monthly Budget
{camp.budget.currency} {camp.budget.monthly}
Approx. {camp.budget.currency}{camp.budget.daily}/day

Ad Group Organization

{camp.adGroups.map((group, j) => (
{group.name}
{group.biddingStrategy}

{group.theme}

{group.keywords.map((kw, k) => ( {kw} ))}
))}
Target Locations
{camp.targeting.locations?.join(', ') || 'All'}
Devices
{camp.targeting.devices?.join(', ') || 'All Devices'}
Demographics
{camp.targeting.demographics?.join(', ') || 'All Ages'}
Schedule
{camp.targeting.schedule?.join(', ') || '24/7'}
))}
Bidding Strategy

We recommend Maximize Conversions with a target CPA to balance volume and ROI given your industry competition.

Network Selection

Include Search Partners but disable Display Network for this campaign to ensure high search intent traffic.

Ad Assets

Add Sitelinks, Callouts, and Image assets to improve your Ad Rank and Quality Score.

1 Launch Steps

{googleAdsResult.implementation.setupSteps.map((step, i) => (
{i + 1}

{step}

))}

2 Quality Score Hacks

{googleAdsResult.implementation.qualityScoreTips.map((tip, i) => (
{tip}
))}

3 Tracking & Analytics

    {googleAdsResult.implementation.trackingSetup.map((item, i) => (
  • {item}
  • ))}

Scale Your Success

Success in Google Ads is about iterative optimization. Use these initial settings to gather data for 14 days, then begin aggressive A/B testing on headlines and landing page consistency.

{googleAdsResult.implementation.optimizationTips.slice(0, 3).map((tip, i) => ( {tip} ))}
)}
); }