Añadida implementacion de resetear contraseña

This commit is contained in:
2025-11-29 19:11:33 -03:00
parent b60a2bb32f
commit 3068280b82
4 changed files with 160 additions and 7 deletions

View File

@@ -5,15 +5,40 @@
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 type { UserResponseDto } from '../../types';
import Button from './ui/button/button.svelte';
import KeyIcon from '@lucide/svelte/icons/key';
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 { Dialog } from './ui/dialog';
import DialogContent from './ui/dialog/dialog-content.svelte';
interface Props {
usuarios: UserResponseDto[];
}
let { usuarios }: Props = $props();
let open = $state(false);
//si ponia contraseña en español quedaba muy largo el nombre
let usuarioCambioPass: UserResponseDto | null = $state(null);
$effect(() => {
if (!open) {
usuarioCambioPass = null;
}
});
function handleCambiarContraseña(usuario: UserResponseDto) {
open = true;
usuarioCambioPass = usuario;
}
</script>
<!-- {$inspect(usuarios)} -->
<Table>
<TableHeader>
<TableRow>
@@ -31,8 +56,20 @@
<TableCell>{usuario.displayName}</TableCell>
<TableCell>?</TableCell>
<TableCell>{usuario.createdAt.replace('Z', ' ').replace('T', ' | ')}</TableCell>
<TableCell>?</TableCell>
<TableCell class="flex gap-2">
<Tooltip>
<TooltipTrigger>
<Button onclick={() => handleCambiarContraseña(usuario)}><KeyIcon></KeyIcon></Button>
</TooltipTrigger>
<TooltipContent>
<p>Recuperar Contraseña</p>
</TooltipContent>
</Tooltip>
<Button></Button>
<Button></Button>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
<RecuperarContraseña bind:open usuario={usuarioCambioPass} />

View File

@@ -0,0 +1,88 @@
<script lang="ts">
import Key from '@lucide/svelte/icons/key';
import { Dialog } from '../ui/dialog';
import DialogContent from '../ui/dialog/dialog-content.svelte';
import InputGroupAddon from '../ui/input-group/input-group-addon.svelte';
import InputGroupInput from '../ui/input-group/input-group-input.svelte';
import InputGroup from '../ui/input-group/input-group.svelte';
import DialogTitle from '../ui/dialog/dialog-title.svelte';
import type { UserResponseDto } from '../../../types';
import DialogHeader from '../ui/dialog/dialog-header.svelte';
import { fade } from 'svelte/transition';
import { cambiarContraseña } from '@/hooks/cambiarContraseña';
import Button from '../ui/button/button.svelte';
import Spinner from '../ui/spinner/spinner.svelte';
interface Prop {
open: boolean;
usuario: UserResponseDto | null;
}
let { open = $bindable(), usuario }: Prop = $props();
let cargando = $state(false);
let error = $state('');
let nuevapass = $state('');
let openMensaje = $state(false);
async function onsubmit(e: SubmitEvent) {
cargando = true;
error = await cambiarContraseña(usuario!, nuevapass);
if (error === '') {
open = false;
nuevapass = '';
}
openMensaje = true;
cargando = false;
}
</script>
<div transition:fade>
<Dialog open={open && !!usuario} onOpenChange={() => (open = !open)}>
<DialogContent>
<DialogHeader>
<DialogTitle><p>Cambiar Contraseña</p></DialogTitle>
</DialogHeader>
<form {onsubmit}>
<InputGroup>
<InputGroupInput
disabled={cargando}
type="password"
name=""
minlength={8}
bind:value={nuevapass}
/>
<InputGroupAddon><Key /></InputGroupAddon>
<InputGroupAddon align="inline-end">
<p
class={{
'text-red-500': nuevapass.length < 8,
'text-blue-500': nuevapass.length >= 8
}}
>
{nuevapass.length}
</p>
/ 8
</InputGroupAddon>
</InputGroup>
<div class="mt-2 flex justify-between">
<Button type="submit" disabled={cargando}>
{#if cargando}
<Spinner />
{:else}
Aceptar
{/if}
</Button>
<Button variant="secondary" onclick={() => (open = false)} disabled={cargando}
>Cerrar</Button
>
</div>
</form>
</DialogContent>
</Dialog>
</div>
<div transition:fade>
<Dialog open={openMensaje} onOpenChange={() => (openMensaje = false)}>
{$inspect(error)}
<DialogContent>{error === '' ? 'Se modificó el usuario' : error}</DialogContent>
</Dialog>
</div>

View File

@@ -0,0 +1,24 @@
import { apiBase } from '@/stores/url';
import { get } from 'svelte/store';
import type { UserResponseDto } from '../../types';
import { sesionStore } from '@/stores/usuario';
export async function cambiarContraseña(usuario: UserResponseDto, newpass: string) {
try {
const req = await fetch(get(apiBase) + '/api/admin/password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${get(sesionStore)?.accessToken}`
},
body: JSON.stringify({ id: usuario.id, newpass })
});
if (req.ok) {
return '';
}
const data = await req.json();
return data.message;
} catch {
return 'No se pudo alcanzar el servidor';
}
}

View File

@@ -12,18 +12,22 @@
import TableCell from '@/components/ui/table/table-cell.svelte';
import { page } from '$app/state';
import TablaUsuarios from '@/components/TablaUsuarios.svelte';
import CardTitle from '@/components/ui/card/card-title.svelte';
import CardHeader from '@/components/ui/card/card-header.svelte';
let cargando = $state(true);
</script>
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
<div class="w-full max-w-6xl">
<h1
class="mb-4 scroll-m-20 text-center text-4xl font-extrabold tracking-tight text-balance underline"
>
Gestion Usuarios
</h1>
<Card class={page.data.error ? 'border-red-400' : ''}>
<CardHeader class="w-full">
<CardTitle class="rounded-full bg-accent-foreground/10">
<h1 class="mt-3 mb-4 scroll-m-20 text-center text-2xl font-extrabold tracking-tight">
Gestion Usuarios
</h1>
</CardTitle>
</CardHeader>
<CardContent>
{#if page.data.usuarios.length === 0}
{#if page.data.error}