sofia-cloud / src /app /page.tsx
Gmagl
fix: correcciones críticas y refactorización de componentes
3eebcd0
Raw
History Blame Contribute Delete
5.01 kB
"use client";
import { useState, useEffect, useCallback } from "react";
import { Menu, X, RefreshCw } from "lucide-react";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import {
DashboardSidebar,
PromptEngineerTab,
ImagesTab,
VideosTab,
MonetizationTab,
PostsTab,
StorytellingTab,
AutomationTab,
InfluencersTab,
PetsTab,
TrendsTab,
ContentTab,
} from "@/components/dashboard";
import { apiFetch, type Content, type Platform, type Post, type Story, type Automation, type Pet } from "@/components/dashboard/types";
export default function Dashboard() {
const [sidebarOpen, setSidebarOpen] = useState(true);
const [activeTab, setActiveTab] = useState("prompt-engineer");
const [loading, setLoading] = useState(false);
// Shared state loaded at dashboard level
const [contents, setContents] = useState<Content[]>([]);
const [platforms, setPlatforms] = useState<Platform[]>([]);
const [posts, setPosts] = useState<Post[]>([]);
const [stories, setStories] = useState<Story[]>([]);
const [automations, setAutomations] = useState<Automation[]>([]);
const [pets, setPets] = useState<Pet[]>([]);
const [includePetInContent, setIncludePetInContent] = useState(false);
const [stats, setStats] = useState({ images: 0, videos: 0, stories: 0, automations: 0, pets: 0 });
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]);
const renderActiveTab = () => {
switch (activeTab) {
case "prompt-engineer":
return <PromptEngineerTab pets={pets} includePetInContent={includePetInContent} setIncludePetInContent={setIncludePetInContent} onImageGenerated={loadData} />;
case "images":
return <ImagesTab pets={pets} includePetInContent={includePetInContent} setIncludePetInContent={setIncludePetInContent} onGenerated={loadData} />;
case "videos":
return <VideosTab onGenerated={loadData} />;
case "monetization":
return <MonetizationTab />;
case "posts":
return <PostsTab posts={posts} onCreated={loadData} />;
case "storytelling":
return <StorytellingTab stories={stories} onCreated={loadData} />;
case "automation":
return <AutomationTab automations={automations} onCreated={loadData} />;
case "influencers":
return <InfluencersTab />;
case "pets":
return <PetsTab pets={pets} onCreated={loadData} />;
case "trends":
return <TrendsTab />;
case "content":
return <ContentTab contents={contents} />;
default:
return null;
}
};
return (
<div className="min-h-screen bg-gradient-to-b from-slate-950 via-slate-900 to-slate-950 text-white">
<DashboardSidebar sidebarOpen={sidebarOpen} activeTab={activeTab} setActiveTab={setActiveTab} stats={stats} />
<div className={`transition-all duration-300 ${sidebarOpen ? "ml-64" : "ml-0"}`}>
{/* Header */}
<header className="sticky top-0 bg-slate-900/80 backdrop-blur-xl border-b border-slate-800 z-40">
<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)}>
{sidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</Button>
<h2 className="text-lg font-semibold capitalize">{activeTab.replace(/-/g, " ")}</h2>
</div>
<Button variant="ghost" size="sm" onClick={loadData} disabled={loading}>
<RefreshCw className={`h-4 w-4 mr-2 ${loading ? "animate-spin" : ""}`} />Actualizar
</Button>
</div>
</header>
{/* Main Content */}
<main className="p-6">
{renderActiveTab()}
</main>
</div>
</div>
);
}