sidebar.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. 'use client'
  2. import { useState } from 'react'
  3. import { useSession, signOut } from 'next-auth/react'
  4. import Link from 'next/link'
  5. import { usePathname } from 'next/navigation'
  6. import { cn } from '@/lib/utils'
  7. import { Button } from '@/components/ui/button'
  8. import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
  9. import { Separator } from '@/components/ui/separator'
  10. import {
  11. Menu,
  12. Home,
  13. Users,
  14. BookOpen,
  15. Calendar,
  16. ClipboardList,
  17. Settings,
  18. LogOut,
  19. GraduationCap,
  20. UserCheck,
  21. BarChart3,
  22. School,
  23. User,
  24. Layers
  25. } from 'lucide-react'
  26. interface SidebarProps {
  27. className?: string
  28. }
  29. const adminMenuItems = [
  30. { icon: Home, label: 'Dashboard', href: '/admin' },
  31. { icon: Users, label: 'Usuarios', href: '/admin/users' },
  32. { icon: School, label: 'Periodos', href: '/admin/periods' },
  33. { icon: BookOpen, label: 'Clases', href: '/admin/classes' },
  34. { icon: Layers, label: 'Secciones', href: '/admin/sections' },
  35. { icon: GraduationCap, label: 'Profesores', href: '/admin/teacher-assignments' },
  36. { icon: User, label: 'Estudiantes', href: '/admin/student-enrollments' },
  37. { icon: BarChart3, label: 'Reportes', href: '/admin/reports' },
  38. // { icon: Settings, label: 'Configuración', href: '/admin/settings' },
  39. ]
  40. const teacherMenuItems = [
  41. { icon: Home, label: 'Dashboard', href: '/teacher' },
  42. { icon: BookOpen, label: 'Mis Clases', href: '/teacher/assignments' },
  43. { icon: UserCheck, label: 'Asistencia', href: '/teacher/attendance' },
  44. { icon: ClipboardList, label: 'Reportes', href: '/teacher/reports' },
  45. // { icon: Settings, label: 'Perfil', href: '/teacher/profile' },
  46. ]
  47. const studentMenuItems = [
  48. { icon: Home, label: 'Dashboard', href: '/student' },
  49. { icon: BookOpen, label: 'Mis Clases', href: '/student/classes' },
  50. { icon: Calendar, label: 'Horarios', href: '/student/schedule' },
  51. { icon: ClipboardList, label: 'Mi Asistencia', href: '/student/attendance' },
  52. { icon: Settings, label: 'Perfil', href: '/student/profile' },
  53. ]
  54. function SidebarContent({ className }: SidebarProps) {
  55. const { data: session } = useSession()
  56. const pathname = usePathname()
  57. const getMenuItems = () => {
  58. switch (session?.user?.role) {
  59. case 'ADMIN':
  60. return adminMenuItems
  61. case 'TEACHER':
  62. return teacherMenuItems
  63. case 'STUDENT':
  64. return studentMenuItems
  65. default:
  66. return []
  67. }
  68. }
  69. const menuItems = getMenuItems()
  70. const handleSignOut = () => {
  71. signOut({ callbackUrl: '/auth/signin' })
  72. }
  73. return (
  74. <div className={cn('flex h-full flex-col bg-white border-r', className)}>
  75. {/* Header */}
  76. <div className="p-6">
  77. <div className="flex items-center gap-2">
  78. <GraduationCap className="h-8 w-8 text-blue-600" />
  79. <div>
  80. <h1 className="text-xl font-bold text-gray-900">TAPIR</h1>
  81. <p className="text-sm text-gray-500">Sistema de Asistencia</p>
  82. </div>
  83. </div>
  84. </div>
  85. <Separator />
  86. {/* User Info */}
  87. {session?.user && (
  88. <div className="p-4">
  89. <div className="flex items-center gap-3">
  90. <div className="h-10 w-10 rounded-full bg-blue-100 flex items-center justify-center">
  91. <User className="h-5 w-5 text-blue-600" />
  92. </div>
  93. <div className="flex-1 min-w-0">
  94. <p className="text-sm font-medium text-gray-900 truncate">
  95. {session.user.name || session.user.email}
  96. </p>
  97. <p className="text-xs text-gray-500 capitalize">
  98. {session.user.role?.toLowerCase()}
  99. </p>
  100. </div>
  101. </div>
  102. </div>
  103. )}
  104. <Separator />
  105. {/* Navigation */}
  106. <nav className="flex-1 p-4 space-y-1">
  107. {menuItems.map((item) => {
  108. const Icon = item.icon
  109. const isActive = pathname === item.href
  110. return (
  111. <Link
  112. key={item.href}
  113. href={item.href}
  114. className={cn(
  115. 'flex items-center gap-3 px-3 py-2 text-sm font-medium rounded-md transition-colors',
  116. isActive
  117. ? 'bg-blue-100 text-blue-700'
  118. : 'text-gray-600 hover:bg-gray-100 hover:text-gray-900'
  119. )}
  120. >
  121. <Icon className="h-5 w-5" />
  122. {item.label}
  123. </Link>
  124. )
  125. })}
  126. </nav>
  127. {/* Footer */}
  128. <div className="p-4">
  129. <Separator className="mb-4" />
  130. <Button
  131. variant="ghost"
  132. className="w-full justify-start text-gray-600 hover:text-gray-900 hover:bg-gray-100"
  133. onClick={handleSignOut}
  134. >
  135. <LogOut className="h-5 w-5 mr-3" />
  136. Cerrar Sesión
  137. </Button>
  138. </div>
  139. </div>
  140. )
  141. }
  142. export function Sidebar({ className }: SidebarProps) {
  143. return (
  144. <div className={cn('hidden lg:flex lg:w-64 lg:flex-col lg:fixed lg:inset-y-0', className)}>
  145. <SidebarContent />
  146. </div>
  147. )
  148. }
  149. export function MobileSidebar() {
  150. const [open, setOpen] = useState(false)
  151. return (
  152. <Sheet open={open} onOpenChange={setOpen}>
  153. <SheetTrigger asChild>
  154. <Button variant="ghost" size="icon" className="lg:hidden">
  155. <Menu className="h-6 w-6" />
  156. </Button>
  157. </SheetTrigger>
  158. <SheetContent side="left" className="p-0 w-64">
  159. <SidebarContent />
  160. </SheetContent>
  161. </Sheet>
  162. )
  163. }