sofia-cloud / src /components /dashboard /InfluencersTab.tsx
Gmagl
fix: correcciones críticas y refactorización de componentes
3eebcd0
Raw
History Blame Contribute Delete
9.92 kB
"use client";
import { useState } from "react";
import { Users2, Lightbulb, Star, PawPrint, Sparkles, RefreshCw } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
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 { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { toast } from "sonner";
import { apiFetch, type Influencer } from "./types";
export default function InfluencersTab() {
const [influencers, setInfluencers] = useState<Influencer[]>([]);
const [influencerNiche, setInfluencerNiche] = useState("");
const [influencerPlatform, setInfluencerPlatform] = useState("");
const [influencerWithPets, setInfluencerWithPets] = useState(false);
const [influencerLoading, setInfluencerLoading] = useState(false);
const [characterConcept, setCharacterConcept] = useState<any | null>(null);
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 || []);
setCharacterConcept(result.characterConcept);
toast.success("Análisis completado");
} else toast.error(result.error);
} catch { toast.error("Error"); }
finally { setInfluencerLoading(false); }
};
return (
<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>
);
}