mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 14:13:18 +00:00
111 lines
3 KiB
Vue
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>
|