197 lines
4.9 KiB
Vue
197 lines
4.9 KiB
Vue
<template>
|
|
<q-page class="auth-page">
|
|
<div class="auth-shell auth-shell-wide">
|
|
<q-card flat bordered class="auth-card">
|
|
<q-card-section>
|
|
<div class="text-overline text-primary">Registrazione</div>
|
|
<div class="text-h4">Sign up</div>
|
|
<div class="text-body2 text-grey-7">Crea un nuovo utente.</div>
|
|
</q-card-section>
|
|
|
|
<q-separator />
|
|
|
|
<q-card-section>
|
|
<q-form v-if="!sent" class="auth-form" autocomplete="off" @submit.prevent="submit">
|
|
<q-input ref="firstNameRef" v-model="form.firstName" outlined label="Nome" autocomplete="off" />
|
|
<q-input v-model="form.lastName" outlined label="Cognome" autocomplete="off" />
|
|
<q-input v-model="form.email" outlined type="email" label="Email" autocomplete="off" />
|
|
<q-input
|
|
v-model="form.password"
|
|
outlined
|
|
type="password"
|
|
label="Password"
|
|
autocomplete="new-password"
|
|
/>
|
|
<q-input
|
|
v-model="form.confirmPassword"
|
|
outlined
|
|
type="password"
|
|
label="Ripeti password"
|
|
autocomplete="new-password"
|
|
/>
|
|
<q-checkbox
|
|
v-model="form.acceptTerms"
|
|
label="Accetto le condizioni"
|
|
/>
|
|
<div class="auth-actions">
|
|
<q-btn color="primary" label="Crea account" type="submit" :loading="loading" />
|
|
</div>
|
|
</q-form>
|
|
|
|
<div v-else class="success-state">
|
|
<q-icon name="task_alt" size="56px" color="positive" />
|
|
<div class="text-h6">Registrazione completata</div>
|
|
<div class="text-body2 text-grey-7">
|
|
Il tuo account e stato creato con successo.
|
|
</div>
|
|
<div class="success-actions">
|
|
<q-btn flat color="primary" label="Home" to="/" />
|
|
<q-btn color="primary" label="Login" to="/login" />
|
|
</div>
|
|
</div>
|
|
</q-card-section>
|
|
</q-card>
|
|
</div>
|
|
</q-page>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { nextTick, onMounted, reactive, ref, watch } from 'vue';
|
|
import { useQuasar } from 'quasar';
|
|
import { EnumUserStatus, register, type UserCreateRequest } from 'src/api/users';
|
|
|
|
const $q = useQuasar();
|
|
const loading = ref(false);
|
|
const sent = ref(false);
|
|
const firstNameRef = ref();
|
|
|
|
const form = reactive({
|
|
firstName: '',
|
|
lastName: '',
|
|
email: '',
|
|
password: '',
|
|
confirmPassword: '',
|
|
acceptTerms: false,
|
|
});
|
|
|
|
onMounted(async () => {
|
|
await focusFirstField();
|
|
});
|
|
|
|
watch(sent, async (value) => {
|
|
if (!value) {
|
|
await focusFirstField();
|
|
}
|
|
});
|
|
|
|
async function submit(): Promise<void> {
|
|
if (!form.firstName.trim() || !form.lastName.trim() || !form.email.trim()) {
|
|
$q.notify({ type: 'negative', message: 'Compila tutti i campi obbligatori.' });
|
|
return;
|
|
}
|
|
|
|
if (form.password.length < 8) {
|
|
$q.notify({ type: 'negative', message: 'La password deve contenere almeno 8 caratteri.' });
|
|
return;
|
|
}
|
|
|
|
if (form.password !== form.confirmPassword) {
|
|
$q.notify({ type: 'negative', message: 'Le password non coincidono.' });
|
|
return;
|
|
}
|
|
|
|
if (!form.acceptTerms) {
|
|
$q.notify({ type: 'negative', message: 'Devi accettare le condizioni.' });
|
|
return;
|
|
}
|
|
|
|
loading.value = true;
|
|
try {
|
|
const payload: UserCreateRequest = {
|
|
name: `${form.firstName.trim()} ${form.lastName.trim()}`.trim(),
|
|
email: form.email.trim(),
|
|
password: form.password,
|
|
permission: "user",
|
|
status: EnumUserStatus.UserStatusPending,
|
|
types: ['internal'],
|
|
avatar: null,
|
|
details: {
|
|
title: '',
|
|
firstName: form.firstName.trim(),
|
|
lastName: form.lastName.trim(),
|
|
address: '',
|
|
city: '',
|
|
zipCode: '',
|
|
country: '',
|
|
phone: '',
|
|
id: 0,
|
|
userId: 0,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
},
|
|
preferences: null,
|
|
};
|
|
const response = await register(payload);
|
|
if (response.error) {
|
|
throw new Error(response.error);
|
|
}
|
|
sent.value = true;
|
|
} catch (error) {
|
|
$q.notify({
|
|
type: 'negative',
|
|
message: error instanceof Error ? error.message : String(error),
|
|
});
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function focusFirstField(): Promise<void> {
|
|
await nextTick();
|
|
firstNameRef.value?.focus?.();
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.auth-page {
|
|
background: linear-gradient(180deg, #f7fafc 0%, #e9f0f7 100%);
|
|
}
|
|
|
|
.auth-shell {
|
|
max-width: 520px;
|
|
margin: 0 auto;
|
|
padding: 40px 20px;
|
|
}
|
|
|
|
.auth-shell-wide {
|
|
max-width: 760px;
|
|
}
|
|
|
|
.auth-card {
|
|
border-radius: 24px;
|
|
}
|
|
|
|
.auth-form {
|
|
display: grid;
|
|
gap: 14px;
|
|
}
|
|
|
|
.auth-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.success-state {
|
|
display: grid;
|
|
justify-items: center;
|
|
gap: 12px;
|
|
text-align: center;
|
|
padding: 12px 0;
|
|
}
|
|
|
|
.success-actions {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
</style>
|