- Extraccion de helpers en backend: audit_helpers.py, helpers.py - Modularizacion de schemas en archivos individuales por dominio - Reduccion de audit.py en 953 lineas (74% del archivo) - Reduccion de tickets.py en 655 lineas (60% del archivo) - Expansion de auth.py con recuperacion de contrasenia y tokens - Nuevos modulos: core/email.py, core/cache.py - Reorganizacion de scripts a backend/scripts/ - Frontend: refactorizacion de audit page con array-driven components - Frontend: correccion de 11 errores ortograficos en tickets page - Frontend: proxy Docker corregido en vite.config.js - Frontend: nuevas rutas forgot-password, reset-password, organization, profile - Nuevas utilidades TS: colorUtils.ts, dateFormats.ts - 5 nuevos archivos de tests unitarios en backend/tests/unit/ - Eliminacion de 3 scripts temporales de prueba - Documentacion tecnica: CAMBIOS_v1.10.0.md, OPTIMIZACIONES_RENDIMIENTO.md
152 lines
4.9 KiB
Svelte
152 lines
4.9 KiB
Svelte
<script lang="ts">
|
|
import { auth } from '$lib/stores/auth.js';
|
|
import { onMount } from 'svelte';
|
|
import Icon from './Icon.svelte';
|
|
|
|
export let showLogo = true;
|
|
export let showNavigation = true;
|
|
|
|
let isMenuOpen = false;
|
|
|
|
onMount(() => {
|
|
auth.init();
|
|
});
|
|
|
|
function toggleMenu() {
|
|
isMenuOpen = !isMenuOpen;
|
|
}
|
|
|
|
function handleLogout() {
|
|
isMenuOpen = false;
|
|
auth.logout(); // El store maneja la redirección automática
|
|
}
|
|
</script>
|
|
|
|
<header class="bg-white shadow-sm border-b border-gray-200">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex justify-between items-center h-16">
|
|
<!-- Logo -->
|
|
{#if showLogo}
|
|
<div class="flex items-center">
|
|
<a href="/" class="flex items-center space-x-2">
|
|
<div class="w-8 h-8 bg-primary-600 rounded-lg flex items-center justify-center">
|
|
<Icon name="ticket" size="w-5 h-5" className="text-white" />
|
|
</div>
|
|
<div class="hidden sm:block">
|
|
<h1 class="text-xl font-semibold text-gray-900">ServiceManager</h1>
|
|
<p class="text-xs text-gray-500">Mesa de Ayuda</p>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Navigation -->
|
|
{#if showNavigation && $auth.isAuthenticated}
|
|
<nav class="hidden md:flex space-x-8">
|
|
<a
|
|
href="/tickets"
|
|
class="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"
|
|
>
|
|
Mis Tickets
|
|
</a>
|
|
<a
|
|
href="/tickets/new"
|
|
class="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"
|
|
>
|
|
Crear Ticket
|
|
</a>
|
|
</nav>
|
|
{/if}
|
|
|
|
<!-- User menu -->
|
|
<div class="flex items-center space-x-4">
|
|
{#if $auth.isAuthenticated}
|
|
<div class="relative">
|
|
<button
|
|
on:click={toggleMenu}
|
|
class="flex items-center space-x-2 text-gray-700 hover:text-primary-600 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 rounded-md p-2"
|
|
tabindex="0"
|
|
on:keydown={e => e.key === 'Enter' && toggleMenu()}
|
|
>
|
|
<div class="w-8 h-8 bg-primary-100 rounded-full flex items-center justify-center">
|
|
<span class="text-primary-600 text-sm font-medium">
|
|
{$auth.user?.first_name?.[0]}{$auth.user?.last_name?.[0]}
|
|
</span>
|
|
</div>
|
|
<span class="hidden sm:block text-sm">
|
|
{$auth.user?.first_name}
|
|
{$auth.user?.last_name}
|
|
</span>
|
|
<Icon name="chevronDown" size="w-4 h-4" />
|
|
</button>
|
|
|
|
{#if isMenuOpen}
|
|
<div
|
|
class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg border border-gray-200 z-50"
|
|
>
|
|
<div class="py-1">
|
|
<div class="px-4 py-2 text-xs text-gray-500 border-b border-gray-200">
|
|
{$auth.user?.email}
|
|
</div>
|
|
<a
|
|
href="/profile"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
|
on:click={() => (isMenuOpen = false)}
|
|
>
|
|
Mi Perfil
|
|
</a>
|
|
<a
|
|
href="/organization"
|
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
|
on:click={() => (isMenuOpen = false)}
|
|
>
|
|
Mi Organización
|
|
</a>
|
|
<button
|
|
on:click={handleLogout}
|
|
class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100"
|
|
role="button"
|
|
tabindex="0"
|
|
on:keydown={e => e.key === 'Enter' && handleLogout()}
|
|
>
|
|
Cerrar Sesión
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
{:else}
|
|
<a href="/login" class="text-gray-700 hover:text-primary-600 text-sm font-medium">
|
|
Iniciar Sesión
|
|
</a>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mobile navigation -->
|
|
{#if showNavigation && $auth.isAuthenticated}
|
|
<div class="md:hidden border-t border-gray-200 py-2">
|
|
<nav class="flex space-x-4">
|
|
<a
|
|
href="/tickets"
|
|
class="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"
|
|
>
|
|
Mis Tickets
|
|
</a>
|
|
<a
|
|
href="/tickets/new"
|
|
class="text-gray-700 hover:text-primary-600 px-3 py-2 text-sm font-medium"
|
|
>
|
|
Crear Ticket
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Backdrop for mobile menu -->
|
|
{#if isMenuOpen}
|
|
<div class="fixed inset-0 z-40 md:hidden" on:click={() => (isMenuOpen = false)} />
|
|
{/if}
|