refactor: improve auth login and register pages with UX improvements
- Add guest middleware to login page - Integrate auth handles for handleLoginSuccess on verifyOtp and passwordLogin - Add password visibility toggle to register and login password inputs - Calculate and validate Italian Fiscal Code structure against name/surname input on register - Align form-group structure within row cols for Bootstrap Italia layout compliance
This commit is contained in:
+79
-21
@@ -1,6 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'guest'
|
||||
})
|
||||
|
||||
useHead({ title: 'Registrazione - Visione' })
|
||||
|
||||
const { register } = useAuth()
|
||||
@@ -9,8 +13,8 @@ const router = useRouter()
|
||||
const isLoading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const successMessage = ref(false)
|
||||
const showPassword = ref(false)
|
||||
|
||||
// Form State mappato sull'API RegisterCitizenRequest
|
||||
const form = ref({
|
||||
first_name: '',
|
||||
last_name: '',
|
||||
@@ -21,12 +25,38 @@ const form = ref({
|
||||
privacy: false
|
||||
})
|
||||
|
||||
const computeSurnameCode = (surname = '') => {
|
||||
const s = surname.toUpperCase().replace(/[^A-Z]/g, '')
|
||||
const consonants = s.replace(/[AEIOU]/g, '')
|
||||
const vowels = s.replace(/[^AEIOU]/g, '')
|
||||
return (consonants + vowels + 'XXX').slice(0, 3)
|
||||
}
|
||||
|
||||
const computeNameCode = (name = '') => {
|
||||
const s = name.toUpperCase().replace(/[^A-Z]/g, '')
|
||||
const consonants = s.replace(/[AEIOU]/g, '')
|
||||
const vowels = s.replace(/[^AEIOU]/g, '')
|
||||
if (consonants.length >= 4) {
|
||||
return consonants.charAt(0) + consonants.charAt(2) + consonants.charAt(3)
|
||||
}
|
||||
return (consonants + vowels + 'XXX').slice(0, 3)
|
||||
}
|
||||
|
||||
const handleRegister = async () => {
|
||||
if (!form.value.privacy) {
|
||||
errorMessage.value = "È necessario accettare l'informativa sulla privacy."
|
||||
return
|
||||
}
|
||||
|
||||
const expected = computeSurnameCode(form.value.last_name) + computeNameCode(form.value.first_name)
|
||||
if (form.value.fiscal_code.trim().length >= 6) {
|
||||
const provided = form.value.fiscal_code.trim().toUpperCase().slice(0, 6)
|
||||
if (provided !== expected) {
|
||||
errorMessage.value = `Il Codice Fiscale non sembra corrispondere a nome/cognome. Atteso: ${expected}`
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
errorMessage.value = ''
|
||||
|
||||
@@ -41,7 +71,6 @@ const handleRegister = async () => {
|
||||
})
|
||||
|
||||
successMessage.value = true
|
||||
// Ritarda il redirect per far leggere il messaggio
|
||||
setTimeout(() => {
|
||||
router.push('/auth/login')
|
||||
}, 3000)
|
||||
@@ -55,7 +84,7 @@ const handleRegister = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex align-items-center min-vh-100 bg-light py-5">
|
||||
<div class="d-flex align-items-center bg-light py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-lg-8">
|
||||
@@ -70,7 +99,6 @@ const handleRegister = async () => {
|
||||
<div class="card-body p-4 p-md-5">
|
||||
|
||||
<div v-if="successMessage" class="alert alert-success" role="alert">
|
||||
<BIIcon name="it-check-circle" size="sm" class="me-2" />
|
||||
Registrazione completata con successo! Reindirizzamento al login...
|
||||
</div>
|
||||
|
||||
@@ -81,14 +109,20 @@ const handleRegister = async () => {
|
||||
<form v-if="!successMessage" @submit.prevent="handleRegister">
|
||||
|
||||
<h2 class="h5 text-primary font-weight-bold mb-4 border-bottom pb-2">Dati Anagrafici</h2>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 form-group mb-4">
|
||||
<input type="text" class="form-control" id="nome" v-model="form.first_name" required>
|
||||
<label for="nome" :class="{ 'active': form.first_name.length > 0 }">Nome</label>
|
||||
|
||||
<!-- FIX LAYOUT: form-group separato da col -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12 col-md-6 mb-4 mb-md-0">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="nome" v-model="form.first_name" required>
|
||||
<label for="nome" :class="{ 'active': form.first_name.length > 0 }">Nome</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 form-group mb-4">
|
||||
<input type="text" class="form-control" id="cognome" v-model="form.last_name" required>
|
||||
<label for="cognome" :class="{ 'active': form.last_name.length > 0 }">Cognome</label>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="cognome" v-model="form.last_name" required>
|
||||
<label for="cognome" :class="{ 'active': form.last_name.length > 0 }">Cognome</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -99,20 +133,37 @@ const handleRegister = async () => {
|
||||
</div>
|
||||
|
||||
<h2 class="h5 text-primary font-weight-bold mt-5 mb-4 border-bottom pb-2">Credenziali e Contatti</h2>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 form-group mb-4">
|
||||
<input type="email" class="form-control" id="regEmail" v-model="form.email" required>
|
||||
<label for="regEmail" :class="{ 'active': form.email.length > 0 }">Indirizzo Email</label>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-12 col-md-6 mb-4 mb-md-0">
|
||||
<div class="form-group">
|
||||
<input type="email" class="form-control" id="regEmail" v-model="form.email" required>
|
||||
<label for="regEmail" :class="{ 'active': form.email.length > 0 }">Indirizzo Email</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6 form-group mb-4">
|
||||
<input type="password" class="form-control" id="regPwd" v-model="form.password" required minlength="10">
|
||||
<label for="regPwd" :class="{ 'active': form.password.length > 0 }">Password (min. 10 crt)</label>
|
||||
<div class="col-12 col-md-6">
|
||||
<!-- INPUT PASSWORD FIXATO -->
|
||||
<div class="form-group position-relative">
|
||||
<input :type="showPassword ? 'text' : 'password'" class="form-control pe-5" id="regPwd" v-model="form.password" required minlength="10">
|
||||
<label for="regPwd" :class="{ 'active': form.password.length > 0 }">Password (min. 10 crt)</label>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn bg-transparent border-0 shadow-none position-absolute p-2"
|
||||
style="right: 0; top: 2px; z-index: 10;"
|
||||
@click="showPassword = !showPassword"
|
||||
:aria-pressed="showPassword"
|
||||
aria-label="Mostra/Nascondi password"
|
||||
>
|
||||
<BIIcon :name="showPassword ? 'it-password-visible' : 'it-password-invisible'" color="primary" size="sm" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mb-5">
|
||||
<input type="tel" class="form-control" id="phone" v-model="form.phone">
|
||||
<label for="phone" :class="{ 'active': form.phone.length > 0 }">Numero di telefono (Opzionale)</label>
|
||||
<label for="phone" :class="{ 'active': form.phone?.length > 0 }">Numero di telefono (Opzionale)</label>
|
||||
<small class="form-text text-muted">Faciliterà il contatto da parte degli operatori comunali in caso di intervento.</small>
|
||||
</div>
|
||||
|
||||
@@ -120,7 +171,7 @@ const handleRegister = async () => {
|
||||
<div class="form-check mb-4">
|
||||
<input class="form-check-input" type="checkbox" id="privacyCheck" v-model="form.privacy" required>
|
||||
<label class="form-check-label small" for="privacyCheck">
|
||||
Dichiaro di aver letto l'<NuxtLink to="/privacy" target="_blank">Informativa sulla Privacy</NuxtLink> e accetto il trattamento dei dati personali ai fini dell'erogazione del servizio.
|
||||
Dichiaro di aver letto l'<NuxtLink to="/privacy" target="_blank">Informativa sulla Privacy</NuxtLink> e accetto il trattamento dei dati personali.
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -141,4 +192,11 @@ const handleRegister = async () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Previene che il testo finisca sotto l'icona */
|
||||
.pe-5 {
|
||||
padding-right: 3rem !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user