refactor: enhance password change page with improved UI and functionality

- Updated the layout and styling of the password change page for a more modern and user-friendly experience.
- Integrated new icons and visual elements to enhance the overall design and accessibility.
- Improved form handling with better loading states and error messages for user feedback.
- Added security tips and password requirements to guide users during the password change process.
This commit is contained in:
2025-11-18 07:09:40 -03:00
parent 22e77d8890
commit af6353fa40
3 changed files with 343 additions and 341 deletions

View File

@@ -5,6 +5,7 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { Key, Eye, EyeOff, CheckCircle2, XCircle, Shield, Lock, AlertCircle, Info } from 'lucide-svelte';
const convex = useConvexClient(); const convex = useConvexClient();
const currentUser = useQuery(api.auth.getCurrentUser, {}); const currentUser = useQuery(api.auth.getCurrentUser, {});
@@ -136,127 +137,94 @@
} }
</script> </script>
<main class="container mx-auto max-w-2xl px-4 py-8"> <main class="container mx-auto max-w-4xl px-4 py-8">
<!-- Header --> <!-- Header Moderno -->
<div class="mb-8"> <div class="mb-8">
<div class="mb-2 flex items-center gap-3"> <div class="bg-linear-to-r from-primary/20 via-primary/10 to-primary/20 rounded-2xl p-6 mb-6 shadow-lg border border-primary/20">
<svg <div class="flex items-center gap-4">
xmlns="http://www.w3.org/2000/svg" <div class="p-3 bg-primary/20 rounded-2xl">
class="text-primary h-10 w-10" <Key class="h-8 w-8 text-primary" strokeWidth={2.5} />
fill="none" </div>
viewBox="0 0 24 24" <div class="flex-1">
stroke="currentColor" <h1 class="text-primary text-4xl font-bold mb-2">Alterar Senha</h1>
> <p class="text-base-content/70 text-lg">
<path Atualize sua senha de acesso ao sistema de forma segura
stroke-linecap="round" </p>
stroke-linejoin="round" </div>
stroke-width="2" <div class="badge badge-primary badge-lg gap-2">
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" <Shield class="h-4 w-4" strokeWidth={2} />
/> Seguro
</svg> </div>
<h1 class="text-primary text-4xl font-bold">Alterar Senha</h1>
</div> </div>
<p class="text-base-content/70 text-lg">Atualize sua senha de acesso ao sistema</p>
</div> </div>
<!-- Breadcrumbs --> <!-- Breadcrumbs -->
<div class="breadcrumbs mb-6 text-sm"> <div class="breadcrumbs text-sm mb-6">
<ul> <ul>
<li><a href={resolve('/')}>Dashboard</a></li> <li><a href={resolve('/')} class="link link-hover">Dashboard</a></li>
<li>Alterar Senha</li> <li>Alterar Senha</li>
</ul> </ul>
</div> </div>
</div>
<!-- Alertas --> <!-- Alertas -->
{#if notice} {#if notice}
<div class="alert {notice.type === 'success' ? 'alert-success' : 'alert-error'} mb-6 shadow-lg"> <div
<svg class="alert {notice.type === 'success'
xmlns="http://www.w3.org/2000/svg" ? 'alert-success'
class="h-6 w-6 shrink-0 stroke-current" : 'alert-error'} mb-6 shadow-xl animate-in fade-in slide-in-from-top duration-300"
fill="none"
viewBox="0 0 24 24"
> >
{#if notice.type === 'success'} {#if notice.type === 'success'}
<path <CheckCircle2 class="h-6 w-6 shrink-0 stroke-current" strokeWidth={2} />
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
{:else} {:else}
<path <XCircle class="h-6 w-6 shrink-0 stroke-current" strokeWidth={2} />
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
{/if} {/if}
</svg> <span class="font-semibold">{notice.message}</span>
<span>{notice.message}</span>
</div> </div>
{/if} {/if}
<!-- Formulário --> <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="card bg-base-100 border-base-300 border shadow-xl"> <!-- Formulário Principal -->
<div class="card-body"> <div class="lg:col-span-2">
<div
class="card bg-base-100 border-base-300/50 border-2 shadow-xl hover:shadow-2xl transition-all duration-300"
>
<div class="card-body p-8">
<div class="flex items-center gap-3 mb-6">
<div class="p-2 bg-primary/10 rounded-xl">
<Lock class="h-6 w-6 text-primary" strokeWidth={2} />
</div>
<h2 class="text-2xl font-bold text-base-content">Formulário de Alteração</h2>
</div>
<form onsubmit={handleSubmit} class="space-y-6"> <form onsubmit={handleSubmit} class="space-y-6">
<!-- Senha Atual --> <!-- Senha Atual -->
<div class="form-control"> <div class="form-control">
<label class="label" for="senha-atual"> <label class="label" for="senha-atual">
<span class="label-text font-semibold">Senha Atual</span> <span class="label-text font-semibold text-base">Senha Atual</span>
<span class="label-text-alt text-error">*</span> <span class="label-text-alt text-error font-bold">*</span>
</label> </label>
<div class="relative"> <div class="relative">
<input <input
id="senha-atual" id="senha-atual"
type={mostrarSenhaAtual ? 'text' : 'password'} type={mostrarSenhaAtual ? 'text' : 'password'}
placeholder="Digite sua senha atual" placeholder="Digite sua senha atual"
class="input input-bordered input-primary w-full pr-12" class="input input-bordered input-primary w-full pr-12 h-12 text-base"
bind:value={senhaAtual} bind:value={senhaAtual}
required required
disabled={carregando} disabled={carregando}
/> />
<button <button
type="button" type="button"
class="btn btn-sm btn-circle absolute top-1/2 right-3 -translate-y-1/2" class="btn btn-sm btn-ghost btn-circle absolute top-1/2 right-2 -translate-y-1/2 hover:bg-primary/10"
onclick={() => (mostrarSenhaAtual = !mostrarSenhaAtual)} onclick={() => (mostrarSenhaAtual = !mostrarSenhaAtual)}
disabled={carregando}
aria-label={mostrarSenhaAtual ? 'Ocultar senha' : 'Mostrar senha'}
> >
{#if mostrarSenhaAtual} {#if mostrarSenhaAtual}
<svg <EyeOff class="h-5 w-5 text-base-content/60" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
/>
</svg>
{:else} {:else}
<svg <Eye class="h-5 w-5 text-base-content/60" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
/>
</svg>
{/if} {/if}
</button> </button>
</div> </div>
@@ -265,66 +233,36 @@
<!-- Nova Senha --> <!-- Nova Senha -->
<div class="form-control"> <div class="form-control">
<label class="label" for="nova-senha"> <label class="label" for="nova-senha">
<span class="label-text font-semibold">Nova Senha</span> <span class="label-text font-semibold text-base">Nova Senha</span>
<span class="label-text-alt text-error">*</span> <span class="label-text-alt text-error font-bold">*</span>
</label> </label>
<div class="relative"> <div class="relative">
<input <input
id="nova-senha" id="nova-senha"
type={mostrarNovaSenha ? 'text' : 'password'} type={mostrarNovaSenha ? 'text' : 'password'}
placeholder="Digite sua nova senha" placeholder="Digite sua nova senha"
class="input input-bordered input-primary w-full pr-12" class="input input-bordered input-primary w-full pr-12 h-12 text-base"
bind:value={novaSenha} bind:value={novaSenha}
required required
disabled={carregando} disabled={carregando}
/> />
<button <button
type="button" type="button"
class="btn btn-sm btn-circle absolute top-1/2 right-3 -translate-y-1/2" class="btn btn-sm btn-ghost btn-circle absolute top-1/2 right-2 -translate-y-1/2 hover:bg-primary/10"
onclick={() => (mostrarNovaSenha = !mostrarNovaSenha)} onclick={() => (mostrarNovaSenha = !mostrarNovaSenha)}
disabled={carregando}
aria-label={mostrarNovaSenha ? 'Ocultar senha' : 'Mostrar senha'}
> >
{#if mostrarNovaSenha} {#if mostrarNovaSenha}
<svg <EyeOff class="h-5 w-5 text-base-content/60" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
/>
</svg>
{:else} {:else}
<svg <Eye class="h-5 w-5 text-base-content/60" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
/>
</svg>
{/if} {/if}
</button> </button>
</div> </div>
<div class="label"> <div class="label">
<span class="label-text-alt text-base-content/60"> <span class="label-text-alt text-base-content/60 text-xs">
Mínimo 8 caracteres, com letras maiúsculas, minúsculas, números e caracteres especiais Mínimo 8 caracteres com maiúsculas, minúsculas, números e especiais
</span> </span>
</div> </div>
</div> </div>
@@ -332,130 +270,56 @@
<!-- Confirmar Senha --> <!-- Confirmar Senha -->
<div class="form-control"> <div class="form-control">
<label class="label" for="confirmar-senha"> <label class="label" for="confirmar-senha">
<span class="label-text font-semibold">Confirmar Nova Senha</span> <span class="label-text font-semibold text-base">Confirmar Nova Senha</span>
<span class="label-text-alt text-error">*</span> <span class="label-text-alt text-error font-bold">*</span>
</label> </label>
<div class="relative"> <div class="relative">
<input <input
id="confirmar-senha" id="confirmar-senha"
type={mostrarConfirmarSenha ? 'text' : 'password'} type={mostrarConfirmarSenha ? 'text' : 'password'}
placeholder="Digite novamente sua nova senha" placeholder="Digite novamente sua nova senha"
class="input input-bordered input-primary w-full pr-12" class="input input-bordered input-primary w-full pr-12 h-12 text-base"
bind:value={confirmarSenha} bind:value={confirmarSenha}
required required
disabled={carregando} disabled={carregando}
/> />
<button <button
type="button" type="button"
class="btn btn-sm btn-circle absolute top-1/2 right-3 -translate-y-1/2" class="btn btn-sm btn-ghost btn-circle absolute top-1/2 right-2 -translate-y-1/2 hover:bg-primary/10"
onclick={() => (mostrarConfirmarSenha = !mostrarConfirmarSenha)} onclick={() => (mostrarConfirmarSenha = !mostrarConfirmarSenha)}
disabled={carregando}
aria-label={mostrarConfirmarSenha ? 'Ocultar senha' : 'Mostrar senha'}
> >
{#if mostrarConfirmarSenha} {#if mostrarConfirmarSenha}
<svg <EyeOff class="h-5 w-5 text-base-content/60" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"
/>
</svg>
{:else} {:else}
<svg <Eye class="h-5 w-5 text-base-content/60" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
/>
</svg>
{/if} {/if}
</button> </button>
</div> </div>
</div> </div>
<!-- Requisitos de Senha -->
<div class="alert alert-info">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 shrink-0 stroke-current"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<div>
<h3 class="font-bold">Requisitos de Senha:</h3>
<ul class="mt-2 list-inside list-disc space-y-1 text-sm">
<li>Mínimo de 8 caracteres</li>
<li>Pelo menos uma letra maiúscula (A-Z)</li>
<li>Pelo menos uma letra minúscula (a-z)</li>
<li>Pelo menos um número (0-9)</li>
<li>Pelo menos um caractere especial (!@#$%^&*...)</li>
</ul>
</div>
</div>
<!-- Botões --> <!-- Botões -->
<div class="mt-8 flex justify-end gap-4"> <div class="flex flex-col sm:flex-row justify-end gap-4 mt-8 pt-6 border-t border-base-300">
<button type="button" class="btn" onclick={cancelar} disabled={carregando}> <button
<svg type="button"
xmlns="http://www.w3.org/2000/svg" class="btn btn-outline btn-lg flex-1 sm:flex-initial"
class="h-5 w-5" onclick={cancelar}
fill="none" disabled={carregando}
viewBox="0 0 24 24"
stroke="currentColor"
> >
<path <XCircle class="h-5 w-5" strokeWidth={2} />
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Cancelar Cancelar
</button> </button>
<button type="submit" class="btn btn-primary" disabled={carregando}> <button
type="submit"
class="btn btn-primary btn-lg flex-1 sm:flex-initial shadow-lg hover:shadow-xl transition-all duration-200"
disabled={carregando}
>
{#if carregando} {#if carregando}
<span class="loading loading-spinner loading-sm"></span> <span class="loading loading-spinner loading-sm"></span>
Alterando... Alterando...
{:else} {:else}
<svg <CheckCircle2 class="h-5 w-5" strokeWidth={2} />
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7"
/>
</svg>
Alterar Senha Alterar Senha
{/if} {/if}
</button> </button>
@@ -463,34 +327,98 @@
</form> </form>
</div> </div>
</div> </div>
</div>
<!-- Dicas de Segurança --> <!-- Sidebar com Informações -->
<div class="card bg-base-200 mt-6 shadow-lg"> <div class="space-y-6">
<div class="card-body"> <!-- Requisitos de Senha -->
<h3 class="card-title text-lg"> <div
<svg class="card bg-linear-to-br from-info/10 to-info/5 border-2 border-info/20 shadow-lg"
xmlns="http://www.w3.org/2000/svg"
class="text-warning h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
> >
<path <div class="card-body p-6">
stroke-linecap="round" <div class="flex items-center gap-3 mb-4">
stroke-linejoin="round" <div class="p-2 bg-info/20 rounded-xl">
stroke-width="2" <Info class="h-6 w-6 text-info" strokeWidth={2} />
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" </div>
/> <h3 class="text-lg font-bold text-base-content">Requisitos de Senha</h3>
</svg> </div>
Dicas de Segurança <ul class="space-y-3 text-sm">
</h3> <li class="flex items-start gap-2">
<ul class="text-base-content/70 space-y-2 text-sm"> <CheckCircle2 class="h-5 w-5 text-success shrink-0 mt-0.5" strokeWidth={2} />
<li>✅ Nunca compartilhe sua senha com ninguém</li> <span class="text-base-content/80">Mínimo de 8 caracteres</span>
<li>✅ Use uma senha única para cada sistema</li> </li>
<li>✅ Altere sua senha regularmente</li> <li class="flex items-start gap-2">
<li>✅ Não use informações pessoais óbvias (nome, data de nascimento, etc.)</li> <CheckCircle2 class="h-5 w-5 text-success shrink-0 mt-0.5" strokeWidth={2} />
<li>✅ Considere usar um gerenciador de senhas</li> <span class="text-base-content/80">Pelo menos uma letra maiúscula (A-Z)</span>
</li>
<li class="flex items-start gap-2">
<CheckCircle2 class="h-5 w-5 text-success shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Pelo menos uma letra minúscula (a-z)</span>
</li>
<li class="flex items-start gap-2">
<CheckCircle2 class="h-5 w-5 text-success shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Pelo menos um número (0-9)</span>
</li>
<li class="flex items-start gap-2">
<CheckCircle2 class="h-5 w-5 text-success shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Pelo menos um caractere especial (!@#$%...)</span>
</li>
</ul> </ul>
</div> </div>
</div> </div>
<!-- Dicas de Segurança -->
<div
class="card bg-linear-to-br from-warning/10 to-warning/5 border-2 border-warning/20 shadow-lg"
>
<div class="card-body p-6">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-warning/20 rounded-xl">
<Shield class="h-6 w-6 text-warning" strokeWidth={2} />
</div>
<h3 class="text-lg font-bold text-base-content">Dicas de Segurança</h3>
</div>
<ul class="space-y-3 text-sm">
<li class="flex items-start gap-2">
<AlertCircle class="h-5 w-5 text-warning shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Nunca compartilhe sua senha</span>
</li>
<li class="flex items-start gap-2">
<AlertCircle class="h-5 w-5 text-warning shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Use uma senha única para cada sistema</span>
</li>
<li class="flex items-start gap-2">
<AlertCircle class="h-5 w-5 text-warning shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Altere sua senha regularmente</span>
</li>
<li class="flex items-start gap-2">
<AlertCircle class="h-5 w-5 text-warning shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Evite informações pessoais óbvias</span>
</li>
<li class="flex items-start gap-2">
<AlertCircle class="h-5 w-5 text-warning shrink-0 mt-0.5" strokeWidth={2} />
<span class="text-base-content/80">Considere usar um gerenciador de senhas</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</main> </main>
<style>
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-in {
animation: fade-in 0.3s ease-out;
}
</style>

View File

@@ -15,6 +15,7 @@ import type * as actions_smtp from "../actions/smtp.js";
import type * as actions_utils_nodeCrypto from "../actions/utils/nodeCrypto.js"; import type * as actions_utils_nodeCrypto from "../actions/utils/nodeCrypto.js";
import type * as atestadosLicencas from "../atestadosLicencas.js"; import type * as atestadosLicencas from "../atestadosLicencas.js";
import type * as ausencias from "../ausencias.js"; import type * as ausencias from "../ausencias.js";
import type * as autenticacao from "../autenticacao.js";
import type * as auth from "../auth.js"; import type * as auth from "../auth.js";
import type * as auth_utils from "../auth/utils.js"; import type * as auth_utils from "../auth/utils.js";
import type * as chamados from "../chamados.js"; import type * as chamados from "../chamados.js";
@@ -63,6 +64,7 @@ declare const fullApi: ApiFromModules<{
"actions/utils/nodeCrypto": typeof actions_utils_nodeCrypto; "actions/utils/nodeCrypto": typeof actions_utils_nodeCrypto;
atestadosLicencas: typeof atestadosLicencas; atestadosLicencas: typeof atestadosLicencas;
ausencias: typeof ausencias; ausencias: typeof ausencias;
autenticacao: typeof autenticacao;
auth: typeof auth; auth: typeof auth;
"auth/utils": typeof auth_utils; "auth/utils": typeof auth_utils;
chamados: typeof chamados; chamados: typeof chamados;

View File

@@ -0,0 +1,72 @@
import { mutation } from './_generated/server';
import { v } from 'convex/values';
import { updatePassword } from './auth';
import { authComponent } from './auth';
/**
* Alterar senha do usuário autenticado
*/
export const alterarSenha = mutation({
args: {
token: v.string(), // Token não é usado, mas mantido para compatibilidade
senhaAtual: v.string(),
novaSenha: v.string()
},
returns: v.union(
v.object({ sucesso: v.literal(true) }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args) => {
try {
// Verificar se o usuário está autenticado
const authUser = await authComponent.safeGetAuthUser(ctx);
if (!authUser) {
return {
sucesso: false as const,
erro: 'Usuário não autenticado'
};
}
// Validar que a nova senha não está vazia
if (!args.novaSenha || args.novaSenha.trim().length === 0) {
return {
sucesso: false as const,
erro: 'A nova senha não pode estar vazia'
};
}
// Chamar a função de atualização de senha
await updatePassword(ctx, {
currentPassword: args.senhaAtual,
newPassword: args.novaSenha
});
return {
sucesso: true as const
};
} catch (error: any) {
// Capturar erros específicos do Better Auth
let mensagemErro = 'Erro ao alterar senha';
if (error?.message) {
mensagemErro = error.message;
} else if (typeof error === 'string') {
mensagemErro = error;
}
// Mensagens de erro mais amigáveis
if (mensagemErro.toLowerCase().includes('password') ||
mensagemErro.toLowerCase().includes('senha') ||
mensagemErro.toLowerCase().includes('incorrect') ||
mensagemErro.toLowerCase().includes('incorreta')) {
mensagemErro = 'Senha atual incorreta';
}
return {
sucesso: false as const,
erro: mensagemErro
};
}
}
});