/* Sidebar + Topbar */ const PLAN_ICONS_SB = { starter: "△", creator: "◆", pro: "★" }; function PlanPill({ plan, status }) { if (!plan || plan === "admin") return null; const active = status === "active" || status === "trialing"; const icon = PLAN_ICONS_SB[plan] || ""; return ( {icon && {icon}} {plan} ); } function NavGroup({ groupId, label, items, active, onChange, compact }) { const [open, setOpen] = React.useState(() => { const saved = localStorage.getItem(`vc_group_${groupId}`); return saved !== null ? saved === "1" : true; }); React.useEffect(() => { localStorage.setItem(`vc_group_${groupId}`, open ? "1" : "0"); }, [open, groupId]); const showItems = open || compact; return (
{!compact && ( )} {showItems && (
{items.map(({ id, label: itemLabel, Icon, badge, dot, badgeAlert }) => ( ))}
)}
); } function Sidebar({ active, onChange, compact, onToggleCompact, mobileOpen, currentUser, onLogout, historyPending = 0, launchListPending = 0, challengePending = 0 }) { const isAdmin = currentUser?.is_admin; const plan = currentUser?.plan; const planStatus = currentUser?.subscription_status; const [profileOpen, setProfileOpen] = React.useState(false); const profileRef = React.useRef(null); React.useEffect(() => { function handleClick(e) { if (profileRef.current && !profileRef.current.contains(e.target)) { setProfileOpen(false); } } if (profileOpen) document.addEventListener("mousedown", handleClick); return () => document.removeEventListener("mousedown", handleClick); }, [profileOpen]); const clipsItems = [ { id: "create_home", label: "Crear vídeo", Icon: IconVideo, badge: "AI" }, { id: "history", label: "Producción", Icon: IconHistory, badge: historyPending > 0 ? String(historyPending) : null, dot: historyPending > 0, badgeAlert: true }, { id: "launch_list", label: "Creación en lista", Icon: IconPlay, badge: launchListPending > 0 ? String(launchListPending) : null, dot: launchListPending > 0, badgeAlert: true }, ...(isAdmin ? [{ id: "challenge30", label: "30-day challenge", Icon: IconFlag, badge: challengePending > 0 ? String(challengePending) : null, dot: challengePending > 0, badgeAlert: true }] : []), ]; const toolsItems = [ { id: "gen_clips", label: "Generar Clips", Icon: IconClap }, { id: "gen_images", label: "Generar Imágenes", Icon: IconImage }, { id: "viral_voice", label: "Viral Voice", Icon: IconWave }, { id: "planning", label: "Planning", Icon: IconCalendar }, ]; const username = currentUser?.username || "…"; const email = currentUser?.email || ""; const initials = username.slice(0, 2).toUpperCase(); function goTo(id) { onChange(id); setProfileOpen(false); } // ── Credit widget data ── const planActive = planStatus === "active" || planStatus === "trialing"; const creditsAvail = currentUser?.credits_available ?? 0; const creditsGrant = currentUser?.credits_monthly_grant ?? 0; const creditsUsed = creditsGrant > 0 ? Math.max(0, creditsGrant - creditsAvail) : 0; const creditPct = creditsGrant > 0 ? Math.min(1, creditsUsed / creditsGrant) : 0; const widgetColor = "var(--accent)"; return ( ); } function CreditPill({ user }) { if (!user) return null; if (user.is_admin) return null; const credits = user.credits_available != null ? user.credits_available : 0; const plan = user.plan; const status = user.subscription_status; const active = status === "active" || status === "trialing"; if (!plan || !active) { return (
Sin plan activo
); } return (
{credits.toLocaleString()}
); } function Topbar({ title, subtitle, children, onMobileMenu, currentUser }) { return (

{title}

{subtitle && · {subtitle}}
{children}
); } Object.assign(window, { Sidebar, Topbar });