Spaces:
Build error
Build error
| "use client"; | |
| import { useState, useEffect, useCallback } from "react"; | |
| import { Rocket, Flame, Target, Lightbulb, RefreshCw } from "lucide-react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; | |
| import { Badge } from "@/components/ui/badge"; | |
| import { Label } from "@/components/ui/label"; | |
| import { Switch } from "@/components/ui/switch"; | |
| import { toast } from "sonner"; | |
| import { apiFetch } from "./types"; | |
| export default function TrendsTab() { | |
| const [trends, setTrends] = useState<any[]>([]); | |
| const [viralStrategies, setViralStrategies] = useState<any[]>([]); | |
| const [contentIdeas, setContentIdeas] = useState<any[]>([]); | |
| const [trendAnalysis, setTrendAnalysis] = useState<any | null>(null); | |
| const [trendLoading, setTrendLoading] = useState(false); | |
| const [includePetInContent, setIncludePetInContent] = useState(false); | |
| const loadTrends = useCallback(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"); } | |
| }, [includePetInContent]); | |
| useEffect(() => { loadTrends(); }, [loadTrends]); | |
| const handleAnalyzeTrends = async () => { | |
| setTrendLoading(true); | |
| try { | |
| const result = await apiFetch("/trends", { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| niche: "lifestyle", | |
| 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); } | |
| }; | |
| return ( | |
| <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> | |
| <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> | |
| {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> | |
| )} | |
| {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> | |
| )} | |
| {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> | |
| ); | |
| } | |