Files
service_manager/frontend-internal/src/routes/+page.svelte

136 lines
6.2 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import { auth } from '$lib/stores/auth.js';
import { goto } from '$app/navigation';
import { dashboardConfig, ALL_MODULES, type DashboardModule } from '$lib/stores/dashboardConfig.js';
let showSettings = false;
onMount(() => {
if (!$auth.isAuthenticated) {
goto('/login');
}
});
const role = $auth.user?.role ?? '';
/** Only modules the current role can access */
$: accessibleModules = ALL_MODULES.filter(m => m.roles.includes(role) || role === 'ADMIN');
/** Modules that are visible (enabled by user + accessible by role) */
$: visibleModules = accessibleModules.filter(m => $dashboardConfig[m.id] !== false);
function toggleSettings() {
showSettings = !showSettings;
}
</script>
<svelte:head>
<title>Dashboard Admin - ServiceManager</title>
</svelte:head>
<div class="px-4 py-8 mx-auto max-w-7xl sm:px-6 lg:px-8">
<!-- Header -->
<div class="md:flex md:items-center md:justify-between">
<div class="flex-1 min-w-0">
<h2 class="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">
Panel de Administración
</h2>
<p class="mt-1 text-sm text-gray-500">
Bienvenido al sistema de gestión interna.
</p>
</div>
<div class="mt-4 flex md:mt-0 md:ml-4 gap-2">
<button
on:click={toggleSettings}
class="inline-flex items-center gap-1.5 px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Configurar
</button>
</div>
</div>
<!-- Settings Panel -->
{#if showSettings}
<div class="mt-6 bg-white border border-gray-200 rounded-lg shadow-sm p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-base font-semibold text-gray-900">Módulos visibles en el dashboard</h3>
<div class="flex gap-2">
<button
on:click={() => dashboardConfig.showAll()}
class="text-xs text-blue-600 hover:text-blue-800 underline"
>
Mostrar todos
</button>
</div>
</div>
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3">
{#each accessibleModules as mod}
<label class="flex items-center gap-2 p-3 border rounded-lg cursor-pointer hover:bg-gray-50 {$dashboardConfig[mod.id] !== false ? 'border-blue-300 bg-blue-50' : 'border-gray-200'}">
<input
type="checkbox"
checked={$dashboardConfig[mod.id] !== false}
on:change={() => dashboardConfig.toggle(mod.id)}
class="rounded text-blue-600 focus:ring-blue-500"
/>
<div class="min-w-0">
<div class="flex items-center gap-1.5">
<span class="w-2 h-2 rounded-full {mod.color} flex-shrink-0"></span>
<span class="text-sm font-medium text-gray-800 truncate">{mod.title}</span>
</div>
</div>
</label>
{/each}
</div>
<p class="mt-3 text-xs text-gray-400">Las preferencias se guardan automáticamente en este navegador.</p>
</div>
{/if}
<!-- Module Cards -->
{#if visibleModules.length === 0}
<div class="mt-10 text-center py-16 bg-white rounded-lg border-2 border-dashed border-gray-200">
<svg class="mx-auto h-10 w-10 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
</svg>
<p class="mt-3 text-sm text-gray-500">No hay módulos visibles.</p>
<button on:click={() => dashboardConfig.showAll()} class="mt-3 text-sm text-blue-600 hover:underline">
Restaurar todos los módulos
</button>
</div>
{:else}
<div class="mt-8 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{#each visibleModules as mod}
<a
href={mod.href}
class="bg-white overflow-hidden shadow rounded-lg hover:shadow-md transition-all duration-200 cursor-pointer group flex flex-col"
>
<div class="p-5 flex-1">
<div class="flex items-center gap-3 mb-2">
<div class="w-9 h-9 rounded-lg {mod.color} flex items-center justify-center flex-shrink-0">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d={mod.icon} />
</svg>
</div>
<span class="text-sm font-semibold text-gray-800 group-hover:text-blue-700 transition-colors">
{mod.title}
</span>
</div>
<p class="text-xs text-gray-500 leading-relaxed">{mod.description}</p>
</div>
<div class="bg-gray-50 px-5 py-2.5 border-t border-gray-100">
<span class="text-xs font-medium text-blue-600 group-hover:text-blue-800 transition-colors">
Abrir módulo →
</span>
</div>
</a>
{/each}
</div>
{/if}
</div>