feat: responsive sidebar, client selector and layout with alert/device counts
This commit is contained in:
@@ -1,37 +1,132 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import Sidebar from '@/components/layout/Sidebar'
|
||||
import Header from '@/components/layout/Header'
|
||||
import { SelectedClientProvider, useSelectedClient } from '@/components/providers/SelectedClientProvider'
|
||||
import { trpc } from '@/lib/trpc-client'
|
||||
|
||||
export default function DashboardLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const [alertasActivas, setAlertasActivas] = useState(0)
|
||||
const [user, setUser] = useState({
|
||||
nombre: 'Admin',
|
||||
email: 'admin@example.com',
|
||||
rol: 'SUPER_ADMIN',
|
||||
const router = useRouter()
|
||||
|
||||
const meQuery = trpc.auth.me.useQuery(undefined, {
|
||||
retry: false,
|
||||
staleTime: 60 * 1000,
|
||||
})
|
||||
const logoutMutation = trpc.auth.logout.useMutation({
|
||||
onSuccess: () => {
|
||||
window.location.href = '/login'
|
||||
},
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
// TODO: Cargar alertas activas desde API
|
||||
// TODO: Cargar usuario desde sesion
|
||||
}, [])
|
||||
if (meQuery.isError) {
|
||||
router.push('/login')
|
||||
}
|
||||
}, [meQuery.isError, router])
|
||||
|
||||
const handleLogout = async () => {
|
||||
// TODO: Implementar logout
|
||||
window.location.href = '/login'
|
||||
const handleLogout = () => {
|
||||
logoutMutation.mutate()
|
||||
}
|
||||
|
||||
if (meQuery.isLoading || meQuery.isError) {
|
||||
return (
|
||||
<div className="flex h-screen bg-dark-500 items-center justify-center">
|
||||
<div className="text-gray-400">Cargando...</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const user = meQuery.data
|
||||
if (!user) return null
|
||||
|
||||
return (
|
||||
<DashboardContent user={user} onLogout={handleLogout}>
|
||||
{children}
|
||||
</DashboardContent>
|
||||
)
|
||||
}
|
||||
|
||||
function DashboardContent({
|
||||
user,
|
||||
onLogout,
|
||||
children,
|
||||
}: {
|
||||
user: { nombre: string; email: string; rol: string }
|
||||
onLogout: () => void
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<SelectedClientProvider>
|
||||
<DashboardContentInner user={user} onLogout={onLogout}>
|
||||
{children}
|
||||
</DashboardContentInner>
|
||||
</SelectedClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
function DashboardContentInner({
|
||||
user,
|
||||
onLogout,
|
||||
children,
|
||||
}: {
|
||||
user: { nombre: string; email: string; rol: string }
|
||||
onLogout: () => void
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const { selectedClientId } = useSelectedClient()
|
||||
const clienteId = selectedClientId ?? undefined
|
||||
|
||||
const activeAlertsCountQuery = trpc.alertas.conteoActivas.useQuery(
|
||||
{ clienteId },
|
||||
{ refetchOnWindowFocus: true, staleTime: 30 * 1000 }
|
||||
)
|
||||
const activeAlertsCount = activeAlertsCountQuery.data?.total ?? 0
|
||||
|
||||
const devicesCountQuery = trpc.equipos.list.useQuery(
|
||||
{ clienteId, page: 1, limit: 1 },
|
||||
{ refetchOnWindowFocus: true, staleTime: 30 * 1000 }
|
||||
)
|
||||
const devicesCount = devicesCountQuery.data?.pagination?.total ?? 0
|
||||
|
||||
const clientsQuery = trpc.clientes.list.useQuery(
|
||||
{ limit: 100 },
|
||||
{ staleTime: 60 * 1000 }
|
||||
)
|
||||
const clients = (clientsQuery.data?.clientes ?? []).map((c) => ({
|
||||
id: c.id,
|
||||
nombre: c.nombre,
|
||||
codigo: c.codigo,
|
||||
}))
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="flex h-screen bg-dark-500">
|
||||
<Sidebar alertasActivas={alertasActivas} />
|
||||
<div className="flex-1 flex flex-col overflow-hidden">
|
||||
<Header user={user} onLogout={handleLogout} />
|
||||
<main className="flex-1 overflow-y-auto p-6">
|
||||
<Sidebar
|
||||
activeAlertsCount={activeAlertsCount}
|
||||
devicesCount={devicesCount}
|
||||
open={sidebarOpen}
|
||||
onClose={() => setSidebarOpen(false)}
|
||||
/>
|
||||
<div className="ml-0 md:ml-[260px] flex min-w-0 flex-1 flex-col overflow-hidden transition-[margin] duration-200">
|
||||
<Header
|
||||
user={{
|
||||
nombre: user.nombre,
|
||||
email: user.email,
|
||||
rol: user.rol,
|
||||
}}
|
||||
onLogout={onLogout}
|
||||
clients={clients}
|
||||
showAllClientsOption={user.rol === 'SUPER_ADMIN'}
|
||||
onOpenSidebar={() => setSidebarOpen(true)}
|
||||
/>
|
||||
<main className="flex-1 overflow-y-auto p-4 sm:p-6">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user