Update prenotazione form with waiver handling improvements
Updated frontend changes documentation and prenotazione user form to improve waiver (liberatoria) handling functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,11 +7,15 @@ import { required } from '@vuelidate/validators';
|
||||
|
||||
import StrutturaService from '@/entities/struttura/struttura.service';
|
||||
import UtenteAppService from '@/entities/utente-app/utente-app.service';
|
||||
import LiberatoriaService from '@/entities/liberatoria/liberatoria.service';
|
||||
import ModelloLiberatoriaService from '@/entities/modello-liberatoria/modello-liberatoria.service';
|
||||
import { useAlertService } from '@/shared/alert/alert.service';
|
||||
import { useDateFormat } from '@/shared/composables';
|
||||
import { type IPrenotazione, Prenotazione } from '@/shared/model/prenotazione.model';
|
||||
import { type IStruttura } from '@/shared/model/struttura.model';
|
||||
import { type IUtenteApp } from '@/shared/model/utente-app.model';
|
||||
import { type ILiberatoria, Liberatoria } from '@/shared/model/liberatoria.model';
|
||||
import { type IModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
|
||||
import { StatoPrenotazione } from '@/shared/model/enumerations/stato-prenotazione.model';
|
||||
|
||||
import PrenotazioneService from './prenotazione.service';
|
||||
@@ -33,6 +37,15 @@ export default defineComponent({
|
||||
const strutturaService = inject('strutturaService', () => new StrutturaService());
|
||||
const strutturas: Ref<IStruttura[]> = ref([]);
|
||||
|
||||
const liberatoriaService = inject('liberatoriaService', () => new LiberatoriaService());
|
||||
const modelloLiberatoriaService = inject('modelloLiberatoriaService', () => new ModelloLiberatoriaService());
|
||||
|
||||
// Liberatorie state
|
||||
const modelloLiberatorias: Ref<IModelloLiberatoria[]> = ref([]);
|
||||
const userLiberatorias: Ref<ILiberatoria[]> = ref([]);
|
||||
const isLoadingLiberatorie = ref(false);
|
||||
const selectedModello: Ref<IModelloLiberatoria | null> = ref(null);
|
||||
|
||||
const isSaving = ref(false);
|
||||
const isLoading = ref(true);
|
||||
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
|
||||
@@ -55,6 +68,50 @@ export default defineComponent({
|
||||
};
|
||||
const v$ = useVuelidate(validationRules, prenotazione as any);
|
||||
|
||||
// Computed properties for liberatorie
|
||||
const liberatorieStatus = computed(() => {
|
||||
if (!prenotazione.value.struttura?.id) return [];
|
||||
|
||||
// Filter ModelloLiberatoria for selected struttura
|
||||
const strutturaModelli = modelloLiberatorias.value.filter(m => m.struttura?.id === prenotazione.value.struttura.id);
|
||||
|
||||
// Map to include acceptance status
|
||||
return strutturaModelli.map(modello => {
|
||||
const accepted = userLiberatorias.value.find(lib => lib.modelloLiberatoria?.id === modello.id);
|
||||
return {
|
||||
modello,
|
||||
liberatoria: accepted || null,
|
||||
isAccepted: !!accepted,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const allLiberatorieAccepted = computed(() => {
|
||||
const status = liberatorieStatus.value;
|
||||
return status.length === 0 || status.every(s => s.isAccepted);
|
||||
});
|
||||
|
||||
const loadLiberatorieData = async () => {
|
||||
if (!currentUser.value?.id) return;
|
||||
|
||||
try {
|
||||
isLoadingLiberatorie.value = true;
|
||||
|
||||
// Fetch all ModelloLiberatoria (filter client-side)
|
||||
const modelliRes = await modelloLiberatoriaService().retrieve();
|
||||
modelloLiberatorias.value = modelliRes.data;
|
||||
|
||||
// Fetch all Liberatoria and filter by current user
|
||||
const liberatorieRes = await liberatoriaService().retrieve();
|
||||
userLiberatorias.value = liberatorieRes.data.filter((lib: ILiberatoria) => lib.utente?.id === currentUser.value.id);
|
||||
|
||||
isLoadingLiberatorie.value = false;
|
||||
} catch (error) {
|
||||
isLoadingLiberatorie.value = false;
|
||||
alertService.showHttpError(error.response);
|
||||
}
|
||||
};
|
||||
|
||||
const initData = async () => {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
@@ -68,6 +125,9 @@ export default defineComponent({
|
||||
const res = await strutturaService().retrieve();
|
||||
strutturas.value = res.data;
|
||||
|
||||
// Load liberatorie data
|
||||
await loadLiberatorieData();
|
||||
|
||||
isLoading.value = false;
|
||||
} catch (error) {
|
||||
isLoading.value = false;
|
||||
@@ -99,6 +159,15 @@ export default defineComponent({
|
||||
currentLanguage,
|
||||
v$,
|
||||
resetForm,
|
||||
// Liberatorie additions
|
||||
liberatoriaService,
|
||||
modelloLiberatoriaService,
|
||||
modelloLiberatorias,
|
||||
userLiberatorias,
|
||||
isLoadingLiberatorie,
|
||||
selectedModello,
|
||||
liberatorieStatus,
|
||||
allLiberatorieAccepted,
|
||||
...useDateFormat({ entityRef: prenotazione }),
|
||||
t$,
|
||||
};
|
||||
@@ -113,6 +182,13 @@ export default defineComponent({
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if all required liberatorie are accepted
|
||||
if (!this.allLiberatorieAccepted) {
|
||||
this.isSaving = false;
|
||||
this.alertService.showError(this.t$('smartbookingApp.prenotazione.userForm.liberatorieRequired').toString());
|
||||
return;
|
||||
}
|
||||
|
||||
this.prenotazioneService()
|
||||
.create(this.prenotazione)
|
||||
.then(param => {
|
||||
@@ -125,5 +201,45 @@ export default defineComponent({
|
||||
this.alertService.showHttpError(error.response);
|
||||
});
|
||||
},
|
||||
|
||||
showLiberatoriaModal(modello: IModelloLiberatoria): void {
|
||||
this.selectedModello = modello;
|
||||
(<any>this.$refs.liberatoriaModal).show();
|
||||
},
|
||||
|
||||
closeLiberatoriaModal(): void {
|
||||
this.selectedModello = null;
|
||||
(<any>this.$refs.liberatoriaModal).hide();
|
||||
},
|
||||
|
||||
async acceptLiberatoria(): Promise<void> {
|
||||
if (!this.selectedModello || !this.currentUser) return;
|
||||
|
||||
try {
|
||||
this.isSaving = true;
|
||||
|
||||
// Create new Liberatoria
|
||||
const newLiberatoria = new Liberatoria();
|
||||
newLiberatoria.accettata = new Date();
|
||||
newLiberatoria.utente = this.currentUser;
|
||||
newLiberatoria.modelloLiberatoria = this.selectedModello;
|
||||
|
||||
const result = await this.liberatoriaService().create(newLiberatoria);
|
||||
|
||||
// Add to local state
|
||||
this.userLiberatorias.push(result);
|
||||
|
||||
// Close modal
|
||||
this.closeLiberatoriaModal();
|
||||
|
||||
// Show success message
|
||||
this.alertService.showSuccess(this.t$('smartbookingApp.liberatoria.created', { param: result.id }).toString());
|
||||
|
||||
this.isSaving = false;
|
||||
} catch (error) {
|
||||
this.isSaving = false;
|
||||
this.alertService.showHttpError(error.response);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -220,13 +220,65 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Liberatorie Section -->
|
||||
<div class="card mb-4" v-if="prenotazione.struttura">
|
||||
<div class="card-header">
|
||||
<h4>{{ t$('smartbookingApp.prenotazione.userForm.liberatorie') }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div v-if="isLoadingLiberatorie" class="text-center">
|
||||
<div class="spinner-border spinner-border-sm" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="liberatorieStatus.length === 0" class="alert alert-info">
|
||||
{{ t$('smartbookingApp.prenotazione.userForm.noLiberatorieRequired') }}
|
||||
</div>
|
||||
|
||||
<div v-else class="list-group">
|
||||
<div
|
||||
v-for="item in liberatorieStatus"
|
||||
:key="item.modello.id"
|
||||
class="list-group-item d-flex justify-content-between align-items-center"
|
||||
>
|
||||
<div>
|
||||
<span v-if="item.isAccepted" class="badge bg-success me-2">
|
||||
<font-awesome-icon icon="check"></font-awesome-icon>
|
||||
</span>
|
||||
<span v-else class="badge bg-warning me-2">
|
||||
<font-awesome-icon icon="exclamation-triangle"></font-awesome-icon>
|
||||
</span>
|
||||
|
||||
<span v-if="item.isAccepted">
|
||||
{{ item.modello.nome }}
|
||||
</span>
|
||||
<a v-else href="javascript:void(0)" @click="showLiberatoriaModal(item.modello)">
|
||||
{{ item.modello.nome }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span v-if="item.isAccepted" class="text-muted small">
|
||||
{{ t$('smartbookingApp.liberatoria.accettata') }}:
|
||||
{{ new Date(item.liberatoria.accettata).toLocaleDateString('it-IT') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!allLiberatorieAccepted" class="alert alert-warning mt-3 mb-0">
|
||||
<font-awesome-icon icon="exclamation-triangle"></font-awesome-icon>
|
||||
{{ t$('smartbookingApp.prenotazione.userForm.liberatorieWarning') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary" @click="resetForm()" :disabled="isSaving">
|
||||
<font-awesome-icon icon="undo"></font-awesome-icon>
|
||||
<span>{{ t$('smartbookingApp.prenotazione.userForm.reset') }}</span>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="v$.$invalid || isSaving">
|
||||
<button type="submit" class="btn btn-primary" :disabled="v$.$invalid || isSaving || !allLiberatorieAccepted">
|
||||
<font-awesome-icon icon="save"></font-awesome-icon>
|
||||
<span>{{ t$('smartbookingApp.prenotazione.userForm.submit') }}</span>
|
||||
</button>
|
||||
@@ -234,5 +286,54 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Liberatoria Acceptance Modal -->
|
||||
<b-modal ref="liberatoriaModal" size="lg" @hidden="closeLiberatoriaModal">
|
||||
<template #title>
|
||||
<h4>{{ selectedModello?.nome }}</h4>
|
||||
</template>
|
||||
|
||||
<div v-if="selectedModello">
|
||||
<!-- Modello Text -->
|
||||
<div v-if="selectedModello.testo" class="mb-3">
|
||||
<h5>{{ t$('smartbookingApp.modelloLiberatoria.testo') }}</h5>
|
||||
<div class="border p-3 bg-light" style="white-space: pre-wrap">
|
||||
{{ selectedModello.testo }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modello Document -->
|
||||
<div v-if="selectedModello.documento" class="mb-3">
|
||||
<h5>{{ t$('smartbookingApp.modelloLiberatoria.documento') }}</h5>
|
||||
<a
|
||||
:href="'data:' + selectedModello.documentoContentType + ';base64,' + selectedModello.documento"
|
||||
:download="selectedModello.nome + '.pdf'"
|
||||
class="btn btn-sm btn-outline-primary"
|
||||
>
|
||||
<font-awesome-icon icon="download"></font-awesome-icon>
|
||||
{{ t$('entity.action.download') }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Acceptance Statement -->
|
||||
<div class="alert alert-info mt-4">
|
||||
<strong>{{ t$('smartbookingApp.prenotazione.userForm.acceptanceStatement') }}</strong>
|
||||
<p class="mb-0 mt-2">
|
||||
Il sottoscritto <strong>{{ currentUser?.nome }} {{ currentUser?.cognome }}</strong>
|
||||
presa visione della documentazione proposta accetta le condizioni ivi indicate.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<button type="button" class="btn btn-secondary" @click="closeLiberatoriaModal" :disabled="isSaving">
|
||||
{{ t$('entity.action.cancel') }}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" @click="acceptLiberatoria" :disabled="isSaving">
|
||||
<font-awesome-icon icon="check"></font-awesome-icon>
|
||||
{{ t$('smartbookingApp.prenotazione.userForm.accept') }}
|
||||
</button>
|
||||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
<script lang="ts" src="./prenotazione-form-user.component.ts"></script>
|
||||
|
||||
@@ -37,7 +37,13 @@
|
||||
"societa": "società/associazione",
|
||||
"companyData": "Dati della società/associazione",
|
||||
"reset": "Annulla",
|
||||
"submit": "Invia richiesta"
|
||||
"submit": "Invia richiesta",
|
||||
"liberatorie": "Liberatorie",
|
||||
"noLiberatorieRequired": "Nessuna liberatoria richiesta per questa struttura",
|
||||
"liberatorieWarning": "È necessario accettare tutte le liberatorie richieste prima di inviare la prenotazione",
|
||||
"liberatorieRequired": "Devi accettare tutte le liberatorie richieste",
|
||||
"acceptanceStatement": "Dichiarazione di accettazione",
|
||||
"accept": "Accetta"
|
||||
},
|
||||
"StatoPrenotazione": {
|
||||
"RICHIESTA": ""
|
||||
|
||||
Reference in New Issue
Block a user