mirror of
https://github.com/emailerfacu-spec/minix-front.git
synced 2026-04-11 14:50:44 -03:00
287 lines
8.6 KiB
Svelte
287 lines
8.6 KiB
Svelte
<script lang="ts">
|
|
import TableBody from '@/components/ui/table/table-body.svelte';
|
|
import TableCell from '@/components/ui/table/table-cell.svelte';
|
|
import TableHead from '@/components/ui/table/table-head.svelte';
|
|
import TableHeader from '@/components/ui/table/table-header.svelte';
|
|
import TableRow from '@/components/ui/table/table-row.svelte';
|
|
import Table from '@/components/ui/table/table.svelte';
|
|
import type { UserResponseDto } from '../../types';
|
|
import Button from './ui/button/button.svelte';
|
|
import KeyIcon from '@lucide/svelte/icons/key';
|
|
import UserPen from '@lucide/svelte/icons/user-pen';
|
|
import Shield from '@lucide/svelte/icons/shield';
|
|
import Search from '@lucide/svelte/icons/search';
|
|
import Plus from '@lucide/svelte/icons/plus';
|
|
import { Tooltip } from './ui/tooltip';
|
|
import TooltipTrigger from './ui/tooltip/tooltip-trigger.svelte';
|
|
import TooltipContent from './ui/tooltip/tooltip-content.svelte';
|
|
import RecuperarContraseña from './admin/RecuperarContraseña.svelte';
|
|
import ModificarUsuario from './admin/ModificarUsuario.svelte';
|
|
import Trash_2 from '@lucide/svelte/icons/trash-2';
|
|
import BorrarUsuario from './BorrarUsuario.svelte';
|
|
import InputGroup from './ui/input-group/input-group.svelte';
|
|
import InputGroupAddon from './ui/input-group/input-group-addon.svelte';
|
|
import InputGroupInput from './ui/input-group/input-group-input.svelte';
|
|
import AgregarUsuario from './admin/AgregarUsuario.svelte';
|
|
import DarAdmin from './admin/DarAdmin.svelte';
|
|
import { busquedaAdminUsuarios } from '@/hooks/busquedaAdminUsuarios';
|
|
import { invalidate, replaceState } from '$app/navigation';
|
|
|
|
interface Props {
|
|
usuarios: UserResponseDto[];
|
|
hayMas: boolean;
|
|
}
|
|
|
|
let { usuarios = $bindable(), hayMas }: Props = $props();
|
|
|
|
let paginaActual = $derived.by(() => {
|
|
const url = new URL(window.location.href);
|
|
return Number(url.searchParams.get('p')) || 1;
|
|
});
|
|
let search = $derived.by(() => {
|
|
const url = new URL(window.location.href);
|
|
let ret = url.searchParams.get('q') || '';
|
|
return ret;
|
|
});
|
|
let hayMass = $derived(hayMas);
|
|
|
|
let open = $state(false);
|
|
let openModificarUsuario = $state(false);
|
|
let openDarAdmin = $state(false);
|
|
let openBorrar = $state(false);
|
|
let opencrearUsuario = $state(false);
|
|
|
|
let usuarioBorrar: UserResponseDto | null = $state(null);
|
|
let usuarioCambioPass: UserResponseDto | null = $state(null);
|
|
let usuarioModificar: UserResponseDto | null = $state(null);
|
|
let usuarioDarAdmin: UserResponseDto | null = $state(null);
|
|
|
|
type SortKey = 'username' | 'displayName' | 'postsCount' | 'createdAt';
|
|
let sortBy = $state<SortKey | null>(null);
|
|
let sortDirection = $state<'asc' | 'desc'>('asc');
|
|
|
|
let usuariosFiltrados = $derived(usuarios);
|
|
|
|
function ordenarPor(campo: SortKey) {
|
|
if (sortBy === campo) {
|
|
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
sortBy = campo;
|
|
sortDirection = 'asc';
|
|
}
|
|
usuariosFiltrados = usuariosFiltrados.toSorted((a, b) => {
|
|
if (!sortBy) return 0;
|
|
|
|
const key: SortKey = sortBy;
|
|
|
|
if (key === 'createdAt') {
|
|
const ta = new Date(a.createdAt).getTime();
|
|
const tb = new Date(b.createdAt).getTime();
|
|
return sortDirection === 'asc' ? ta - tb : tb - ta;
|
|
}
|
|
|
|
if (key === 'postsCount') {
|
|
return sortDirection === 'asc' ? a.postsCount - b.postsCount : b.postsCount - a.postsCount;
|
|
}
|
|
|
|
const sa = a[key].toString().toLowerCase();
|
|
const sb = b[key].toString().toLowerCase();
|
|
return sortDirection === 'asc' ? sa.localeCompare(sb) : sb.localeCompare(sa);
|
|
});
|
|
paginaActual = 1;
|
|
}
|
|
|
|
function getSortIcon(campo: SortKey) {
|
|
if (sortBy !== campo) return '';
|
|
return sortDirection === 'asc' ? '↑' : '↓';
|
|
}
|
|
|
|
// $inspect(usuarios);
|
|
let timeoutId: ReturnType<typeof setTimeout> | number | undefined;
|
|
function buscarUsuarios() {
|
|
if (timeoutId) {
|
|
clearTimeout(timeoutId);
|
|
}
|
|
|
|
timeoutId = setTimeout(async () => {
|
|
const url = new URL(window.location.href);
|
|
if (!search.trim()) {
|
|
url.searchParams.delete('q');
|
|
} else {
|
|
url.searchParams.set('q', search);
|
|
}
|
|
replaceState(url, {});
|
|
|
|
let ret = await busquedaAdminUsuarios(search, ITEMS_POR_PAGINA, paginaActual);
|
|
usuariosFiltrados = ret.usuarios;
|
|
// invalidate('admin:load');
|
|
hayMass = ret.hayMas;
|
|
}, 200);
|
|
|
|
return () => {
|
|
if (timeoutId) clearTimeout(timeoutId);
|
|
};
|
|
}
|
|
const ITEMS_POR_PAGINA = 5;
|
|
|
|
// const usuariosPaginados = $derived(
|
|
// usuariosFiltrados.slice((paginaActual - 1) * ITEMS_POR_PAGINA, paginaActual * ITEMS_POR_PAGINA)
|
|
// );
|
|
</script>
|
|
|
|
<div class="mb-4 flex gap-2">
|
|
<InputGroup>
|
|
<InputGroupAddon align="inline-start"><Search></Search></InputGroupAddon>
|
|
<InputGroupInput
|
|
type="text"
|
|
placeholder="Buscar usuario..."
|
|
bind:value={search}
|
|
oninput={() => buscarUsuarios()}
|
|
/>
|
|
</InputGroup>
|
|
<Button
|
|
onclick={() => (opencrearUsuario = !opencrearUsuario)}
|
|
variant="secondary"
|
|
class="bg-blue-500/20"><Plus /></Button
|
|
>
|
|
</div>
|
|
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead onclick={() => ordenarPor('username')} class="cursor-pointer select-none">
|
|
Usuario {getSortIcon('username')}
|
|
</TableHead>
|
|
<TableHead onclick={() => ordenarPor('displayName')} class="cursor-pointer select-none">
|
|
Nombre {getSortIcon('displayName')}
|
|
</TableHead>
|
|
<TableHead onclick={() => ordenarPor('postsCount')} class="cursor-pointer select-none">
|
|
Cantidad de posts {getSortIcon('postsCount')}
|
|
</TableHead>
|
|
<TableHead onclick={() => ordenarPor('createdAt')} class="cursor-pointer select-none">
|
|
Fecha de Creacion {getSortIcon('createdAt')}
|
|
</TableHead>
|
|
<TableHead>Acciones</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{#if usuariosFiltrados.length == 0}
|
|
<TableRow>
|
|
<TableCell colspan={5}>
|
|
<p class="text-center">No hay usuarios por el nombre de: {search}</p>
|
|
</TableCell>
|
|
</TableRow>{:else}
|
|
{#each usuariosFiltrados as usuario}
|
|
<TableRow>
|
|
<TableCell
|
|
>@<a href={'/' + usuario.username}>
|
|
{usuario.username}
|
|
</a>
|
|
</TableCell>
|
|
<TableCell>{usuario.displayName}</TableCell>
|
|
<TableCell class="text-center">{usuario.postsCount}</TableCell>
|
|
<TableCell>{usuario.createdAt.replace('Z', ' ').replace('T', ' | ')}</TableCell>
|
|
<TableCell class="flex gap-2">
|
|
<Tooltip>
|
|
<TooltipTrigger>
|
|
<Button
|
|
onclick={() => {
|
|
open = true;
|
|
usuarioCambioPass = usuario;
|
|
}}><KeyIcon></KeyIcon></Button
|
|
>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Recuperar Contraseña</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
<Tooltip>
|
|
<TooltipTrigger>
|
|
<Button
|
|
onclick={() => {
|
|
openModificarUsuario = true;
|
|
usuarioModificar = usuario;
|
|
}}><UserPen /></Button
|
|
>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Modificar Usuario</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
<Tooltip>
|
|
<TooltipTrigger>
|
|
<Button
|
|
disabled={usuario.isAdmin}
|
|
onclick={() => {
|
|
openBorrar = true;
|
|
usuarioBorrar = usuario;
|
|
}}
|
|
variant="destructive"><Trash_2 /></Button
|
|
>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
{#if usuario.isAdmin}
|
|
No se pueden eliminar usuarios Admin
|
|
{:else}
|
|
Eliminar Usuario
|
|
{/if}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<Tooltip>
|
|
<TooltipTrigger>
|
|
<Button
|
|
onclick={() => {
|
|
openDarAdmin = true;
|
|
usuarioDarAdmin = usuario;
|
|
}}
|
|
variant={usuario.isAdmin ? 'destructive' : 'default'}
|
|
>
|
|
<Shield />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
{#if usuario.isAdmin}
|
|
Sacar admin
|
|
{:else}
|
|
Dar Admin
|
|
{/if}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</TableCell>
|
|
</TableRow>
|
|
{/each}
|
|
{/if}
|
|
</TableBody>
|
|
</Table>
|
|
<div class="mt-4 flex items-center justify-between">
|
|
<Button
|
|
disabled={paginaActual === 1}
|
|
onclick={() => {
|
|
const url = new URL(window.location.href);
|
|
url.searchParams.set('p', String(--paginaActual));
|
|
replaceState(url, {});
|
|
buscarUsuarios();
|
|
}}
|
|
variant="secondary"
|
|
>
|
|
Anterior
|
|
</Button>
|
|
|
|
<Button
|
|
disabled={!hayMass}
|
|
onclick={() => {
|
|
const url = new URL(window.location.href);
|
|
url.searchParams.set('p', String(++paginaActual));
|
|
replaceState(url, {});
|
|
buscarUsuarios();
|
|
}}
|
|
variant="secondary">Siguiente</Button
|
|
>
|
|
</div>
|
|
<BorrarUsuario bind:open={openBorrar} usuario={usuarioBorrar} />
|
|
<RecuperarContraseña bind:open usuario={usuarioCambioPass} />
|
|
<ModificarUsuario bind:open={openModificarUsuario} bind:usuario={usuarioModificar} />
|
|
<AgregarUsuario bind:open={opencrearUsuario} />
|
|
<DarAdmin bind:open={openDarAdmin} usuario={usuarioDarAdmin} />
|