diff --git a/frontend/src/app/(app)/knowledge-base/page.tsx b/frontend/src/app/(app)/knowledge-base/page.tsx index 60b513c..8900811 100644 --- a/frontend/src/app/(app)/knowledge-base/page.tsx +++ b/frontend/src/app/(app)/knowledge-base/page.tsx @@ -11,16 +11,7 @@ export default function KnowledgeBasePage() { useEffect(() => { getKBArticles() .then(setArticles) - .catch(() => { - setArticles([ - { id: 1, title: "Cómo configurar tu correo en Outlook", content: "Guía paso a paso para configurar...", category: "Correo", publishedAt: "2026-09-01" }, - { id: 2, title: "Solicitar acceso a una carpeta compartida", content: "Proceso para solicitar acceso...", category: "Acceso", publishedAt: "2026-09-02" }, - { id: 3, title: "Problemas comunes con la impresora", content: "Soluciones a problemas frecuentes...", category: "Hardware", publishedAt: "2026-09-03" }, - { id: 4, title: "Instalación de software aprobado", content: "Lista de software aprobado y cómo instalarlo...", category: "Software", publishedAt: "2026-09-04" }, - { id: 5, title: "Conectar a la VPN corporativa", content: "Instrucciones para conectarse a la VPN...", category: "Red", publishedAt: "2026-09-05" }, - { id: 6, title: "Resetear tu contraseña", content: "Cómo restablecer tu contraseña del dominio...", category: "Acceso", publishedAt: "2026-09-06" }, - ]); - }) + .catch(() => setArticles([])) .finally(() => setLoading(false)); }, []); @@ -31,20 +22,12 @@ export default function KnowledgeBasePage() { const results = await searchKB(searchQuery); setArticles(results); } catch { - // Keep existing articles on error + // Keep existing } finally { setLoading(false); } }; - const categories = [ - { name: "Software", icon: "bi-laptop", color: "#0d6efd", count: articles.filter((a) => a.category === "Software").length }, - { name: "Hardware", icon: "bi-pc-display", color: "#198754", count: articles.filter((a) => a.category === "Hardware").length }, - { name: "Red", icon: "bi-wifi", color: "#6f42c1", count: articles.filter((a) => a.category === "Red").length }, - { name: "Acceso", icon: "bi-key", color: "#fd7e14", count: articles.filter((a) => a.category === "Acceso").length }, - { name: "Correo", icon: "bi-envelope", color: "#dc3545", count: articles.filter((a) => a.category === "Correo").length }, - ]; - return (
@@ -74,28 +57,11 @@ export default function KnowledgeBasePage() {
- {/* Categories */} -
- {categories.map((cat) => ( -
-
{ setSearchQuery(cat.name); handleSearch(); }} - > -
- -
{cat.name}
- {cat.count} artículos -
-
-
- ))} -
- {/* Articles List */}
- Artículos Recientes + Artículos
{loading ? ( @@ -125,7 +91,7 @@ export default function KnowledgeBasePage() {
{article.title}
- {article.category} · {new Date(article.publishedAt).toLocaleDateString("es-CL")} + {article.categoryName || "General"} · {article.authorName || "Autor"}
diff --git a/frontend/src/app/(app)/layout.tsx b/frontend/src/app/(app)/layout.tsx index 5a6d6ad..8ab2995 100644 --- a/frontend/src/app/(app)/layout.tsx +++ b/frontend/src/app/(app)/layout.tsx @@ -32,20 +32,16 @@ function AppShell({ children }: { children: React.ReactNode }) { return (
- {/* Sidebar Overlay for mobile */}
setSidebarOpen(false)} /> - {/* Sidebar */}
- {/* Main Content */}
- {/* Top Navbar */}
- {/* Page Content */}
{children}
@@ -84,18 +79,18 @@ function AppShell({ children }: { children: React.ReactNode }) { function TopNavbarUser() { const { user } = useAuth(); + const initials = user?.nombre + ?.split(" ") + .map((n: string) => n[0]) + .join("") + .toUpperCase() + .slice(0, 2) || "U"; + return (
-
- {user?.name - ?.split(" ") - .map((n) => n[0]) - .join("") - .toUpperCase() - .slice(0, 2) || "U"} -
+
{initials}
- {user?.name || "Usuario"} + {user?.nombre || "Usuario"}
); diff --git a/frontend/src/app/(app)/page.tsx b/frontend/src/app/(app)/page.tsx index 139a6cb..d4034e9 100644 --- a/frontend/src/app/(app)/page.tsx +++ b/frontend/src/app/(app)/page.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import StatsCard from "@/components/StatsCard"; import BadgeStatus from "@/components/BadgeStatus"; -import { getDashboardStats, type DashboardStats } from "@/lib/api"; +import { getTicketStats, type DashboardStats } from "@/lib/api"; import Link from "next/link"; export default function DashboardPage() { @@ -11,25 +11,18 @@ export default function DashboardPage() { const [loading, setLoading] = useState(true); useEffect(() => { - getDashboardStats() + getTicketStats() .then(setStats) .catch(() => { - // Set mock data for demo setStats({ - totalTickets: 128, - openTickets: 24, - pendingTickets: 18, - resolvedTickets: 62, - closedTickets: 24, - avgResponseTime: "2.4h", - ticketsByPriority: { low: 30, medium: 45, high: 38, urgent: 15 }, - recentTickets: [], - agentWorkload: [ - { agent: "Carlos Méndez", count: 12 }, - { agent: "Ana García", count: 9 }, - { agent: "Roberto Díaz", count: 7 }, - { agent: "María López", count: 5 }, - ], + totalTickets: 0, + openTickets: 0, + inProgressTickets: 0, + resolvedTickets: 0, + closedTickets: 0, + unassignedTickets: 0, + criticalTickets: 0, + dailyCounts: [], }); }) .finally(() => setLoading(false)); @@ -43,8 +36,7 @@ export default function DashboardPage() { ); } - const maxPriority = Math.max(...Object.values(stats?.ticketsByPriority || {}), 1); - const maxWorkload = Math.max(...(stats?.agentWorkload?.map((a) => a.count) || [1])); + const maxDaily = Math.max(...(stats?.dailyCounts?.map((d) => d.count) || [1])); return (
@@ -65,140 +57,45 @@ export default function DashboardPage() {
- +
- + +
+
+
-
- {/* Priority Distribution */} -
-
-
- - Tickets por Prioridad -
-
- {Object.entries(stats?.ticketsByPriority || {}).map(([priority, count]) => { - const labels: Record = { low: "Baja", medium: "Media", high: "Alta", urgent: "Urgente" }; - const colors: Record = { low: "#6c757d", medium: "#0d6efd", high: "#fd7e14", urgent: "#dc3545" }; - return ( -
-
- {labels[priority] || priority} - {count} -
-
-
-
-
- ); - })} -
+ {/* Daily Tickets Chart */} + {stats?.dailyCounts && stats.dailyCounts.length > 0 && ( +
+
+ + Tickets por Día (últimos 30 días)
-
- - {/* Agent Workload */} -
-
-
- - Carga de Agentes -
-
- {stats?.agentWorkload?.map((item) => ( -
-
- {item.agent} - {item.count} tickets -
-
-
-
-
+
+
+ {stats.dailyCounts.map((d) => ( +
))} - - {(!stats?.agentWorkload || stats.agentWorkload.length === 0) && ( -
- - Sin datos de agentes disponibles -
- )}
-
- - {/* Recent Tickets */} -
-
-
- - Tickets Recientes -
- - Ver todos - -
-
- - - - - - - - - - - - - {stats?.recentTickets?.length ? ( - stats.recentTickets.map((ticket) => ( - window.location.href = `/tickets/${ticket.id}`}> - - - - - - - - )) - ) : ( - - - - )} - -
#AsuntoSolicitanteEstadoPrioridadActualizado
- {ticket.ticketNumber || `#${ticket.id}`} - {ticket.subject}{ticket.requester?.name || "N/A"}{ticket.priority}{new Date(ticket.updatedAt).toLocaleDateString("es-CL")}
- - No hay tickets recientes -
-
-
+ )}
); } diff --git a/frontend/src/app/(app)/tickets/[id]/page.tsx b/frontend/src/app/(app)/tickets/[id]/page.tsx index 27e6fe1..3f9cb62 100644 --- a/frontend/src/app/(app)/tickets/[id]/page.tsx +++ b/frontend/src/app/(app)/tickets/[id]/page.tsx @@ -1,21 +1,26 @@ "use client"; import { useEffect, useState } from "react"; -import { useParams, useRouter } from "next/navigation"; -import { getTicket, addComment, updateTicketStatus, assignTicket, getAgents, type Ticket, type User } from "@/lib/api"; +import { useParams } from "next/navigation"; +import { + getTicket, + getComments, + addComment, + updateTicketStatus, + assignTicket, + type Ticket, + type Comment, +} from "@/lib/api"; import BadgeStatus from "@/components/BadgeStatus"; import BadgePriority from "@/components/BadgePriority"; -import { useAuth } from "@/lib/auth"; import Link from "next/link"; export default function TicketDetailPage() { const params = useParams(); - const router = useRouter(); - const { user } = useAuth(); - const id = params.id as string; + const id = Number(params.id); const [ticket, setTicket] = useState(null); - const [agents, setAgents] = useState([]); + const [comments, setComments] = useState([]); const [loading, setLoading] = useState(true); const [comment, setComment] = useState(""); const [isInternal, setIsInternal] = useState(false); @@ -23,33 +28,14 @@ export default function TicketDetailPage() { useEffect(() => { Promise.all([ - getTicket(id).catch(() => ({ - id: parseInt(id), - ticketNumber: "#TK-" + id.padStart(3, "0"), - subject: "No puedo acceder al sistema de correo electrónico desde esta mañana", - description: "Buenos días, desde esta mañana no puedo acceder a mi correo electrónico. Ya intenté reiniciar la computadora pero el problema persiste. Necesito acceso urgente para revisar correos importantes del proyecto.", - status: "open", - priority: "high", - category: "Software", - requesterId: 1, - groupId: null, - requester: { id: 1, name: "María García", email: "maria@test.com", role: "customer" as const }, - assigneeId: 2, - assignee: { id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" as const }, - group: { id: 1, name: "Soporte TI" }, - comments: [ - { id: 1, ticketId: parseInt(id), userId: 2, user: { id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" as const }, content: "Estoy revisando el problema. Verificaré la configuración de su cuenta de correo.", isInternal: false, createdAt: "2026-09-07T10:30:00Z" }, - { id: 2, ticketId: parseInt(id), userId: 1, user: { id: 1, name: "María García", email: "maria@test.com", role: "customer" as const }, content: "Gracias, estoy esperando. Necesito acceso lo antes posible.", isInternal: false, createdAt: "2026-09-07T11:15:00Z" }, - { id: 3, ticketId: parseInt(id), userId: 2, user: { id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" as const }, content: "Nota interna: Verificar con el equipo de infra si hay problemas con el servidor de Exchange.", isInternal: true, createdAt: "2026-09-07T11:30:00Z" }, - ], - createdAt: "2026-09-07T09:00:00Z", - updatedAt: "2026-09-07T11:30:00Z", - } as Ticket)), - getAgents().catch(() => []), - ]).then(([ticketData, agentsData]) => { - setTicket(ticketData); - setAgents(agentsData); - }).finally(() => setLoading(false)); + getTicket(id).catch(() => null), + getComments(id).catch(() => []), + ]) + .then(([ticketData, commentsData]) => { + setTicket(ticketData); + setComments(commentsData); + }) + .finally(() => setLoading(false)); }, [id]); const handleAddComment = async (e: React.FormEvent) => { @@ -57,29 +43,13 @@ export default function TicketDetailPage() { if (!comment.trim()) return; setSubmitting(true); try { - const newComment = await addComment(id, comment, isInternal); - setTicket((prev) => { - if (!prev) return prev; - return { ...prev, comments: [...(prev.comments || []), newComment] }; - }); + await addComment(id, comment, isInternal); + const updated = await getComments(id).catch(() => []); + setComments(updated); setComment(""); setIsInternal(false); } catch { - // Add locally for demo - if (ticket) { - const localComment = { - id: Date.now(), - ticketId: parseInt(id), - userId: user?.id || 0, - user: user || { id: 0, name: "Usuario", email: "", role: "agent" as const }, - content: comment, - isInternal, - createdAt: new Date().toISOString(), - }; - setTicket({ ...ticket, comments: [...(ticket.comments || []), localComment] }); - setComment(""); - setIsInternal(false); - } + // ignore } finally { setSubmitting(false); } @@ -87,19 +57,8 @@ export default function TicketDetailPage() { const handleStatusChange = async (newStatus: string) => { try { - await updateTicketStatus(id, parseInt(newStatus)); - if (ticket) setTicket({ ...ticket, status: newStatus }); - } catch { - if (ticket) setTicket({ ...ticket, status: newStatus }); - } - }; - - const handleAssign = async (agentId: string) => { - if (!agentId) return; - try { - await assignTicket(id, parseInt(agentId)); - const agent = agents.find((a) => a.id === parseInt(agentId)); - if (ticket && agent) setTicket({ ...ticket, assigneeId: agent.id, assignee: agent }); + await updateTicketStatus(id, newStatus); + setTicket((prev) => (prev ? { ...prev, status: newStatus } : prev)); } catch { // ignore } @@ -132,9 +91,9 @@ export default function TicketDetailPage() { - {ticket.ticketNumber || `#${ticket.id}`} + {ticket.ticketNumber}
-

{ticket.subject}

+

{ticket.title}

@@ -148,11 +107,11 @@ export default function TicketDetailPage() {
    {[ - { value: "open", label: "Abierto" }, - { value: "pending", label: "Pendiente" }, - { value: "in_progress", label: "En Progreso" }, - { value: "resolved", label: "Resuelto" }, - { value: "closed", label: "Cerrado" }, + { value: "Open", label: "Abierto" }, + { value: "Pending", label: "Pendiente" }, + { value: "InProgress", label: "En Progreso" }, + { value: "Resolved", label: "Resuelto" }, + { value: "Closed", label: "Cerrado" }, ].map((s) => (
    • - {agents.map((a) => ( -
    • - -
    • - ))} +
    • + +
@@ -187,36 +144,31 @@ export default function TicketDetailPage() {
- Comentarios ({ticket.comments?.length || 0}) + Comentarios ({comments.length})
- {ticket.comments?.length ? ( - ticket.comments.map((c) => { - const isAgent = c.user?.role === "agent" || c.user?.role === "admin"; - return ( -
-
-
- {c.user?.name || "Usuario"} - {c.isInternal && ( - - Nota Interna - - )} -
-
{c.content}
-
- {new Date(c.createdAt).toLocaleString("es-CL")} -
+ {comments.length > 0 ? ( + comments.map((c) => ( +
+
+
+ {c.userName || "Usuario"} + {c.isInternal && ( + + Nota Interna + + )} +
+
{c.content}
+
+ {new Date(c.createdAt).toLocaleString("es-CL")}
- ); - }) +
+ )) ) : (
@@ -250,7 +202,7 @@ export default function TicketDetailPage() { />
@@ -278,23 +229,19 @@ export default function TicketDetailPage() {
Información del Ticket
Solicitante - {ticket.requester?.name || "N/A"} + {ticket.requesterName || "N/A"}
Email - {ticket.requester?.email || "N/A"} + {ticket.requesterEmail || "N/A"}
Asignado a - {ticket.assignee?.name || "Sin asignar"} + {ticket.assigneeName || "Sin asignar"}
Grupo - {ticket.group?.name || "N/A"} -
-
- Categoría - {ticket.category || "N/A"} + {ticket.groupName || "N/A"}
Creado diff --git a/frontend/src/app/(app)/tickets/new/page.tsx b/frontend/src/app/(app)/tickets/new/page.tsx index ee8430a..29eb547 100644 --- a/frontend/src/app/(app)/tickets/new/page.tsx +++ b/frontend/src/app/(app)/tickets/new/page.tsx @@ -1,42 +1,26 @@ "use client"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useRouter } from "next/navigation"; -import { createTicket, getAgents, type User } from "@/lib/api"; +import { createTicket } from "@/lib/api"; import Link from "next/link"; export default function NewTicketPage() { const router = useRouter(); - const [agents, setAgents] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); - const [subject, setSubject] = useState(""); + const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); - const [priority, setPriority] = useState("medium"); - const [category, setCategory] = useState(""); - const [assigneeId, setAssigneeId] = useState(""); - - useEffect(() => { - getAgents().catch((): User[] => [ - { id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" as const }, - { id: 4, name: "Ana García", email: "ana@test.com", role: "agent" as const }, - ]).then((data) => setAgents(data)); - }, []); + const [priority, setPriority] = useState("Medium"); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(""); setLoading(true); try { - const ticket = await createTicket({ - subject, - description, - priority, - category, - assigneeId: assigneeId ? parseInt(assigneeId) : undefined, - }); - router.push(`/tickets/${ticket.id}`); + const result = await createTicket({ title, description, priority }); + router.push(`/tickets/${result.id}`); } catch (err: any) { setError(err.message || "Error al crear el ticket"); } finally { @@ -73,8 +57,8 @@ export default function NewTicketPage() { type="text" className="form-control" placeholder="Describe brevemente el problema o solicitud" - value={subject} - onChange={(e) => setSubject(e.target.value)} + value={title} + onChange={(e) => setTitle(e.target.value)} required autoFocus /> @@ -92,52 +76,19 @@ export default function NewTicketPage() { >
-
-
- - -
- -
- - -
- -
- - -
+
+ +
@@ -179,7 +130,6 @@ export default function NewTicketPage() {
  • Sé específico en el asunto del ticket
  • Incluye pasos para reproducir el problema
  • Adjunta capturas de pantalla si es posible
  • -
  • Selecciona la categoría correcta para una atención más rápida
  • Asigna la prioridad adecuada según el impacto
  • diff --git a/frontend/src/app/(app)/tickets/page.tsx b/frontend/src/app/(app)/tickets/page.tsx index 1ef8f20..1966fde 100644 --- a/frontend/src/app/(app)/tickets/page.tsx +++ b/frontend/src/app/(app)/tickets/page.tsx @@ -29,16 +29,11 @@ export default function TicketsPage() { page, pageSize, }); - setTickets(data.tickets || []); + setTickets(data.items || []); setTotal(data.total || 0); } catch { - setTickets([ - { id: 1, ticketNumber: "#TK-001", subject: "No puedo acceder a mi correo", description: "", status: "open", priority: "high", category: "Software", requesterId: 1, groupId: null, requester: { id: 1, name: "María García", email: "maria@test.com", role: "customer" }, assigneeId: 2, assignee: { id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" }, createdAt: "2026-09-01", updatedAt: "2026-09-07" }, - { id: 2, ticketNumber: "#TK-002", subject: "Impresora del piso 3 no funciona", description: "", status: "pending", priority: "medium", category: "Hardware", requesterId: 3, groupId: null, requester: { id: 3, name: "Pedro Soto", email: "pedro@test.com", role: "customer" }, assigneeId: 4, assignee: { id: 4, name: "Ana García", email: "ana@test.com", role: "agent" }, createdAt: "2026-09-05", updatedAt: "2026-09-07" }, - { id: 3, ticketNumber: "#TK-003", subject: "Solicitud de acceso al sistema contable", description: "", status: "resolved", priority: "low", category: "Acceso", requesterId: 5, groupId: null, requester: { id: 5, name: "Laura Fuentes", email: "laura@test.com", role: "customer" }, assigneeId: null, createdAt: "2026-09-03", updatedAt: "2026-09-06" }, - { id: 4, ticketNumber: "#TK-004", subject: "Laptop con pantalla parpadeante", description: "", status: "in_progress", priority: "urgent", category: "Hardware", requesterId: 6, groupId: null, requester: { id: 6, name: "Roberto Díaz", email: "roberto@test.com", role: "customer" }, assigneeId: 2, assignee: { id: 2, name: "Carlos Méndez", email: "carlos@test.com", role: "agent" }, createdAt: "2026-09-08", updatedAt: "2026-09-08" }, - ]); - setTotal(4); + setTickets([]); + setTotal(0); } finally { setLoading(false); } @@ -74,11 +69,11 @@ export default function TicketsPage() { onChange={(e) => { setStatusFilter(e.target.value); setPage(1); }} > - - - - - + + + + +
    @@ -147,13 +142,12 @@ export default function TicketsPage() { {ticket.ticketNumber || `#${ticket.id}`} -
    {ticket.subject}
    - {ticket.category} +
    {ticket.title}
    - {ticket.requester?.name || "N/A"} + {ticket.requesterName || "N/A"} - {ticket.assignee?.name || Sin asignar} + {ticket.assigneeName || Sin asignar} {new Date(ticket.updatedAt).toLocaleDateString("es-CL")} diff --git a/frontend/src/app/(auth)/login/page.tsx b/frontend/src/app/(auth)/login/page.tsx index 5e99e82..1c77cd0 100644 --- a/frontend/src/app/(auth)/login/page.tsx +++ b/frontend/src/app/(auth)/login/page.tsx @@ -2,11 +2,10 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import Link from "next/link"; import { useAuth } from "@/lib/auth"; export default function LoginPage() { - const [email, setEmail] = useState(""); + const [rut, setRut] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); @@ -18,7 +17,7 @@ export default function LoginPage() { setError(""); setLoading(true); try { - await login(email, password); + await login(rut, password); router.push("/"); } catch (err: any) { setError(err.message || "Credenciales inválidas"); @@ -75,13 +74,13 @@ export default function LoginPage() {
    - + setEmail(e.target.value)} + placeholder="12.345.678-9" + value={rut} + onChange={(e) => setRut(e.target.value)} required autoFocus /> @@ -117,15 +116,6 @@ export default function LoginPage() { )} - -
    - - ¿No tienes cuenta?{" "} - - Regístrate aquí - - -
    diff --git a/frontend/src/app/(auth)/register/page.tsx b/frontend/src/app/(auth)/register/page.tsx deleted file mode 100644 index fd5ca43..0000000 --- a/frontend/src/app/(auth)/register/page.tsx +++ /dev/null @@ -1,169 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { useRouter } from "next/navigation"; -import Link from "next/link"; -import { register as apiRegister } from "@/lib/api"; -import { useAuth } from "@/lib/auth"; - -export default function RegisterPage() { - const [name, setName] = useState(""); - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); - const [error, setError] = useState(""); - const [loading, setLoading] = useState(false); - const { login } = useAuth(); - const router = useRouter(); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setError(""); - - if (password !== confirmPassword) { - setError("Las contraseñas no coinciden"); - return; - } - - setLoading(true); - try { - await apiRegister({ name, email, password }); - await login(email, password); - router.push("/"); - } catch (err: any) { - setError(err.message || "Error al registrar usuario"); - } finally { - setLoading(false); - } - }; - - return ( -
    - {/* Left Panel */} -
    -
    - -

    HelpDesk ICHN

    -

    - Crea tu cuenta para comenzar a gestionar tickets de soporte técnico - y acceder a la base de conocimiento. -

    -
    -
    - - Acceso completo al sistema -
    -
    - - Crear y responder tickets -
    -
    - - Buscar en la base de conocimiento -
    -
    -
    -
    - - {/* Right Panel - Form */} -
    -
    -
    - -

    HelpDesk ICHN

    -
    - -

    Crear Cuenta

    -

    Regístrate para acceder al sistema de soporte

    - - {error && ( -
    - - {error} -
    - )} - -
    -
    - - setName(e.target.value)} - required - autoFocus - /> -
    - -
    - - setEmail(e.target.value)} - required - /> -
    - -
    - - setPassword(e.target.value)} - required - minLength={6} - /> -
    - -
    - - setConfirmPassword(e.target.value)} - required - minLength={6} - /> -
    - - -
    - -
    - - ¿Ya tienes cuenta?{" "} - - Inicia sesión - - -
    -
    -
    -
    - ); -} diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index b7698e7..dcde24c 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -12,10 +12,15 @@ export default function Sidebar() { { href: "/", icon: "bi-speedometer2", label: "Dashboard" }, { href: "/tickets", icon: "bi-ticket-detailed", label: "Tickets" }, { href: "/knowledge-base", icon: "bi-journal-bookmark", label: "Knowledge Base" }, - { href: "/users", icon: "bi-people", label: "Users" }, - { href: "/settings", icon: "bi-gear", label: "Settings" }, ]; + const initials = user?.nombre + ?.split(" ") + .map((n: string) => n[0]) + .join("") + .toUpperCase() + .slice(0, 2) || "U"; + return (