136 lines
6.2 KiB
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>
|