Spaces:
Running
Running
| <template> | |
| <v-main class="pref-main"> | |
| <v-container class="pref-container" style="max-width:680px"> | |
| <!-- Topbar nav --> | |
| <div class="pref-topbar"> | |
| <v-btn variant="text" size="small" prepend-icon="mdi-arrow-left" @click="router.back()">Volver</v-btn> | |
| <div class="pref-brand"> | |
| <v-icon color="amber-darken-1" size="16" class="mr-1">mdi-cog-outline</v-icon> | |
| <span class="pref-brand-text">Preferencias</span> | |
| </div> | |
| <v-btn variant="text" size="small" append-icon="mdi-chat-outline" to="/chat">Chat</v-btn> | |
| </div> | |
| <!-- Contraseña --> | |
| <v-card class="pref-card" rounded="xl" elevation="0"> | |
| <v-card-item> | |
| <template #prepend><v-icon color="primary" size="20">mdi-lock-outline</v-icon></template> | |
| <v-card-title class="pref-stitle">Contraseña</v-card-title> | |
| </v-card-item> | |
| <v-card-text> | |
| <div class="pwd-grid"> | |
| <v-text-field | |
| v-model="oldPwd" | |
| label="Contraseña actual" | |
| :type="showOld ? 'text' : 'password'" | |
| variant="outlined" | |
| density="comfortable" | |
| :append-inner-icon="showOld ? 'mdi-eye-off-outline' : 'mdi-eye-outline'" | |
| hide-details | |
| @click:append-inner="showOld = !showOld" | |
| /> | |
| <v-text-field | |
| v-model="newPwd" | |
| label="Nueva contraseña" | |
| :type="showNew ? 'text' : 'password'" | |
| variant="outlined" | |
| density="comfortable" | |
| :append-inner-icon="showNew ? 'mdi-eye-off-outline' : 'mdi-eye-outline'" | |
| hide-details | |
| @click:append-inner="showNew = !showNew" | |
| /> | |
| </div> | |
| <v-alert v-if="pwdMsg.text" :type="pwdMsg.type" variant="tonal" density="compact" rounded="lg" class="mt-3"> | |
| {{ pwdMsg.text }} | |
| </v-alert> | |
| <v-btn | |
| color="primary" | |
| variant="flat" | |
| rounded="lg" | |
| class="mt-3" | |
| :loading="pwdLoading" | |
| :disabled="!oldPwd || !newPwd" | |
| @click="changePassword" | |
| > | |
| Actualizar contraseña | |
| </v-btn> | |
| </v-card-text> | |
| </v-card> | |
| </v-container> | |
| </v-main> | |
| </template> | |
| <script setup> | |
| import { ref } from "vue"; | |
| import { useRouter } from "vue-router"; | |
| import API_BASE_URL from "../config.js"; | |
| const router = useRouter(); | |
| const oldPwd = ref(""); | |
| const newPwd = ref(""); | |
| const showOld = ref(false); | |
| const showNew = ref(false); | |
| const pwdLoading = ref(false); | |
| const pwdMsg = ref({ text: "", type: "success" }); | |
| async function changePassword() { | |
| pwdMsg.value = { text: "", type: "success" }; | |
| if (newPwd.value.length < 6) { | |
| pwdMsg.value = { text: "La nueva contraseña debe tener al menos 6 caracteres.", type: "error" }; | |
| return; | |
| } | |
| pwdLoading.value = true; | |
| try { | |
| const res = await fetch(`${API_BASE_URL}/auth/password`, { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ | |
| token: localStorage.getItem("vs_token") || "", | |
| old_password: oldPwd.value, | |
| new_password: newPwd.value, | |
| }), | |
| }); | |
| const data = await res.json(); | |
| if (!res.ok) { pwdMsg.value = { text: data.error || "Error al actualizar.", type: "error" }; return; } | |
| pwdMsg.value = { text: "Contraseña actualizada correctamente.", type: "success" }; | |
| oldPwd.value = newPwd.value = ""; | |
| } catch { | |
| pwdMsg.value = { text: "Error de conexión.", type: "error" }; | |
| } finally { | |
| pwdLoading.value = false; | |
| } | |
| } | |
| </script> | |
| <style scoped> | |
| .pref-main { min-height: 100vh; } | |
| .pref-container { padding: 24px 20px 48px; } | |
| .pref-topbar { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 28px; | |
| } | |
| .pref-brand { display: flex; align-items: center; } | |
| .pref-brand-text { font-family: "Fraunces", serif; font-size: 1rem; font-weight: 700; color: var(--vs-text); } | |
| .pref-card { | |
| border: 1.5px solid var(--vs-border) ; | |
| background: var(--vs-panel) ; | |
| backdrop-filter: blur(12px); | |
| } | |
| .pref-stitle { font-size: 0.9rem ; font-weight: 700 ; color: var(--vs-text) ; } | |
| .pwd-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } | |
| @media (max-width: 540px) { .pwd-grid { grid-template-columns: 1fr; } } | |
| </style> | |