- Eliminado max-w-[1280px] de todas las apps (mi-dia, landing, cotizador, cobranza, dashboards, alta-clientes) - Kanban: sin restricción de ancho, columnas min-w-[220px] - Grids: xl:grid-cols-4/5 para pantallas grandes - CSS base: -webkit-text-size-adjust + min-h-screen - 6 apps construidas
140 lines
4.8 KiB
TypeScript
140 lines
4.8 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { MODULOS, esModuloVisible } from './data/modulos'
|
|
import { Navbar } from './components/Navbar'
|
|
import { TarjetaModulo } from './components/TarjetaModulo'
|
|
import { ConfiguracionCuenta } from './components/ConfiguracionCuenta'
|
|
import BannerModoLocal from './components/BannerModoLocal'
|
|
import { VistaContactos } from './components/VistaContactos'
|
|
import { ConfigPage } from './components/config/ConfigPage'
|
|
import { CapturaPage } from './pages/CapturaPage'
|
|
import { ClientesMaestroPage } from './pages/ClientesMaestroPage'
|
|
import { getToken, type UsuarioSesion } from './services/auth'
|
|
import { getMe } from './services/api'
|
|
|
|
type Vista = 'home' | 'contactos' | 'captura' | 'clientes-maestro' | 'configuraciones'
|
|
|
|
export default function App() {
|
|
const [vista, setVista] = useState<Vista>('home')
|
|
// Módulos permitidos por el rol (GET /auth/me); null = sin sesión → se muestran todos
|
|
const [permitidos, setPermitidos] = useState<string[] | null>(null)
|
|
const [usuario, setUsuario] = useState<UsuarioSesion | null>(null)
|
|
|
|
useEffect(() => {
|
|
let cancelado = false
|
|
const cargar = () => {
|
|
if (!getToken()) {
|
|
setPermitidos(null)
|
|
setUsuario(null)
|
|
return
|
|
}
|
|
// Si /me falla se conserva lo anterior (o todos): el login wall de cada app sigue
|
|
getMe()
|
|
.then((u) => {
|
|
if (!cancelado) {
|
|
setPermitidos(u.modulos ?? [])
|
|
setUsuario(u)
|
|
}
|
|
})
|
|
.catch(() => {})
|
|
}
|
|
cargar()
|
|
window.addEventListener('frasa:sesion', cargar)
|
|
return () => {
|
|
cancelado = true
|
|
window.removeEventListener('frasa:sesion', cargar)
|
|
}
|
|
}, [])
|
|
|
|
if (vista === 'contactos') {
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<Navbar usuario={usuario} onConfiguraciones={() => setVista('configuraciones')} />
|
|
<BannerModoLocal />
|
|
<VistaContactos onVolver={() => setVista('home')} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (vista === 'captura') {
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<Navbar usuario={usuario} onConfiguraciones={() => setVista('configuraciones')} />
|
|
<BannerModoLocal />
|
|
<CapturaPage onVolver={() => setVista('home')} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (vista === 'clientes-maestro') {
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<Navbar usuario={usuario} onConfiguraciones={() => setVista('configuraciones')} />
|
|
<BannerModoLocal />
|
|
<ClientesMaestroPage onVolver={() => setVista('home')} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (vista === 'configuraciones' && usuario?.rol === 'admin') {
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<Navbar usuario={usuario} onConfiguraciones={() => setVista('configuraciones')} />
|
|
<BannerModoLocal />
|
|
<ConfigPage onVolver={() => setVista('home')} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<Navbar usuario={usuario} onConfiguraciones={() => setVista('configuraciones')} />
|
|
<BannerModoLocal />
|
|
|
|
<main className="w-full flex-1 px-4 sm:px-6 lg:px-8">
|
|
<section aria-labelledby="titulo-hero" className="py-12 sm:py-16">
|
|
<h1
|
|
id="titulo-hero"
|
|
className="text-3xl font-semibold tracking-tight text-[#111827] dark:text-[#E2E8F0] sm:text-4xl"
|
|
>
|
|
Ecosistema comercial
|
|
</h1>
|
|
<p className="mt-3 max-w-2xl text-sm leading-relaxed text-[#64748B] dark:text-[#94A3B8] sm:text-base">
|
|
Las herramientas del equipo comercial de Frasa Desarrollos en un solo lugar:
|
|
cotizaciones, alta de clientes, cobranza, tableros y asistente IA.
|
|
</p>
|
|
</section>
|
|
|
|
<nav aria-label="Módulos del ecosistema">
|
|
<ul className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
|
{MODULOS.filter((modulo) => esModuloVisible(modulo, permitidos)).map((modulo) => (
|
|
<TarjetaModulo
|
|
key={modulo.id}
|
|
modulo={modulo}
|
|
onAbrir={
|
|
modulo.id === 'contactos'
|
|
? () => setVista('contactos')
|
|
: modulo.id === 'captura'
|
|
? () => setVista('captura')
|
|
: modulo.id === 'clientes-maestro'
|
|
? () => setVista('clientes-maestro')
|
|
: undefined
|
|
}
|
|
/>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
|
|
<div className="mt-6">
|
|
<ConfiguracionCuenta />
|
|
</div>
|
|
</main>
|
|
|
|
<footer className="mt-16 border-t border-[#E5E7EB] dark:border-[#1E293B]">
|
|
<div className="px-6 py-8 sm:px-6 lg:px-8">
|
|
<p className="text-xs text-[#64748B] dark:text-[#94A3B8]">Consult (AS) Technology</p>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
)
|
|
}
|