"use client"; import { useRef, useState } from "react"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { ImagePlus, X, Loader2 } from "lucide-react"; export const PLATFORMS = ["instagram", "tiktok", "nextdoor"] as const; export const GOALS = [ { value: "app_downloads", label: "App Downloads", description: "Drive installs from App Store and Google Play" }, { value: "brand_awareness", label: "Brand Awareness", description: "Maximize reach and impressions across platforms" }, { value: "engagement", label: "Engagement", description: "Boost likes, comments, shares, and saves" }, ] as const; export interface CampaignData { id?: string; name: string; platforms: string[]; config: { goal: string; keyMessage: string; socialProof?: string; targetAudience?: string; visualDirection?: string; competitorApps?: string; variations?: number; useTrendReport?: boolean; screenshots?: string[]; }; } interface CampaignFormProps { initialData?: CampaignData; mode?: "create" | "edit"; } export function CampaignForm({ initialData, mode = "create" }: CampaignFormProps) { const router = useRouter(); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [selectedPlatforms, setSelectedPlatforms] = useState( initialData?.platforms || ["instagram"] ); const [selectedGoal, setSelectedGoal] = useState( initialData?.config.goal || "app_downloads" ); const [screenshots, setScreenshots] = useState< { file?: File; preview: string; uploadedPath?: string }[] >(() => { // Pre-populate from existing campaign screenshots const existing = initialData?.config.screenshots || []; return existing.map((p) => ({ preview: `/api/files/${p}`, uploadedPath: p, })); }); const [uploading, setUploading] = useState(false); const fileInputRef = useRef(null); function handleFilesSelected(files: FileList | null) { if (!files) return; const newScreenshots = Array.from(files) .filter((f) => f.type.startsWith("image/")) .map((file) => ({ file, preview: URL.createObjectURL(file), })); setScreenshots((prev) => [...prev, ...newScreenshots]); } function removeScreenshot(index: number) { setScreenshots((prev) => { const next = [...prev]; if (next[index].preview.startsWith("blob:")) { URL.revokeObjectURL(next[index].preview); } next.splice(index, 1); return next; }); } async function uploadScreenshots(): Promise { if (screenshots.length === 0) return []; const needUpload = screenshots.filter((s) => !s.uploadedPath && s.file); if (needUpload.length === 0) { return screenshots.filter((s) => s.uploadedPath).map((s) => s.uploadedPath!); } setUploading(true); const formData = new FormData(); for (const s of needUpload) { formData.append("files", s.file!); } const res = await fetch("/api/uploads", { method: "POST", body: formData, }); if (!res.ok) { setUploading(false); throw new Error("Failed to upload screenshots"); } const data = await res.json(); const uploadedPaths: string[] = data.uploaded.map( (u: { path: string }) => u.path ); // Map uploaded paths back to screenshots let uploadIdx = 0; setScreenshots((prev) => prev.map((s) => { if (!s.uploadedPath) { return { ...s, uploadedPath: uploadedPaths[uploadIdx++] }; } return s; }) ); setUploading(false); // Return all paths (previously uploaded + newly uploaded) const allPaths: string[] = []; let newIdx = 0; for (const s of screenshots) { if (s.uploadedPath) { allPaths.push(s.uploadedPath); } else { allPaths.push(uploadedPaths[newIdx++]); } } return allPaths; } async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setError(""); if (selectedPlatforms.length === 0) { setError("Select at least one platform."); return; } setLoading(true); let screenshotPaths: string[] = []; try { screenshotPaths = await uploadScreenshots(); } catch { setError("Failed to upload screenshots. Please try again."); setLoading(false); return; } const formData = new FormData(e.currentTarget); const body = { name: formData.get("name") as string, platforms: selectedPlatforms, config: { goal: formData.get("goal") as string, keyMessage: formData.get("keyMessage") as string, socialProof: formData.get("socialProof") as string, targetAudience: formData.get("targetAudience") as string, visualDirection: formData.get("visualDirection") as string, competitorApps: formData.get("competitorApps") as string, variations: Number(formData.get("variations")) || 5, useTrendReport: formData.get("useTrendReport") === "on", screenshots: screenshotPaths, }, }; const isEdit = mode === "edit" && initialData?.id; const url = isEdit ? `/api/campaigns/${initialData.id}` : "/api/campaigns"; const method = isEdit ? "PATCH" : "POST"; const res = await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify( isEdit ? { name: body.name, platforms: JSON.stringify(body.platforms), config: JSON.stringify(body.config) } : body ), }); if (res.ok) { if (isEdit) { router.refresh(); } else { const campaign = await res.json(); router.push(`/campaigns/${campaign.id}`); } } else { const data = await res.json().catch(() => null); setError(data?.error || "Failed to save campaign. Please try again."); setLoading(false); } } function togglePlatform(platform: string) { setSelectedPlatforms((prev) => prev.includes(platform) ? prev.filter((p) => p !== platform) : [...prev, platform] ); } return ( {mode === "edit" ? "Edit Campaign" : "New Campaign"} {mode === "edit" ? "Update campaign details before launching" : "Configure your campaign and launch the AI pipeline"}
{PLATFORMS.map((platform) => ( ))}
{GOALS.map((goal) => ( ))}