"use client"; import React, { useState } from "react"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/Card"; import { Button } from "@/components/ui/Button"; import { Select } from "@/components/ui/Select"; import { ProgressBar } from "@/components/ui/ProgressBar"; import { generateTestingMatrix, generateMatrixAd } from "@/lib/api/endpoints"; import { exportAsJSON, exportAsCSV } from "@/lib/utils/export"; import { toast } from "react-hot-toast"; import { Download, FileJson, FileSpreadsheet, Rocket, CheckSquare, Square } from "lucide-react"; import { IMAGE_MODELS } from "@/lib/constants/models"; import type { TestingMatrixResponse, CombinationInfo } from "@/types/api"; import type { Niche } from "@/types/api"; interface TestingMatrixBuilderProps { onMatrixGenerated?: (matrix: TestingMatrixResponse) => void; } export const TestingMatrixBuilder: React.FC = ({ onMatrixGenerated, }) => { const router = useRouter(); const [niche, setNiche] = useState("home_insurance"); const [strategy, setStrategy] = useState<"balanced" | "top_performers" | "diverse">("balanced"); const [angleCount, setAngleCount] = useState(6); const [conceptCount, setConceptCount] = useState(5); const [matrix, setMatrix] = useState(null); const [isGenerating, setIsGenerating] = useState(false); const [selectedCombinations, setSelectedCombinations] = useState>(new Set()); const [isGeneratingAds, setIsGeneratingAds] = useState(false); const [generationProgress, setGenerationProgress] = useState({ current: 0, total: 0 }); const [numVariations, setNumVariations] = useState(1); const [imageModel, setImageModel] = useState(null); const handleGenerate = async () => { setIsGenerating(true); try { const result = await generateTestingMatrix({ niche, angle_count: angleCount, concept_count: conceptCount, strategy, }); setMatrix(result); onMatrixGenerated?.(result); toast.success(`Generated ${result.summary.total_combinations} combinations!`); } catch (error: any) { toast.error(error.message || "Failed to generate testing matrix"); } finally { setIsGenerating(false); } }; const handleExportJSON = () => { if (!matrix) return; exportAsJSON(matrix, `testing-matrix-${niche}-${Date.now()}.json`); toast.success("Matrix exported as JSON"); }; const handleExportCSV = () => { if (!matrix) return; const csvData = matrix.combinations.map((combo) => ({ combination_id: combo.combination_id, angle_key: combo.angle.key, angle_name: combo.angle.name, angle_trigger: combo.angle.trigger, concept_key: combo.concept.key, concept_name: combo.concept.name, compatibility_score: combo.compatibility_score, })); exportAsCSV(csvData, `testing-matrix-${niche}-${Date.now()}.csv`); toast.success("Matrix exported as CSV"); }; const toggleCombination = (combinationId: string) => { const newSelected = new Set(selectedCombinations); if (newSelected.has(combinationId)) { newSelected.delete(combinationId); } else { newSelected.add(combinationId); } setSelectedCombinations(newSelected); }; const selectAll = () => { if (!matrix) return; if (selectedCombinations.size === matrix.combinations.length) { setSelectedCombinations(new Set()); } else { setSelectedCombinations(new Set(matrix.combinations.map(c => c.combination_id))); } }; const handleGenerateAds = async () => { if (!matrix) return; const combinationsToGenerate = selectedCombinations.size > 0 ? matrix.combinations.filter(c => selectedCombinations.has(c.combination_id)) : matrix.combinations; if (combinationsToGenerate.length === 0) { toast.error("Please select at least one combination"); return; } setIsGeneratingAds(true); setGenerationProgress({ current: 0, total: combinationsToGenerate.length }); try { const generatedAds = []; for (let i = 0; i < combinationsToGenerate.length; i++) { const combo = combinationsToGenerate[i]; setGenerationProgress({ current: i + 1, total: combinationsToGenerate.length }); try { const result = await generateMatrixAd({ niche, angle_key: combo.angle.key, concept_key: combo.concept.key, num_images: numVariations, image_model: imageModel, }); generatedAds.push(result); toast.success(`Generated ad ${i + 1}/${combinationsToGenerate.length}`); } catch (error: any) { console.error(`Failed to generate ad for combination ${combo.combination_id}:`, error); toast.error(`Failed to generate ad ${i + 1}/${combinationsToGenerate.length}`); } } toast.success(`Successfully generated ${generatedAds.length} ads!`); // Navigate to gallery to see the results setTimeout(() => { router.push("/gallery"); }, 1500); } catch (error: any) { toast.error(error.message || "Failed to generate ads"); } finally { setIsGeneratingAds(false); setGenerationProgress({ current: 0, total: 0 }); } }; return (
Testing Matrix Builder Generate a systematic testing matrix for ad optimization setStrategy(e.target.value as typeof strategy)} />
setAngleCount(Number(e.target.value))} />
1 10
setConceptCount(Number(e.target.value))} />
1 10

Total Combinations: {angleCount} × {conceptCount} = {angleCount * conceptCount}

{matrix && ( <>
Matrix Summary {matrix.summary.total_combinations} combinations ready for testing

Total Combinations

{matrix.summary.total_combinations}

Unique Angles

{matrix.summary.unique_angles}

Unique Concepts

{matrix.summary.unique_concepts}

Avg Compatibility

{(matrix.summary.average_compatibility * 100).toFixed(0)}%

{/* Generate Ads Section */}

Generate Ads from Matrix

Select combinations to generate ads, or generate all

setNumVariations(Number(e.target.value))} />
1 3