'use client'; import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import { Button, Card, CardContent, cn } from '@horux/shared-ui'; import { useAuthStore } from '@/stores/auth-store'; import { useContribuyentes } from '@/lib/hooks/use-contribuyentes'; import { apiClient } from '@/lib/api/client'; import { dismissOnboarding } from '@/lib/api/auth'; import { CheckCircle2, ArrowRight, Building2, Key, FileText, Users, CreditCard } from 'lucide-react'; interface Step { id: string; title: string; description: string; icon: React.ReactNode; href: string; completed: boolean; optional?: boolean; } export default function OnboardingPage() { const user = useAuthStore((s) => s.user); const setUser = useAuthStore((s) => s.setUser); const { data: contribuyentes } = useContribuyentes(); const router = useRouter(); const [fielDone, setFielDone] = useState(false); const [csdDone, setCsdDone] = useState(false); const [dismissed, setDismissed] = useState(false); const hasContribuyentes = (contribuyentes?.length ?? 0) > 0; const firstContribId = contribuyentes?.[0]?.id; // Check FIEL + Facturapi status — try per-contribuyente first, fallback to legacy tenant-level useEffect(() => { if (!firstContribId) return; // FIEL: check per-contribuyente (tenant BD) then legacy (central BD) apiClient.get(`/contribuyentes/${firstContribId}/fiel/status`) .then(({ data }) => { if (data.configured) { setFielDone(true); } else { // Fallback: check legacy tenant-level FIEL apiClient.get('/fiel/status') .then(({ data: legacyData }) => setFielDone(legacyData.configured === true)) .catch(() => setFielDone(false)); } }) .catch(() => { apiClient.get('/fiel/status') .then(({ data: legacyData }) => setFielDone(legacyData.configured === true)) .catch(() => setFielDone(false)); }); // Facturapi: check per-contribuyente then legacy apiClient.get(`/contribuyentes/${firstContribId}/facturapi/status`) .then(({ data }) => { if (data.configured) { setCsdDone(data.hasCsd === true); } else { apiClient.get('/facturacion/org/status') .then(({ data: legacyData }) => setCsdDone(legacyData.configured === true && legacyData.hasCsd === true)) .catch(() => setCsdDone(false)); } }) .catch(() => setCsdDone(false)); }, [firstContribId]); const steps: Step[] = [ { id: 'account', title: 'Cuenta creada', description: 'Tu despacho está registrado y listo.', icon: , href: '#', completed: true, }, { id: 'contribuyente', title: 'Agregar primer contribuyente', description: 'Registra el primer RFC que gestionarás.', icon: , href: '/contribuyentes', completed: hasContribuyentes, }, { id: 'fiel', title: 'Subir FIEL del contribuyente', description: 'Necesaria para sincronizar con el SAT.', icon: , href: '/configuracion/sat', completed: fielDone, }, { id: 'csd', title: 'Subir CSD (para emitir facturas)', description: 'Certificado de Sello Digital para timbrado.', icon: , href: '/configuracion/csd', completed: csdDone, }, { id: 'team', title: 'Invitar supervisores o auxiliares', description: 'Agrega a tu equipo de trabajo.', icon: , href: '/usuarios', completed: false, optional: true, }, { id: 'plan', title: 'Elegir plan de pago', description: 'Tu trial gratuito dura 30 días.', icon: , href: '/configuracion/planes-despacho', completed: false, optional: true, }, ]; const completedCount = steps.filter((s) => s.completed).length; const requiredSteps = steps.filter((s) => !s.optional); const requiredCompleted = requiredSteps.filter((s) => s.completed).length; const allRequiredDone = requiredCompleted === requiredSteps.length; // Auto-dismiss cuando todos los pasos requeridos están listos. Idempotente // del lado backend, pero `dismissed` evita el round-trip si la página se // re-renderiza (datos refetched). useEffect(() => { if (!allRequiredDone || dismissed || !user || user.onboardingDismissedAt) return; setDismissed(true); dismissOnboarding() .then((res) => { // Sync al store para que el siguiente login vaya directo al dashboard // sin esperar a que el backend incremente loginCount > threshold. setUser({ ...user, onboardingDismissedAt: res.onboardingDismissedAt }); }) .catch((err) => { console.warn('[onboarding] Failed to mark as dismissed:', err); setDismissed(false); // permite reintentar }); }, [allRequiredDone, dismissed, user, setUser]); return (

Bienvenido a Horux Despachos

Configura tu despacho en unos minutos. {completedCount} de {steps.length} pasos completados.

{steps.map((step) => (
{step.completed ? : step.icon}

{step.title} {step.optional && (opcional)}

{step.description}

{!step.completed && step.href !== '#' && ( )}
))}
{allRequiredDone && (
)}

Puedes completar estos pasos en cualquier orden. Tu trial de 30 días ya comenzó.

); }