sofia-cloud / src /app /page.tsx
Gmagl
Add Sofia Cloud complete files
333c51a
raw
history blame
59.5 kB
"use client";
import { useState, useEffect, useCallback } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
Menu, X, Bot, Wand2, ImageIcon, Video, Users, FolderGit2, Shield,
RefreshCw, DollarSign, Clock, Film, Zap, TrendingUp, Calendar,
Play, Pause, Trash2, Plus, Send, Copy, Eye, Settings, ChevronRight,
CheckCircle2, AlertCircle, ExternalLink, CreditCard, Target, Sparkles,
Heart, PawPrint, Star, Users2, Lightbulb, Flame, Rocket
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { toast } from "sonner";
// Types
interface Content { id: string; type: string; title: string; status: string; platform: string; createdAt: string; }
interface Character { id: string; name: string; description: string | null; referenceImage: string | null; }
interface Platform { id: string; name: string; type: string; isActive: boolean; isVerified: boolean; }
interface Post { id: string; title: string | null; type: string; status: string; scheduledAt: string | null; }
interface Story { id: string; title: string; genre: string; status: string; totalEpisodes: number; }
interface Automation { id: string; name: string; type: string; isActive: boolean; runCount: number; }
interface Pet { id: string; name: string; type: string; breed: string | null; personality: string | null; referenceImage: string | null; }
interface Influencer { name: string; handle: string; platform: string; followers: number; engagement: number; niche: string; petCompanion: boolean; petType?: string; keyLessons: string[]; }
// API Helper
async function apiFetch(endpoint: string, options: RequestInit = {}) {
const response = await fetch(`/api${endpoint}`, {
headers: { "Content-Type": "application/json", ...options.headers },
...options,
});
return response.json();
}
export default function Dashboard() {
const [sidebarOpen, setSidebarOpen] = useState(true);
const [activeTab, setActiveTab] = useState("prompt-engineer");
const [loading, setLoading] = useState(false);
// Prompt Engineer
const [userPrompt, setUserPrompt] = useState("");
const [promptType, setPromptType] = useState("image");
const [targetPlatform, setTargetPlatform] = useState("general");
const [optimizedPrompt, setOptimizedPrompt] = useState<Record<string, unknown> | null>(null);
const [promptLoading, setPromptLoading] = useState(false);
// Image Generation
const [imagePrompt, setImagePrompt] = useState("");
const [imageStyle, setImageStyle] = useState("realistic");
const [imagePlatform, setImagePlatform] = useState("general");
const [imageLoading, setImageLoading] = useState(false);
// Monetization
const [platforms, setPlatforms] = useState<Platform[]>([]);
const [selectedMonetizationPlatform, setSelectedMonetizationPlatform] = useState("");
// Posts
const [posts, setPosts] = useState<Post[]>([]);
const [postTitle, setPostTitle] = useState("");
const [postType, setPostType] = useState("reel");
const [postCaption, setPostCaption] = useState("");
const [scheduledTime, setScheduledTime] = useState("");
// Stories
const [stories, setStories] = useState<Story[]>([]);
const [storyPrompt, setStoryPrompt] = useState("");
const [storyGenre, setStoryGenre] = useState("lifestyle");
const [storyEpisodes, setStoryEpisodes] = useState(7);
const [storyLoading, setStoryLoading] = useState(false);
// Automation
const [automations, setAutomations] = useState<Automation[]>([]);
const [automationName, setAutomationName] = useState("");
const [automationType, setAutomationType] = useState("content_generation");
// Content & Characters
const [contents, setContents] = useState<Content[]>([]);
const [characters, setCharacters] = useState<Character[]>([]);
// Pets
const [pets, setPets] = useState<Pet[]>([]);
const [petName, setPetName] = useState("");
const [petType, setPetType] = useState("dog");
const [petBreed, setPetBreed] = useState("");
const [petPersonality, setPetPersonality] = useState("");
const [includePetInContent, setIncludePetInContent] = useState(false);
const [petLoading, setPetLoading] = useState(false);
// Influencers
const [influencers, setInfluencers] = useState<Influencer[]>([]);
const [influencerNiche, setInfluencerNiche] = useState("");
const [influencerPlatform, setInfluencerPlatform] = useState("");
const [influencerWithPets, setInfluencerWithPets] = useState(false);
const [influencerLoading, setInfluencerLoading] = useState(false);
const [influencerAnalysis, setInfluencerAnalysis] = useState<Record<string, unknown> | null>(null);
const [characterConcept, setCharacterConcept] = useState<Record<string, unknown> | null>(null);
// Trends
const [trends, setTrends] = useState<Record<string, unknown>[]>([]);
const [viralStrategies, setViralStrategies] = useState<Record<string, unknown>[]>([]);
const [contentIdeas, setContentIdeas] = useState<Record<string, unknown>[]>([]);
const [trendAnalysis, setTrendAnalysis] = useState<Record<string, unknown> | null>(null);
const [trendLoading, setTrendLoading] = useState(false);
// Stats
const [stats, setStats] = useState({ images: 0, videos: 0, stories: 0, automations: 0, pets: 0 });
// Load data
const loadData = useCallback(async () => {
setLoading(true);
try {
const [contentRes, platformsRes, postsRes, storiesRes, automationRes, petsRes] = await Promise.all([
apiFetch("/content"),
apiFetch("/monetization"),
apiFetch("/posts"),
apiFetch("/storytelling"),
apiFetch("/automation"),
apiFetch("/pets"),
]);
if (contentRes.success) {
setContents(contentRes.contents);
setStats({
images: contentRes.stats?.images || 0,
videos: contentRes.stats?.videos || 0,
stories: storiesRes?.total || 0,
automations: automationRes?.stats?.total || 0,
pets: petsRes?.total || 0,
});
}
if (platformsRes.success) setPlatforms(platformsRes.userPlatforms);
if (postsRes.success) setPosts(postsRes.posts);
if (storiesRes.success) setStories(storiesRes.stories);
if (automationRes.success) setAutomations(automationRes.automations);
if (petsRes.success) setPets(petsRes.pets);
} catch {
toast.error("Error al cargar datos");
} finally {
setLoading(false);
}
}, []);
useEffect(() => { loadData(); }, [loadData]);
// Actions
const handleOptimizePrompt = async () => {
if (!userPrompt.trim()) { toast.error("Escribe un prompt"); return; }
setPromptLoading(true);
try {
const result = await apiFetch("/prompt-engineer", {
method: "POST",
body: JSON.stringify({ prompt: userPrompt, type: promptType, platform: targetPlatform }),
});
if (result.success) {
setOptimizedPrompt(result);
toast.success("Prompt optimizado");
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setPromptLoading(false); }
};
const handleGenerateImage = async () => {
if (!userPrompt.trim()) { toast.error("Escribe un prompt"); return; }
setImageLoading(true);
try {
const result = await apiFetch("/generate/image", {
method: "POST",
body: JSON.stringify({
prompt: userPrompt,
optimizedPrompt: optimizedPrompt?.optimizedPrompt,
platform: imagePlatform,
style: imageStyle,
includePet: includePetInContent,
petId: pets[0]?.id
}),
});
if (result.success) {
toast.success("Imagen generada");
loadData();
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setImageLoading(false); }
};
const handleCreateStory = async () => {
if (!storyPrompt.trim()) { toast.error("Describe tu historia"); return; }
setStoryLoading(true);
try {
const result = await apiFetch("/storytelling", {
method: "POST",
body: JSON.stringify({
prompt: storyPrompt,
genre: storyGenre,
totalEpisodes: storyEpisodes,
}),
});
if (result.success) {
toast.success(`Historia "${result.story?.title}" creada`);
setStoryPrompt("");
loadData();
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setStoryLoading(false); }
};
const handleCreatePost = async () => {
if (!postTitle.trim()) { toast.error("Añade un título"); return; }
try {
const result = await apiFetch("/posts", {
method: "POST",
body: JSON.stringify({
title: postTitle,
type: postType,
caption: postCaption,
scheduledAt: scheduledTime || null,
autoGenerateCaption: true,
}),
});
if (result.success) {
toast.success(scheduledTime ? "Post programado" : "Post creado");
setPostTitle(""); setPostCaption(""); setScheduledTime("");
loadData();
} else toast.error(result.error);
} catch { toast.error("Error"); }
};
const handleCreateAutomation = async () => {
if (!automationName.trim()) { toast.error("Dale un nombre"); return; }
try {
const result = await apiFetch("/automation", {
method: "POST",
body: JSON.stringify({
name: automationName,
type: automationType,
trigger: "schedule",
triggerConfig: { schedule: "daily:09:00" },
actions: [{ type: "generate_content", prompt: "Genera contenido de lifestyle" }],
}),
});
if (result.success) {
toast.success("Automatización creada");
setAutomationName("");
loadData();
} else toast.error(result.error);
} catch { toast.error("Error"); }
};
const handleToggleAutomation = async (id: string, currentStatus: boolean) => {
try {
await apiFetch("/automation", {
method: "PUT",
body: JSON.stringify({ id, isActive: !currentStatus }),
});
loadData();
} catch { toast.error("Error"); }
};
const handleCreatePet = async () => {
if (!petName.trim()) { toast.error("Dale un nombre a tu mascota"); return; }
setPetLoading(true);
try {
const result = await apiFetch("/pets", {
method: "POST",
body: JSON.stringify({
name: petName,
type: petType,
breed: petBreed || undefined,
personality: petPersonality || undefined,
generateReference: true
}),
});
if (result.success) {
toast.success(`Mascota "${petName}" creada (+${result.engagementBoost}% engagement)`);
setPetName(""); setPetBreed(""); setPetPersonality("");
loadData();
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setPetLoading(false); }
};
const handleAnalyzeInfluencers = async () => {
setInfluencerLoading(true);
try {
const result = await apiFetch("/influencers", {
method: "POST",
body: JSON.stringify({
targetNiche: influencerNiche || "lifestyle",
targetPlatform: influencerPlatform || undefined,
includePets: influencerWithPets
}),
});
if (result.success) {
setInfluencers(result.referenceInfluencers || []);
setInfluencerAnalysis(result.analysis);
setCharacterConcept(result.characterConcept);
toast.success("Análisis completado");
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setInfluencerLoading(false); }
};
const handleAnalyzeTrends = async () => {
setTrendLoading(true);
try {
const result = await apiFetch("/trends", {
method: "POST",
body: JSON.stringify({
niche: influencerNiche || "lifestyle",
platform: influencerPlatform || undefined,
includePets: includePetInContent,
daysToViral: 14
}),
});
if (result.success) {
setTrendAnalysis(result.analysis);
toast.success("Análisis de tendencias completado");
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setTrendLoading(false); }
};
const loadTrends = async () => {
try {
const result = await apiFetch(`/trends?includePets=${includePetInContent}`);
if (result.success) {
setTrends(result.trends);
setViralStrategies(result.viralStrategies);
setContentIdeas(result.contentIdeas);
}
} catch { toast.error("Error cargando tendencias"); }
};
useEffect(() => {
if (activeTab === "trends") loadTrends();
}, [activeTab, includePetInContent]);
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
toast.success("Copiado");
};
const getStatusColor = (status: string) => {
const colors: Record<string, string> = {
completed: "bg-green-500/10 text-green-500",
published: "bg-green-500/10 text-green-500",
scheduled: "bg-blue-500/10 text-blue-500",
draft: "bg-slate-500/10 text-slate-400",
pending: "bg-yellow-500/10 text-yellow-500",
active: "bg-green-500/10 text-green-500",
};
return colors[status] || "bg-slate-500/10 text-slate-400";
};
const petTypes = [
{ value: "dog", label: "🐕 Perro" },
{ value: "cat", label: "🐱 Gato" },
{ value: "bird", label: "🐦 Pájaro" },
{ value: "rabbit", label: "🐰 Conejo" },
{ value: "hamster", label: "🐹 Hámster" }
];
return (
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-white">
{/* Sidebar */}
<AnimatePresence mode="wait">
{sidebarOpen && (
<motion.aside
initial={{ x: -280 }} animate={{ x: 0 }} exit={{ x: -280 }}
className="fixed left-0 top-0 h-full w-64 bg-slate-900/90 backdrop-blur-xl border-r border-slate-800 z-50"
>
<div className="p-5">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-violet-500 to-purple-600 flex items-center justify-center">
<Bot className="h-5 w-5" />
</div>
<div>
<h1 className="text-lg font-bold bg-gradient-to-r from-violet-400 to-purple-400 bg-clip-text text-transparent">Sofía Cloud</h1>
<p className="text-xs text-slate-400">Monetización Pro</p>
</div>
</div>
<nav className="space-y-1">
{[
{ id: "prompt-engineer", icon: Wand2, label: "Ingeniero IA" },
{ id: "images", icon: ImageIcon, label: "Imágenes" },
{ id: "videos", icon: Video, label: "Videos" },
{ id: "monetization", icon: DollarSign, label: "Monetización" },
{ id: "posts", icon: Calendar, label: "Publicaciones" },
{ id: "storytelling", icon: Film, label: "Storytelling" },
{ id: "automation", icon: Zap, label: "Automatización" },
{ id: "influencers", icon: Users2, label: "Influencers IA" },
{ id: "pets", icon: PawPrint, label: "Mascotas" },
{ id: "trends", icon: TrendingUp, label: "Tendencias" },
{ id: "content", icon: FolderGit2, label: "Contenido" },
].map((item) => (
<button key={item.id} onClick={() => setActiveTab(item.id)}
className={`w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all text-sm ${
activeTab === item.id ? "bg-violet-500/20 text-violet-400 border border-violet-500/30" : "text-slate-400 hover:bg-slate-800"}`}>
<item.icon className="h-4 w-4" /><span>{item.label}</span>
</button>
))}
</nav>
</div>
<div className="absolute bottom-0 left-0 right-0 p-4 border-t border-slate-800">
<div className="grid grid-cols-2 gap-2 text-center text-xs">
<div><p className="text-xl font-bold text-violet-400">{stats.images}</p><p className="text-slate-500">Imágenes</p></div>
<div><p className="text-xl font-bold text-blue-400">{stats.videos}</p><p className="text-slate-500">Videos</p></div>
<div><p className="text-xl font-bold text-green-400">{stats.stories}</p><p className="text-slate-500">Historias</p></div>
<div><p className="text-xl font-bold text-amber-400">{stats.pets}</p><p className="text-slate-500">Mascotas</p></div>
</div>
</div>
</motion.aside>
)}
</AnimatePresence>
{/* Main */}
<div className={`transition-all duration-300 ${sidebarOpen ? "ml-64" : "ml-0"}`}>
<header className="sticky top-0 z-40 bg-slate-950/80 backdrop-blur-xl border-b border-slate-800">
<div className="flex items-center justify-between px-6 py-3">
<div className="flex items-center gap-3">
<Button variant="ghost" size="icon" onClick={() => setSidebarOpen(!sidebarOpen)} className="text-slate-400">
{sidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</Button>
<h2 className="text-lg font-semibold capitalize">{activeTab.replace("-", " ")}</h2>
</div>
<Button variant="outline" size="sm" onClick={loadData} disabled={loading} className="border-slate-700">
<RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} />Actualizar
</Button>
</div>
</header>
<main className="p-6">
{/* Prompt Engineer */}
{activeTab === "prompt-engineer" && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader>
<CardTitle className="flex items-center gap-2"><Wand2 className="h-5 w-5 text-violet-400" />Ingeniero de Prompts</CardTitle>
<CardDescription>Describe en lenguaje natural lo que quieres crear</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<Textarea placeholder="Ej: Quiero fotos de una mujer rubia en la playa para OnlyFans..." value={userPrompt} onChange={(e) => setUserPrompt(e.target.value)} className="bg-slate-800 border-slate-700 min-h-28" />
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-xs text-slate-400">Tipo</Label>
<Select value={promptType} onValueChange={setPromptType}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="image">Imagen</SelectItem>
<SelectItem value="video">Video</SelectItem>
<SelectItem value="reel">Reel</SelectItem>
<SelectItem value="carousel">Carrusel</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-xs text-slate-400">Plataforma</Label>
<Select value={targetPlatform} onValueChange={setTargetPlatform}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="general">General</SelectItem>
<SelectItem value="onlyfans">OnlyFans</SelectItem>
<SelectItem value="patreon">Patreon</SelectItem>
<SelectItem value="instagram">Instagram</SelectItem>
<SelectItem value="tiktok">TikTok</SelectItem>
<SelectItem value="youtube">YouTube</SelectItem>
</SelectContent>
</Select>
</div>
</div>
{pets.length > 0 && (
<div className="flex items-center gap-2">
<Switch checked={includePetInContent} onCheckedChange={setIncludePetInContent} />
<Label className="text-sm text-slate-400">Incluir mascota en el contenido (+35% engagement)</Label>
</div>
)}
<Button onClick={handleOptimizePrompt} disabled={promptLoading} className="w-full bg-violet-600 hover:bg-violet-700">
{promptLoading ? <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> : <Wand2 className="h-4 w-4 mr-2" />}Optimizar
</Button>
</CardContent>
</Card>
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle>Prompt Optimizado</CardTitle></CardHeader>
<CardContent>
{optimizedPrompt ? (
<div className="space-y-3">
<div className="p-3 rounded-lg bg-slate-800/50 border border-slate-700">
<div className="flex justify-between mb-2">
<Badge className="bg-violet-500/20 text-violet-400">{String(optimizedPrompt.type)}</Badge>
<Button variant="ghost" size="sm" onClick={() => copyToClipboard(String(optimizedPrompt.optimizedPrompt))}><Copy className="h-4 w-4" /></Button>
</div>
<p className="text-sm whitespace-pre-wrap">{String(optimizedPrompt.optimizedPrompt)}</p>
</div>
<div className="flex gap-2">
<Button onClick={handleGenerateImage} disabled={imageLoading} className="flex-1 bg-green-600 hover:bg-green-700">
<ImageIcon className="h-4 w-4 mr-2" />Generar Imagen
</Button>
<Button onClick={() => setActiveTab("posts")} className="flex-1 bg-blue-600 hover:bg-blue-700">
<Calendar className="h-4 w-4 mr-2" />Crear Post
</Button>
</div>
</div>
) : (
<div className="text-center py-12 text-slate-400">
<Wand2 className="h-12 w-12 mx-auto mb-3 opacity-50" /><p>El prompt optimizado aparecerá aquí</p>
</div>
)}
</CardContent>
</Card>
</div>
)}
{/* Images */}
{activeTab === "images" && (
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><ImageIcon className="h-5 w-5 text-green-400" />Generar Imágenes</CardTitle></CardHeader>
<CardContent className="space-y-4">
<Textarea placeholder="Describe la imagen..." value={userPrompt} onChange={(e) => setUserPrompt(e.target.value)} className="bg-slate-800 border-slate-700" />
<div className="grid grid-cols-3 gap-4">
<div>
<Label className="text-xs text-slate-400">Estilo</Label>
<Select value={imageStyle} onValueChange={setImageStyle}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="realistic">Realista</SelectItem>
<SelectItem value="anime">Anime</SelectItem>
<SelectItem value="artistic">Artístico</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-xs text-slate-400">Plataforma</Label>
<Select value={imagePlatform} onValueChange={setImagePlatform}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="general">General</SelectItem>
<SelectItem value="onlyfans">OnlyFans</SelectItem>
<SelectItem value="instagram">Instagram</SelectItem>
</SelectContent>
</Select>
</div>
</div>
{pets.length > 0 && (
<div className="flex items-center gap-2">
<Switch checked={includePetInContent} onCheckedChange={setIncludePetInContent} />
<Label className="text-sm text-slate-400">Incluir mascota ({pets[0]?.name})</Label>
</div>
)}
<Button onClick={handleGenerateImage} disabled={imageLoading} className="w-full bg-green-600 hover:bg-green-700">
{imageLoading ? <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> : <ImageIcon className="h-4 w-4 mr-2" />}Generar
</Button>
</CardContent>
</Card>
)}
{/* Monetization */}
{activeTab === "monetization" && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{[
{ name: "OnlyFans", type: "subscription", fee: "20%", color: "from-blue-500 to-cyan-500", legal: "Adult content permitido" },
{ name: "Patreon", type: "subscription", fee: "12%", color: "from-orange-500 to-red-500", legal: "Sin adult content real" },
{ name: "Fansly", type: "mixed", fee: "20%", color: "from-purple-500 to-pink-500", legal: "Adult content permitido" },
{ name: "Fanvue", type: "subscription", fee: "15%", color: "from-green-500 to-teal-500", legal: "Adult content permitido" },
{ name: "Ko-fi", type: "tips", fee: "0%", color: "from-sky-500 to-blue-500", legal: "Sin adult content" },
{ name: "Instagram", type: "free", fee: "0%", color: "from-pink-500 to-purple-500", legal: "Sin desnudez" },
].map((p) => (
<Card key={p.name} className="bg-slate-900/50 border-slate-800">
<CardContent className="p-4">
<div className={`w-10 h-10 rounded-lg bg-gradient-to-br ${p.color} flex items-center justify-center mb-3`}>
<DollarSign className="h-5 w-5 text-white" />
</div>
<h3 className="font-semibold">{p.name}</h3>
<p className="text-xs text-slate-400 mt-1">Fee: {p.fee}</p>
<Badge variant="outline" className="mt-2 text-xs">{p.type}</Badge>
<p className="text-xs text-amber-400 mt-2">⚖️ {p.legal}</p>
<Button size="sm" className="w-full mt-3 bg-violet-600 hover:bg-violet-700">
<Plus className="h-3 w-3 mr-1" />Conectar
</Button>
</CardContent>
</Card>
))}
</div>
)}
{/* Posts */}
{activeTab === "posts" && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><Calendar className="h-5 w-5 text-blue-400" />Crear Publicación</CardTitle></CardHeader>
<CardContent className="space-y-4">
<Input placeholder="Título" value={postTitle} onChange={(e) => setPostTitle(e.target.value)} className="bg-slate-800 border-slate-700" />
<Textarea placeholder="Caption..." value={postCaption} onChange={(e) => setPostCaption(e.target.value)} className="bg-slate-800 border-slate-700 min-h-20" />
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-xs text-slate-400">Tipo</Label>
<Select value={postType} onValueChange={setPostType}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="reel">Reel</SelectItem>
<SelectItem value="photo">Foto</SelectItem>
<SelectItem value="carousel">Carrusel</SelectItem>
<SelectItem value="story">Story</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-xs text-slate-400">Programar</Label>
<Input type="datetime-local" value={scheduledTime} onChange={(e) => setScheduledTime(e.target.value)} className="bg-slate-800 border-slate-700 mt-1" />
</div>
</div>
<Button onClick={handleCreatePost} className="w-full bg-blue-600 hover:bg-blue-700">
<Calendar className="h-4 w-4 mr-2" />{scheduledTime ? "Programar" : "Crear"}
</Button>
</CardContent>
</Card>
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle>Publicaciones</CardTitle></CardHeader>
<CardContent>
<ScrollArea className="h-64">
{posts.length === 0 ? (
<p className="text-slate-400 text-center py-8">No hay publicaciones</p>
) : (
<div className="space-y-2">
{posts.map((p) => (
<div key={p.id} className="p-3 rounded-lg bg-slate-800/50 flex items-center justify-between">
<div>
<p className="font-medium text-sm">{p.title || "Sin título"}</p>
<p className="text-xs text-slate-400">{p.type} • {p.scheduledAt ? new Date(p.scheduledAt).toLocaleString() : "Borrador"}</p>
</div>
<Badge className={getStatusColor(p.status)}>{p.status}</Badge>
</div>
))}
</div>
)}
</ScrollArea>
</CardContent>
</Card>
</div>
)}
{/* Storytelling */}
{activeTab === "storytelling" && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><Film className="h-5 w-5 text-purple-400" />Crear Historia</CardTitle></CardHeader>
<CardContent className="space-y-4">
<Textarea placeholder="Describe tu historia... Ej: Una historia de transformación fitness de 30 días..." value={storyPrompt} onChange={(e) => setStoryPrompt(e.target.value)} className="bg-slate-800 border-slate-700 min-h-24" />
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-xs text-slate-400">Género</Label>
<Select value={storyGenre} onValueChange={setStoryGenre}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="lifestyle">Lifestyle</SelectItem>
<SelectItem value="fitness">Fitness</SelectItem>
<SelectItem value="romance">Romance</SelectItem>
<SelectItem value="drama">Drama</SelectItem>
<SelectItem value="comedy">Comedia</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label className="text-xs text-slate-400">Episodios</Label>
<Input type="number" value={storyEpisodes} onChange={(e) => setStoryEpisodes(parseInt(e.target.value) || 7)} className="bg-slate-800 border-slate-700 mt-1" />
</div>
</div>
<Button onClick={handleCreateStory} disabled={storyLoading} className="w-full bg-purple-600 hover:bg-purple-700">
{storyLoading ? <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> : <Sparkles className="h-4 w-4 mr-2" />}Generar Historia
</Button>
</CardContent>
</Card>
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle>Historias Creadas</CardTitle></CardHeader>
<CardContent>
<ScrollArea className="h-64">
{stories.length === 0 ? (
<p className="text-slate-400 text-center py-8">No hay historias</p>
) : (
<div className="space-y-2">
{stories.map((s) => (
<div key={s.id} className="p-3 rounded-lg bg-slate-800/50">
<div className="flex justify-between items-start">
<div>
<p className="font-medium">{s.title}</p>
<p className="text-xs text-slate-400">{s.totalEpisodes} episodios • {s.genre}</p>
</div>
<Badge className={getStatusColor(s.status)}>{s.status}</Badge>
</div>
</div>
))}
</div>
)}
</ScrollArea>
</CardContent>
</Card>
</div>
)}
{/* Automation */}
{activeTab === "automation" && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><Zap className="h-5 w-5 text-amber-400" />Crear Automatización</CardTitle></CardHeader>
<CardContent className="space-y-4">
<Input placeholder="Nombre de la automatización" value={automationName} onChange={(e) => setAutomationName(e.target.value)} className="bg-slate-800 border-slate-700" />
<div>
<Label className="text-xs text-slate-400">Tipo</Label>
<Select value={automationType} onValueChange={setAutomationType}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
<SelectItem value="content_generation">Generación de Contenido</SelectItem>
<SelectItem value="posting">Publicación Automática</SelectItem>
<SelectItem value="cross_posting">Cross-Posting</SelectItem>
<SelectItem value="trend_tracking">Seguimiento de Tendencias</SelectItem>
</SelectContent>
</Select>
</div>
<Button onClick={handleCreateAutomation} className="w-full bg-amber-600 hover:bg-amber-700">
<Zap className="h-4 w-4 mr-2" />Crear
</Button>
</CardContent>
</Card>
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle>Automatizaciones Activas</CardTitle></CardHeader>
<CardContent>
<ScrollArea className="h-64">
{automations.length === 0 ? (
<p className="text-slate-400 text-center py-8">No hay automatizaciones</p>
) : (
<div className="space-y-2">
{automations.map((a) => (
<div key={a.id} className="p-3 rounded-lg bg-slate-800/50 flex items-center justify-between">
<div>
<p className="font-medium text-sm">{a.name}</p>
<p className="text-xs text-slate-400">{a.type} • {a.runCount} ejecuciones</p>
</div>
<Button size="sm" variant="ghost" onClick={() => handleToggleAutomation(a.id, a.isActive)}>
{a.isActive ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
</Button>
</div>
))}
</div>
)}
</ScrollArea>
</CardContent>
</Card>
</div>
)}
{/* Influencers IA */}
{activeTab === "influencers" && (
<div className="space-y-6">
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader>
<CardTitle className="flex items-center gap-2"><Users2 className="h-5 w-5 text-pink-400" />Análisis de Influencers IA Famosos</CardTitle>
<CardDescription>Estudia los patrones de influencers IA exitosos para aplicarlos a tu contenido</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<Label className="text-xs text-slate-400">Tu Nicho</Label>
<Input placeholder="lifestyle, fashion..." value={influencerNiche} onChange={(e) => setInfluencerNiche(e.target.value)} className="bg-slate-800 border-slate-700 mt-1" />
</div>
<div>
<Label className="text-xs text-slate-400">Plataforma Objetivo</Label>
<Select value={influencerPlatform} onValueChange={setInfluencerPlatform}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue placeholder="Todas" /></SelectTrigger>
<SelectContent>
<SelectItem value="">Todas</SelectItem>
<SelectItem value="instagram">Instagram</SelectItem>
<SelectItem value="tiktok">TikTok</SelectItem>
<SelectItem value="youtube">YouTube</SelectItem>
</SelectContent>
</Select>
</div>
<div className="flex items-end">
<div className="flex items-center gap-2 pb-2">
<Switch checked={influencerWithPets} onCheckedChange={setInfluencerWithPets} />
<Label className="text-sm text-slate-400">Con mascotas</Label>
</div>
</div>
<div className="flex items-end">
<Button onClick={handleAnalyzeInfluencers} disabled={influencerLoading} className="w-full bg-pink-600 hover:bg-pink-700">
{influencerLoading ? <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> : <Lightbulb className="h-4 w-4 mr-2" />}Analizar
</Button>
</div>
</div>
</CardContent>
</Card>
{influencers.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{influencers.map((inf, i) => (
<Card key={i} className="bg-slate-900/50 border-slate-800">
<CardContent className="p-4">
<div className="flex items-center gap-2 mb-2">
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-pink-500 to-purple-500 flex items-center justify-center">
<Star className="h-4 w-4 text-white" />
</div>
<div>
<p className="font-medium text-sm">{inf.name}</p>
<p className="text-xs text-slate-400">{inf.handle}</p>
</div>
</div>
<div className="space-y-1 text-xs">
<p><span className="text-slate-400">Seguidores:</span> <span className="text-green-400">{(inf.followers / 1000000).toFixed(1)}M</span></p>
<p><span className="text-slate-400">Engagement:</span> <span className="text-blue-400">{inf.engagement}%</span></p>
<p><span className="text-slate-400">Nicho:</span> {inf.niche}</p>
{inf.petCompanion && <Badge className="bg-amber-500/20 text-amber-400 mt-1"><PawPrint className="h-3 w-3 mr-1" />{inf.petType}</Badge>}
</div>
<div className="mt-2 pt-2 border-t border-slate-700">
<p className="text-xs text-slate-400">Lecciones:</p>
<ul className="text-xs mt-1 space-y-1">
{inf.keyLessons.slice(0, 2).map((l, j) => (
<li key={j} className="text-slate-300">• {l}</li>
))}
</ul>
</div>
</CardContent>
</Card>
))}
</div>
)}
{characterConcept && (
<Card className="bg-slate-900/50 border-slate-800 border-violet-500/30">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-violet-400"><Sparkles className="h-5 w-5" />Concepto de Personaje Sugerido</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<h4 className="font-medium mb-2">Personaje</h4>
<div className="p-3 rounded-lg bg-slate-800/50 text-sm">
{characterConcept.character && (
<>
<p><strong>Nombre:</strong> {String(characterConcept.character.name || "")}</p>
<p className="mt-1"><strong>Personalidad:</strong> {String(characterConcept.character.personality || "")}</p>
<p className="mt-1"><strong>Historia:</strong> {String(characterConcept.character.backstory || "")}</p>
</>
)}
</div>
</div>
<div>
<h4 className="font-medium mb-2">Estilo Visual</h4>
<div className="p-3 rounded-lg bg-slate-800/50 text-sm">
{characterConcept.visualStyle && (
<>
<p><strong>Estética:</strong> {String(characterConcept.visualStyle.aesthetic || "")}</p>
<p className="mt-1"><strong>Colores:</strong> {Array.isArray(characterConcept.visualStyle.colors) ? characterConcept.visualStyle.colors.join(", ") : ""}</p>
</>
)}
</div>
{Array.isArray(characterConcept.hashtags) && characterConcept.hashtags.length > 0 && (
<div className="mt-3 flex flex-wrap gap-1">
{characterConcept.hashtags.slice(0, 10).map((tag: string, i: number) => (
<Badge key={i} variant="outline" className="text-xs">{tag}</Badge>
))}
</div>
)}
</div>
</div>
</CardContent>
</Card>
)}
</div>
)}
{/* Pets */}
{activeTab === "pets" && (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader>
<CardTitle className="flex items-center gap-2"><PawPrint className="h-5 w-5 text-amber-400" />Crear Mascota</CardTitle>
<CardDescription>Las mascotas aumentan el engagement hasta un 35%</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-xs text-slate-400">Nombre</Label>
<Input placeholder="Max, Luna..." value={petName} onChange={(e) => setPetName(e.target.value)} className="bg-slate-800 border-slate-700 mt-1" />
</div>
<div>
<Label className="text-xs text-slate-400">Tipo</Label>
<Select value={petType} onValueChange={setPetType}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue /></SelectTrigger>
<SelectContent>
{petTypes.map((pt) => (
<SelectItem key={pt.value} value={pt.value}>{pt.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-xs text-slate-400">Raza (opcional)</Label>
<Input placeholder="Golden Retriever..." value={petBreed} onChange={(e) => setPetBreed(e.target.value)} className="bg-slate-800 border-slate-700 mt-1" />
</div>
<div>
<Label className="text-xs text-slate-400">Personalidad</Label>
<Select value={petPersonality} onValueChange={setPetPersonality}>
<SelectTrigger className="bg-slate-800 border-slate-700 mt-1"><SelectValue placeholder="Seleccionar" /></SelectTrigger>
<SelectContent>
<SelectItem value="playful">Juguetón</SelectItem>
<SelectItem value="calm">Tranquilo</SelectItem>
<SelectItem value="energetic">Energético</SelectItem>
<SelectItem value="curious">Curioso</SelectItem>
<SelectItem value="lazy">Perezoso</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<Button onClick={handleCreatePet} disabled={petLoading} className="w-full bg-amber-600 hover:bg-amber-700">
{petLoading ? <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> : <PawPrint className="h-4 w-4 mr-2" />}Crear Mascota
</Button>
</CardContent>
</Card>
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle>Mis Mascotas</CardTitle></CardHeader>
<CardContent>
<ScrollArea className="h-64">
{pets.length === 0 ? (
<div className="text-center py-8 text-slate-400">
<PawPrint className="h-12 w-12 mx-auto mb-3 opacity-50" />
<p>No tienes mascotas</p>
<p className="text-xs mt-1">Las mascotas aumentan el engagement</p>
</div>
) : (
<div className="space-y-2">
{pets.map((p) => (
<div key={p.id} className="p-3 rounded-lg bg-slate-800/50 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 flex items-center justify-center">
<PawPrint className="h-5 w-5 text-white" />
</div>
<div>
<p className="font-medium">{p.name}</p>
<p className="text-xs text-slate-400">{p.breed || p.type} • {p.personality || "Sin personalidad"}</p>
</div>
</div>
<Badge className="bg-green-500/20 text-green-400">+35%</Badge>
</div>
))}
</div>
)}
</ScrollArea>
</CardContent>
</Card>
</div>
)}
{/* Trends */}
{activeTab === "trends" && (
<div className="space-y-6">
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
<Switch checked={includePetInContent} onCheckedChange={setIncludePetInContent} />
<Label className="text-sm text-slate-400">Incluir tendencias de mascotas</Label>
</div>
<Button onClick={handleAnalyzeTrends} disabled={trendLoading} className="bg-violet-600 hover:bg-violet-700">
{trendLoading ? <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> : <Rocket className="h-4 w-4 mr-2" />}Analizar para Viralizar
</Button>
</div>
{/* Tendencias Actuales */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{trends.slice(0, 8).map((t, i) => (
<Card key={i} className="bg-slate-900/50 border-slate-800">
<CardContent className="p-4">
<div className="flex items-center justify-between mb-2">
<Badge variant="outline" className="text-xs">{String(t.platform || "")}</Badge>
<Flame className={`h-4 w-4 ${Number(t.growth) > 30 ? "text-red-400" : "text-orange-400"}`} />
</div>
<p className="font-semibold">{String(t.name)}</p>
<p className="text-green-400 text-sm">+{Number(t.growth).toFixed(1)}%</p>
<p className="text-xs text-slate-400 mt-1">{String(t.category || "")}</p>
</CardContent>
</Card>
))}
</div>
{/* Estrategias Virales */}
{viralStrategies.length > 0 && (
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><Rocket className="h-5 w-5 text-violet-400" />Estrategias Virales</CardTitle></CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{viralStrategies.slice(0, 4).map((s, i) => (
<div key={i} className="p-3 rounded-lg bg-slate-800/50 border border-slate-700">
<div className="flex items-center justify-between mb-2">
<p className="font-medium text-sm">{String(s.name)}</p>
<Badge className="bg-green-500/20 text-green-400 text-xs">{String(s.successRate)}%</Badge>
</div>
<p className="text-xs text-slate-400 line-clamp-2">{String(s.description)}</p>
<div className="flex flex-wrap gap-1 mt-2">
{Array.isArray(s.platforms) && s.platforms.slice(0, 3).map((p: string, j: number) => (
<Badge key={j} variant="outline" className="text-xs">{p}</Badge>
))}
</div>
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* Ideas de Contenido */}
{contentIdeas.length > 0 && (
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><Lightbulb className="h-5 w-5 text-amber-400" />Ideas de Contenido Viral</CardTitle></CardHeader>
<CardContent>
<div className="space-y-3">
{contentIdeas.slice(0, 5).map((idea, i) => (
<div key={i} className="p-3 rounded-lg bg-slate-800/50 border border-slate-700">
<div className="flex items-center justify-between">
<div>
<p className="font-medium">{String(idea.title)}</p>
<p className="text-xs text-slate-400 mt-1">{String(idea.description)}</p>
{idea.hook && <p className="text-xs text-violet-400 mt-1">Hook: "{String(idea.hook)}"</p>}
</div>
<div className="text-right">
<Badge className="bg-violet-500/20 text-violet-400">{String(idea.format)}</Badge>
{idea.viralScore && <p className="text-xs text-green-400 mt-1">Score: {String(idea.viralScore)}</p>}
</div>
</div>
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* Análisis de Tendencias */}
{trendAnalysis && (
<Card className="bg-slate-900/50 border-slate-800 border-violet-500/30">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-violet-400"><Target className="h-5 w-5" />Plan para Viralizar</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<h4 className="font-medium mb-2">Tendencias Emergentes</h4>
<div className="space-y-2">
{Array.isArray(trendAnalysis.emergingTrends) && trendAnalysis.emergingTrends.slice(0, 3).map((t: Record<string, unknown>, i: number) => (
<div key={i} className="p-2 rounded bg-slate-800/50 text-sm">
<p className="font-medium">{String(t.name)}</p>
<p className="text-xs text-slate-400">Potencial: {String(t.potential)}</p>
</div>
))}
</div>
</div>
<div>
<h4 className="font-medium mb-2">Recomendaciones</h4>
<div className="space-y-1">
{Array.isArray(trendAnalysis.recommendations) && trendAnalysis.recommendations.slice(0, 4).map((r: string, i: number) => (
<p key={i} className="text-sm text-slate-300">• {r}</p>
))}
</div>
{trendAnalysis.predictedViralPotential && (
<div className="mt-4 p-3 rounded-lg bg-violet-500/10 border border-violet-500/30">
<p className="text-sm">Potencial Viral Estimado:</p>
<p className="text-2xl font-bold text-violet-400">{String(trendAnalysis.predictedViralPotential)}%</p>
</div>
)}
</div>
</div>
</CardContent>
</Card>
)}
</div>
)}
{/* Content */}
{activeTab === "content" && (
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle>Contenido Generado</CardTitle></CardHeader>
<CardContent>
<ScrollArea className="h-96">
{contents.length === 0 ? (
<p className="text-slate-400 text-center py-8">No hay contenido generado</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{contents.map((c) => (
<div key={c.id} className="p-4 rounded-lg bg-slate-800/50 border border-slate-700">
<div className="flex justify-between mb-2">
<Badge className={getStatusColor(c.status)}>{c.status}</Badge>
<Badge variant="outline">{c.type}</Badge>
</div>
<p className="font-medium line-clamp-2">{c.title}</p>
<p className="text-xs text-slate-400 mt-1">{c.platform}</p>
</div>
))}
</div>
)}
</ScrollArea>
</CardContent>
</Card>
)}
{/* Videos */}
{activeTab === "videos" && (
<Card className="bg-slate-900/50 border-slate-800">
<CardHeader><CardTitle className="flex items-center gap-2"><Video className="h-5 w-5 text-blue-400" />Generar Videos</CardTitle></CardHeader>
<CardContent className="space-y-4">
<Textarea placeholder="Describe el video..." value={userPrompt} onChange={(e) => setUserPrompt(e.target.value)} className="bg-slate-800 border-slate-700" />
<Button className="w-full bg-blue-600 hover:bg-blue-700">
<Video className="h-4 w-4 mr-2" />Generar Video
</Button>
</CardContent>
</Card>
)}
</main>
</div>
</div>
);
}