panels-origin/web-panel/pages/cambiar-password.vue
2026-08-21 16:55:01 -05:00

111 lines
3 KiB
Vue

<template>
<div class="change-wrap">
<Card class="change-card">
<template #title>Cambiar contraseña</template>
<template #subtitle>Por seguridad debe definir una nueva contraseña antes de continuar.</template>
<template #content>
<form class="change-form" @submit.prevent="onSubmit">
<FloatLabel variant="on">
<Password
id="cur"
v-model="current"
:feedback="false"
toggle-mask
class="w-full"
input-class="w-full"
fluid
/>
<label for="cur">Contraseña temporal</label>
</FloatLabel>
<FloatLabel variant="on">
<Password
id="next"
v-model="next"
toggle-mask
class="w-full"
input-class="w-full"
fluid
/>
<label for="next">Nueva contraseña</label>
</FloatLabel>
<FloatLabel variant="on">
<Password
id="confirm"
v-model="confirm"
:feedback="false"
toggle-mask
class="w-full"
input-class="w-full"
fluid
/>
<label for="confirm">Confirmar</label>
</FloatLabel>
<Message v-if="error" severity="error" :closable="false">{{ error }}</Message>
<Button type="submit" label="Guardar y continuar" icon="pi pi-check" :loading="loading" />
</form>
</template>
</Card>
</div>
</template>
<script setup lang="ts">
definePageMeta({ layout: "auth" });
const { user, fetchMe } = useAuth();
const { api } = useApi();
const current = ref("");
const next = ref("");
const confirm = ref("");
const error = ref("");
const loading = ref(false);
async function onSubmit() {
error.value = "";
if (next.value !== confirm.value) {
error.value = "La confirmación no coincide";
return;
}
loading.value = true;
try {
const r = await api<{ user: NonNullable<typeof user.value> }>("/v1/auth/change-password", {
method: "POST",
json: { current_password: current.value, new_password: next.value },
});
user.value = r.user;
await fetchMe();
await navigateTo("/");
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : "No se pudo cambiar";
} finally {
loading.value = false;
}
}
onMounted(async () => {
if (!user.value) await fetchMe();
if (!user.value) await navigateTo("/login");
else if (!user.value.must_change_password) await navigateTo("/");
});
</script>
<style scoped>
.change-wrap {
min-height: 100vh;
display: grid;
place-items: center;
padding: 1.5rem;
background: linear-gradient(180deg, #f5f7fa 0%, #e8edf3 100%);
}
.change-card {
width: min(420px, 100%);
}
.change-form {
display: flex;
flex-direction: column;
gap: 1.1rem;
}
:global(html.dark) .change-wrap {
background: linear-gradient(180deg, #0f172a 0%, #0b1220 100%);
}
</style>