go-quasar-partial-ssr/frontend/src/pages/admin/dialogs/UserPasswordDialog.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>