153 lines
3.4 KiB
Vue
153 lines
3.4 KiB
Vue
<template>
|
|
<q-dialog v-model="isOpen">
|
|
<q-card class="password-card modal-card">
|
|
<q-card-section>
|
|
<div class="text-overline text-primary">Change password</div>
|
|
<div class="text-h6">{{ userEmail || 'User' }}</div>
|
|
</q-card-section>
|
|
|
|
<q-separator />
|
|
|
|
<q-card-section class="password-grid">
|
|
<q-input
|
|
v-model="formModel.password"
|
|
outlined
|
|
type="password"
|
|
label="New password"
|
|
hint="Minimo 8 caratteri"
|
|
/>
|
|
<q-input
|
|
v-model="formModel.confirmPassword"
|
|
outlined
|
|
type="password"
|
|
label="Confirm password"
|
|
/>
|
|
</q-card-section>
|
|
|
|
<q-card-actions align="right">
|
|
<q-btn flat color="grey-7" label="Chiudi" @click="isOpen = false" />
|
|
<q-btn color="primary" label="Salva password" :loading="saving" @click="savePasswordChange" />
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, reactive, ref, watch } from 'vue';
|
|
import { useQuasar } from 'quasar';
|
|
|
|
import { getUser, updatePassword } from 'src/api/users';
|
|
|
|
import type { PasswordFormState } from './types';
|
|
|
|
const props = defineProps<{
|
|
modelValue: boolean;
|
|
userId?: string;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [value: boolean];
|
|
saved: [];
|
|
}>();
|
|
|
|
const $q = useQuasar();
|
|
const saving = ref(false);
|
|
const userEmail = ref('');
|
|
const formModel = reactive<PasswordFormState>({
|
|
password: '',
|
|
confirmPassword: '',
|
|
});
|
|
|
|
const isOpen = computed({
|
|
get: () => props.modelValue,
|
|
set: (value: boolean) => emit('update:modelValue', value),
|
|
});
|
|
|
|
watch(
|
|
() => [props.modelValue, props.userId] as const,
|
|
([open, userId]) => {
|
|
if (!open || !userId) {
|
|
return;
|
|
}
|
|
|
|
void prepareDialog(userId);
|
|
},
|
|
{ immediate: true },
|
|
);
|
|
|
|
async function prepareDialog(userId: string): Promise<void> {
|
|
try {
|
|
const response = await getUser(userId);
|
|
if (response.error) {
|
|
throw new Error(response.error);
|
|
}
|
|
|
|
userEmail.value = response.data.email;
|
|
formModel.password = '';
|
|
formModel.confirmPassword = '';
|
|
} catch (error) {
|
|
notifyError(error);
|
|
isOpen.value = false;
|
|
}
|
|
}
|
|
|
|
async function savePasswordChange(): Promise<void> {
|
|
if (!props.userId) {
|
|
$q.notify({ type: 'negative', message: 'ID utente mancante.' });
|
|
return;
|
|
}
|
|
|
|
if (formModel.password.trim().length < 8) {
|
|
$q.notify({ type: 'negative', message: 'La password deve contenere almeno 8 caratteri.' });
|
|
return;
|
|
}
|
|
|
|
if (formModel.password !== formModel.confirmPassword) {
|
|
$q.notify({ type: 'negative', message: 'Le password non coincidono.' });
|
|
return;
|
|
}
|
|
|
|
saving.value = true;
|
|
try {
|
|
const response = await updatePassword({
|
|
id: props.userId,
|
|
password: formModel.password,
|
|
});
|
|
if (response.error) {
|
|
throw new Error(response.error);
|
|
}
|
|
|
|
isOpen.value = false;
|
|
$q.notify({ type: 'positive', message: `Password aggiornata per ${userEmail.value || 'utente'}.` });
|
|
emit('saved');
|
|
} catch (error) {
|
|
notifyError(error);
|
|
} finally {
|
|
saving.value = false;
|
|
}
|
|
}
|
|
|
|
function notifyError(error: unknown): void {
|
|
$q.notify({
|
|
type: 'negative',
|
|
message: error instanceof Error ? error.message : String(error),
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.modal-card {
|
|
width: min(96vw, 460px);
|
|
max-width: 460px;
|
|
}
|
|
|
|
.password-card {
|
|
border-radius: 20px;
|
|
}
|
|
|
|
.password-grid {
|
|
display: grid;
|
|
gap: 14px;
|
|
}
|
|
</style>
|