162 lines
5.3 KiB
Vue
162 lines
5.3 KiB
Vue
<template>
|
|
<div class="card dialog">
|
|
|
|
<div class="card-title">
|
|
{{ t('changePassword') }}
|
|
</div>
|
|
|
|
<div class="card-content">
|
|
<p class="description mb-4">{{ t('passwordDescription') }}</p>
|
|
|
|
<v-text-field v-model="newPassword" :label="t('newPassword')" :type="showNewPassword ? 'text' : 'password'"
|
|
variant="outlined" required :hint="t('passwordRequirements')">
|
|
<template v-slot:append-inner>
|
|
<v-icon @click="showNewPassword = !showNewPassword" class="visibility-toggle" size="small"
|
|
:icon="showNewPassword ? mdiEyeOff : mdiEye" />
|
|
</template>
|
|
</v-text-field>
|
|
|
|
<v-text-field v-model="confirmPassword" :label="t('confirmPassword')"
|
|
:type="showConfirmPassword ? 'text' : 'password'" variant="outlined" required>
|
|
<template v-slot:append-inner>
|
|
<v-icon @click="showConfirmPassword = !showConfirmPassword" class="visibility-toggle" size="small"
|
|
:icon="showNewPassword ? mdiEyeOff : mdiEye" />
|
|
</template>
|
|
</v-text-field>
|
|
|
|
<div v-if="errorMessage" class="error-message mb-4">
|
|
{{ errorMessage }}
|
|
</div>
|
|
|
|
<div class="card-actions">
|
|
<button class="secondary" @click="$emit('closeRequested')">
|
|
{{ t('cancel') }}
|
|
</button>
|
|
<button class="primary" @click="handleChangePassword" :disabled="isLoading">
|
|
{{ t('save') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue';
|
|
import { useAuthStore } from '@/stores/authStore.js';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
const { t } = useI18n();
|
|
const authStore = useAuthStore();
|
|
const emit = defineEmits(['closeRequested']);
|
|
|
|
const newPassword = ref('');
|
|
const confirmPassword = ref('');
|
|
const isLoading = ref(false);
|
|
const errorMessage = ref('');
|
|
const showNewPassword = ref(false);
|
|
const showConfirmPassword = ref(false);
|
|
|
|
async function handleChangePassword() {
|
|
// Clear previous error
|
|
errorMessage.value = '';
|
|
|
|
// Validate passwords match
|
|
if (newPassword.value !== confirmPassword.value) {
|
|
errorMessage.value = t('passwordsDoNotMatch');
|
|
return;
|
|
}
|
|
|
|
// Validate password length
|
|
if (newPassword.value.length < 8) {
|
|
errorMessage.value = t('passwordTooShort');
|
|
return;
|
|
}
|
|
|
|
isLoading.value = true;
|
|
|
|
try {
|
|
// Pass empty string for current password since we're already authenticated
|
|
// This will use the set-password endpoint for OAuth users
|
|
await authStore.changePassword(newPassword.value);
|
|
|
|
// Success - close dialog
|
|
emit('closeRequested');
|
|
|
|
// You could also emit a success event if needed
|
|
// emit('success');
|
|
} catch (error) {
|
|
console.error('Failed to change password:', error);
|
|
// Use error message from response if available, or the error message itself, or fallback
|
|
errorMessage.value = error.response?.data || error.message || t('passwordUpdateFailed');
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dialog {
|
|
@apply max-w-md mx-auto;
|
|
}
|
|
|
|
.error-message {
|
|
@apply text-red-500 text-sm mt-2;
|
|
}
|
|
|
|
.visibility-toggle {
|
|
@apply cursor-pointer;
|
|
@apply transition-opacity duration-300;
|
|
@apply opacity-60 hover:opacity-100;
|
|
@apply absolute right-2 top-1/2 transform -translate-y-1/2;
|
|
@apply z-10;
|
|
}
|
|
|
|
/* Override Vuetify's default padding to accommodate our icon */
|
|
:deep(.v-field__append-inner) {
|
|
padding-inline-start: 0;
|
|
}
|
|
</style>
|
|
|
|
<i18n>
|
|
{
|
|
"en": {
|
|
"changePassword": "Update Password",
|
|
"newPassword": "New Password",
|
|
"confirmPassword": "Confirm New Password",
|
|
"passwordRequirements": "Password must be at least 8 characters",
|
|
"passwordDescription": "Updating your password allows you to log in directly with your email and password.",
|
|
"save": "Save",
|
|
"cancel": "Cancel",
|
|
"passwordsDoNotMatch": "New passwords do not match",
|
|
"passwordTooShort": "Password must be at least 8 characters long",
|
|
"passwordUpdateFailed": "Failed to update password. Please try again."
|
|
},
|
|
"fr": {
|
|
"changePassword": "Modifier le mot de passe",
|
|
"newPassword": "Nouveau mot de passe",
|
|
"confirmPassword": "Confirmer le nouveau mot de passe",
|
|
"passwordRequirements": "Le mot de passe doit comporter au moins 8 caractères",
|
|
"passwordDescription": "La modification de votre mot de passe vous permet de vous connecter directement avec votre email et mot de passe.",
|
|
"save": "Enregistrer",
|
|
"cancel": "Annuler",
|
|
"passwordsDoNotMatch": "Les nouveaux mots de passe ne correspondent pas",
|
|
"passwordTooShort": "Le mot de passe doit comporter au moins 8 caractères",
|
|
"passwordUpdateFailed": "Échec de la mise à jour du mot de passe. Veuillez réessayer."
|
|
},
|
|
"es": {
|
|
"changePassword": "Actualizar contraseña",
|
|
"newPassword": "Nueva contraseña",
|
|
"confirmPassword": "Confirmar nueva contraseña",
|
|
"passwordRequirements": "La contraseña debe tener al menos 8 caracteres",
|
|
"passwordDescription": "La actualización de su contraseña le permite iniciar sesión directamente con su correo electrónico y contraseña.",
|
|
"save": "Guardar",
|
|
"cancel": "Cancelar",
|
|
"passwordsDoNotMatch": "Las nuevas contraseñas no coinciden",
|
|
"passwordTooShort": "La contraseña debe tener al menos 8 caracteres",
|
|
"passwordUpdateFailed": "Error al actualizar la contraseña. Por favor, inténtelo de nuevo."
|
|
}
|
|
}
|
|
|
|
</i18n>
|