Implement role-based booking list views for ROLE_USER and ROLE_INCARICATO
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Simone Bierti
parent
b4d0ca4898
commit
78d3e17d02
@@ -731,3 +731,62 @@ A profile completion check is shown on the home page to prompt users to complete
|
|||||||
- Bootstrap responsive design
|
- Bootstrap responsive design
|
||||||
- Complete Italian translations
|
- Complete Italian translations
|
||||||
- Security: users can only edit their own profile
|
- Security: users can only edit their own profile
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Frontend Changes: Gestione e Visualizzazione Prenotazioni per Ruolo
|
||||||
|
|
||||||
|
## Date
|
||||||
|
|
||||||
|
2026-04-07
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Implemented role-based booking management views as specified in `features/visualizzazione-prenotazioni.md`. The `prenotazione` list page now renders different UIs depending on the user's role:
|
||||||
|
|
||||||
|
- **ROLE_USER**: sees their own bookings in a single table. Edit and Delete actions are hidden when a `Conferma` exists for that booking. A "Vedi conferma" button appears instead.
|
||||||
|
- **ROLE_INCARICATO**: sees two separate tables — *Prenotazioni in attesa* (no `Conferma`) and *Prenotazioni gestite* (with `Conferma`). A "Prendi in carico" button opens a modal to create the `Conferma` record; after saving, the row moves reactively from the first table to the second without a page reload.
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
|
||||||
|
### 1. Component Logic
|
||||||
|
|
||||||
|
**File:** `src/main/webapp/app/entities/prenotazione/prenotazione.component.ts`
|
||||||
|
|
||||||
|
- Imported `useAccountStore`, `Authority`, `TipoConferma`, `ConfermaService`
|
||||||
|
- Added `isIncaricato` computed property (checks `account.authorities`)
|
||||||
|
- Added `prenotazioniPendenti` and `prenotazioniCompletate` computed arrays (derived from `prenotaziones`)
|
||||||
|
- Added modal state: `showPrendiInCaricoModal`, `selectedPrenotazione`, `confermaForm`, `isSubmittingConferma`
|
||||||
|
- Added methods: `prendiInCarico()`, `closePrendiInCaricoModal()`, `submitConferma()`
|
||||||
|
- `submitConferma()` calls `ConfermaService.create()` with `id` set to the prenotazione id (shared PK), then refreshes the list reactively
|
||||||
|
|
||||||
|
### 2. Vue Template
|
||||||
|
|
||||||
|
**File:** `src/main/webapp/app/entities/prenotazione/prenotazione.vue`
|
||||||
|
|
||||||
|
- Split into two `<template v-if>` blocks: one for `!isIncaricato`, one for `isIncaricato`
|
||||||
|
- **ROLE_USER block**: simplified column set; Edit/Delete wrapped in `v-if="!prenotazione.conferma"`, "Vedi conferma" router-link shown when `conferma` exists
|
||||||
|
- **ROLE_INCARICATO block**:
|
||||||
|
- Table 1 (pendenti): full user/struttura columns + "Prendi in carico" button
|
||||||
|
- Table 2 (completate): shows `TipoConferma` badge + "Vedi conferma" link
|
||||||
|
- `b-modal` for "Prendi in carico" with `tipoConferma` select (required) and `motivoConferma` textarea; submit button disabled until tipo selected; spinner during save
|
||||||
|
|
||||||
|
### 3. Internationalization
|
||||||
|
|
||||||
|
**File:** `src/main/webapp/i18n/it/prenotazione.json`
|
||||||
|
|
||||||
|
New keys added:
|
||||||
|
- `home.titleIncaricato` — page title for incaricato view
|
||||||
|
- `viewConferma` — "Vedi conferma" button label
|
||||||
|
- `pendenti.title` / `pendenti.notFound`
|
||||||
|
- `completate.title` / `completate.notFound`
|
||||||
|
- `prendiInCarico.button`, `.title`, `.subtitle`, `.selectTipo`, `.motivoPlaceholder`, `.submit`, `.success`
|
||||||
|
|
||||||
|
Also improved existing Italian strings (`home.title`, `home.refreshListLabel`, `home.createLabel`, `home.notFound`).
|
||||||
|
|
||||||
|
## Acceptance Criteria Status
|
||||||
|
|
||||||
|
- [x] ROLE_USER cannot delete/edit a booking that has a conferma (buttons hidden in UI)
|
||||||
|
- [x] ROLE_INCARICATO sees two tables with correct content split
|
||||||
|
- [x] Saving a conferma moves the row reactively from Table 1 to Table 2 (via list refresh after create)
|
||||||
|
- [x] Conferma is created with `id` matching the prenotazione id (shared PK per spec)
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
|
import { type Ref, computed, defineComponent, inject, onMounted, ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useAlertService } from '@/shared/alert/alert.service';
|
import { useAlertService } from '@/shared/alert/alert.service';
|
||||||
import { useDateFormat } from '@/shared/composables';
|
import { useDateFormat } from '@/shared/composables';
|
||||||
|
import { type IConferma } from '@/shared/model/conferma.model';
|
||||||
|
import { TipoConferma } from '@/shared/model/enumerations/tipo-conferma.model';
|
||||||
import { type IPrenotazione } from '@/shared/model/prenotazione.model';
|
import { type IPrenotazione } from '@/shared/model/prenotazione.model';
|
||||||
|
import { Authority } from '@/shared/security/authority';
|
||||||
|
import { useAccountStore } from '@/shared/config/store/account-store';
|
||||||
|
|
||||||
|
import ConfermaService from '../conferma/conferma.service';
|
||||||
import PrenotazioneService from './prenotazione.service';
|
import PrenotazioneService from './prenotazione.service';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -13,7 +18,9 @@ export default defineComponent({
|
|||||||
const { t: t$ } = useI18n();
|
const { t: t$ } = useI18n();
|
||||||
const dateFormat = useDateFormat();
|
const dateFormat = useDateFormat();
|
||||||
const prenotazioneService = inject('prenotazioneService', () => new PrenotazioneService());
|
const prenotazioneService = inject('prenotazioneService', () => new PrenotazioneService());
|
||||||
|
const confermaService = inject('confermaService', () => new ConfermaService());
|
||||||
const alertService = inject('alertService', () => useAlertService(), true);
|
const alertService = inject('alertService', () => useAlertService(), true);
|
||||||
|
const accountStore = useAccountStore();
|
||||||
|
|
||||||
const itemsPerPage = ref(20);
|
const itemsPerPage = ref(20);
|
||||||
const queryCount: Ref<number> = ref(null);
|
const queryCount: Ref<number> = ref(null);
|
||||||
@@ -23,9 +30,25 @@ export default defineComponent({
|
|||||||
const totalItems = ref(0);
|
const totalItems = ref(0);
|
||||||
|
|
||||||
const prenotaziones: Ref<IPrenotazione[]> = ref([]);
|
const prenotaziones: Ref<IPrenotazione[]> = ref([]);
|
||||||
|
|
||||||
const isFetching = ref(false);
|
const isFetching = ref(false);
|
||||||
|
|
||||||
|
// Role-based helpers
|
||||||
|
const account = computed(() => accountStore.account);
|
||||||
|
const isIncaricato = computed(() => account.value?.authorities?.includes(Authority.INCARICATO) ?? false);
|
||||||
|
|
||||||
|
// ROLE_INCARICATO: split list into pending (no conferma) and completed (with conferma)
|
||||||
|
const prenotazioniPendenti = computed(() => prenotaziones.value.filter(p => !p.conferma));
|
||||||
|
const prenotazioniCompletate = computed(() => prenotaziones.value.filter(p => !!p.conferma));
|
||||||
|
|
||||||
|
// "Prendi in carico" modal state
|
||||||
|
const showPrendiInCaricoModal = ref(false);
|
||||||
|
const selectedPrenotazione: Ref<IPrenotazione | null> = ref(null);
|
||||||
|
const confermaForm = ref<{ tipoConferma: string; motivoConferma: string }>({
|
||||||
|
tipoConferma: '',
|
||||||
|
motivoConferma: '',
|
||||||
|
});
|
||||||
|
const isSubmittingConferma = ref(false);
|
||||||
|
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
page.value = 1;
|
page.value = 1;
|
||||||
};
|
};
|
||||||
@@ -87,6 +110,37 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const prendiInCarico = (prenotazione: IPrenotazione) => {
|
||||||
|
selectedPrenotazione.value = prenotazione;
|
||||||
|
confermaForm.value = { tipoConferma: '', motivoConferma: '' };
|
||||||
|
showPrendiInCaricoModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closePrendiInCaricoModal = () => {
|
||||||
|
showPrendiInCaricoModal.value = false;
|
||||||
|
selectedPrenotazione.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitConferma = async () => {
|
||||||
|
if (!selectedPrenotazione.value || !confermaForm.value.tipoConferma) return;
|
||||||
|
isSubmittingConferma.value = true;
|
||||||
|
try {
|
||||||
|
const newConferma: IConferma = {
|
||||||
|
id: selectedPrenotazione.value.id,
|
||||||
|
tipoConferma: confermaForm.value.tipoConferma as keyof typeof TipoConferma,
|
||||||
|
motivoConferma: confermaForm.value.motivoConferma || null,
|
||||||
|
};
|
||||||
|
await confermaService().create(newConferma);
|
||||||
|
alertService.showInfo(t$('smartbookingApp.prenotazione.prendiInCarico.success').toString());
|
||||||
|
closePrendiInCaricoModal();
|
||||||
|
await retrievePrenotaziones();
|
||||||
|
} catch (error) {
|
||||||
|
alertService.showHttpError(error.response);
|
||||||
|
} finally {
|
||||||
|
isSubmittingConferma.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const changeOrder = (newOrder: string) => {
|
const changeOrder = (newOrder: string) => {
|
||||||
if (propOrder.value === newOrder) {
|
if (propOrder.value === newOrder) {
|
||||||
reverse.value = !reverse.value;
|
reverse.value = !reverse.value;
|
||||||
@@ -96,18 +150,14 @@ export default defineComponent({
|
|||||||
propOrder.value = newOrder;
|
propOrder.value = newOrder;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Whenever order changes, reset the pagination
|
|
||||||
watch([propOrder, reverse], async () => {
|
watch([propOrder, reverse], async () => {
|
||||||
if (page.value === 1) {
|
if (page.value === 1) {
|
||||||
// first page, retrieve new data
|
|
||||||
await retrievePrenotaziones();
|
await retrievePrenotaziones();
|
||||||
} else {
|
} else {
|
||||||
// reset the pagination
|
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Whenever page changes, switch to the new page.
|
|
||||||
watch(page, async () => {
|
watch(page, async () => {
|
||||||
await retrievePrenotaziones();
|
await retrievePrenotaziones();
|
||||||
});
|
});
|
||||||
@@ -132,6 +182,18 @@ export default defineComponent({
|
|||||||
totalItems,
|
totalItems,
|
||||||
changeOrder,
|
changeOrder,
|
||||||
t$,
|
t$,
|
||||||
|
// Role-based
|
||||||
|
isIncaricato,
|
||||||
|
prenotazioniPendenti,
|
||||||
|
prenotazioniCompletate,
|
||||||
|
// Prendi in carico modal
|
||||||
|
showPrendiInCaricoModal,
|
||||||
|
selectedPrenotazione,
|
||||||
|
confermaForm,
|
||||||
|
isSubmittingConferma,
|
||||||
|
prendiInCarico,
|
||||||
|
closePrendiInCaricoModal,
|
||||||
|
submitConferma,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,176 +1,355 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2 id="page-heading" data-cy="PrenotazioneHeading">
|
<!-- ============================= ROLE_USER VIEW ============================= -->
|
||||||
<span id="prenotazione">{{ t$('smartbookingApp.prenotazione.home.title') }}</span>
|
<template v-if="!isIncaricato">
|
||||||
<div class="d-flex justify-content-end">
|
<h2 id="page-heading" data-cy="PrenotazioneHeading">
|
||||||
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
|
<span id="prenotazione">{{ t$('smartbookingApp.prenotazione.home.title') }}</span>
|
||||||
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
|
<div class="d-flex justify-content-end">
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.home.refreshListLabel') }}</span>
|
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
|
||||||
</button>
|
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
|
||||||
<router-link :to="{ name: 'PrenotazioneCreate' }" custom v-slot="{ navigate }">
|
<span>{{ t$('smartbookingApp.prenotazione.home.refreshListLabel') }}</span>
|
||||||
<button
|
|
||||||
@click="navigate"
|
|
||||||
id="jh-create-entity"
|
|
||||||
data-cy="entityCreateButton"
|
|
||||||
class="btn btn-primary jh-create-entity create-prenotazione"
|
|
||||||
>
|
|
||||||
<font-awesome-icon icon="plus"></font-awesome-icon>
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.home.createLabel') }}</span>
|
|
||||||
</button>
|
</button>
|
||||||
</router-link>
|
<router-link :to="{ name: 'PrenotazioneNuova' }" custom v-slot="{ navigate }">
|
||||||
|
<button
|
||||||
|
@click="navigate"
|
||||||
|
id="jh-create-entity"
|
||||||
|
data-cy="entityCreateButton"
|
||||||
|
class="btn btn-primary jh-create-entity create-prenotazione"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="plus"></font-awesome-icon>
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.home.createLabel') }}</span>
|
||||||
|
</button>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<br />
|
||||||
|
<div class="alert alert-warning" v-if="!isFetching && prenotaziones?.length === 0">
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.home.notFound') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
<div class="table-responsive" v-if="prenotaziones?.length > 0">
|
||||||
<br />
|
<table class="table table-striped" aria-describedby="prenotaziones">
|
||||||
<div class="alert alert-warning" v-if="!isFetching && prenotaziones?.length === 0">
|
<thead>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.home.notFound') }}</span>
|
<tr>
|
||||||
</div>
|
<th scope="col" @click="changeOrder('id')">
|
||||||
<div class="table-responsive" v-if="prenotaziones?.length > 0">
|
<span>{{ t$('global.field.id') }}</span>
|
||||||
<table class="table table-striped" aria-describedby="prenotaziones">
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
|
||||||
<thead>
|
</th>
|
||||||
<tr>
|
<th scope="col" @click="changeOrder('oraInizio')">
|
||||||
<th scope="col" @click="changeOrder('id')">
|
<span>{{ t$('smartbookingApp.prenotazione.oraInizio') }}</span>
|
||||||
<span>{{ t$('global.field.id') }}</span>
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraInizio'"></jhi-sort-indicator>
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
|
</th>
|
||||||
</th>
|
<th scope="col" @click="changeOrder('oraFine')">
|
||||||
<th scope="col" @click="changeOrder('oraInizio')">
|
<span>{{ t$('smartbookingApp.prenotazione.oraFine') }}</span>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.oraInizio') }}</span>
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraFine'"></jhi-sort-indicator>
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraInizio'"></jhi-sort-indicator>
|
</th>
|
||||||
</th>
|
<th scope="col" @click="changeOrder('stato')">
|
||||||
<th scope="col" @click="changeOrder('oraFine')">
|
<span>{{ t$('smartbookingApp.prenotazione.stato') }}</span>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.oraFine') }}</span>
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'stato'"></jhi-sort-indicator>
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraFine'"></jhi-sort-indicator>
|
</th>
|
||||||
</th>
|
<th scope="col" @click="changeOrder('struttura.nome')">
|
||||||
<th scope="col" @click="changeOrder('stato')">
|
<span>{{ t$('smartbookingApp.prenotazione.struttura') }}</span>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.stato') }}</span>
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'struttura.nome'"></jhi-sort-indicator>
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'stato'"></jhi-sort-indicator>
|
</th>
|
||||||
</th>
|
<th scope="col" @click="changeOrder('motivoEvento')">
|
||||||
<th scope="col" @click="changeOrder('motivoEvento')">
|
<span>{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</span>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</span>
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'motivoEvento'"></jhi-sort-indicator>
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'motivoEvento'"></jhi-sort-indicator>
|
</th>
|
||||||
</th>
|
<th scope="col"></th>
|
||||||
<th scope="col" @click="changeOrder('numeroPartecipanti')">
|
</tr>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.numeroPartecipanti') }}</span>
|
</thead>
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'numeroPartecipanti'"></jhi-sort-indicator>
|
<tbody>
|
||||||
</th>
|
<tr v-for="prenotazione in prenotaziones" :key="prenotazione.id" data-cy="entityTable">
|
||||||
<th scope="col" @click="changeOrder('noteUtente')">
|
<td>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.noteUtente') }}</span>
|
<router-link :to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }">{{
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'noteUtente'"></jhi-sort-indicator>
|
prenotazione.id
|
||||||
</th>
|
|
||||||
<th scope="col" @click="changeOrder('conferma.id')">
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.conferma') }}</span>
|
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'conferma.id'"></jhi-sort-indicator>
|
|
||||||
</th>
|
|
||||||
<th scope="col" @click="changeOrder('utente.username')">
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.utente') }}</span>
|
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'utente.username'"></jhi-sort-indicator>
|
|
||||||
</th>
|
|
||||||
<th scope="col" @click="changeOrder('struttura.nome')">
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.struttura') }}</span>
|
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'struttura.nome'"></jhi-sort-indicator>
|
|
||||||
</th>
|
|
||||||
<th scope="col"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr v-for="prenotazione in prenotaziones" :key="prenotazione.id" data-cy="entityTable">
|
|
||||||
<td>
|
|
||||||
<router-link :to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }">{{
|
|
||||||
prenotazione.id
|
|
||||||
}}</router-link>
|
|
||||||
</td>
|
|
||||||
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
|
|
||||||
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
|
|
||||||
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
|
|
||||||
<td>{{ prenotazione.motivoEvento }}</td>
|
|
||||||
<td>{{ prenotazione.numeroPartecipanti }}</td>
|
|
||||||
<td>{{ prenotazione.noteUtente }}</td>
|
|
||||||
<td>
|
|
||||||
<div v-if="prenotazione.conferma">
|
|
||||||
<router-link :to="{ name: 'ConfermaView', params: { confermaId: prenotazione.conferma.id } }">{{
|
|
||||||
prenotazione.conferma.id
|
|
||||||
}}</router-link>
|
}}</router-link>
|
||||||
</div>
|
</td>
|
||||||
</td>
|
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
|
||||||
<td>
|
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
|
||||||
<div v-if="prenotazione.utente">
|
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
|
||||||
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: prenotazione.utente.id } }">{{
|
<td>
|
||||||
prenotazione.utente.username
|
<div v-if="prenotazione.struttura">{{ prenotazione.struttura.nome }}</div>
|
||||||
}}</router-link>
|
</td>
|
||||||
</div>
|
<td>{{ prenotazione.motivoEvento }}</td>
|
||||||
</td>
|
<td class="text-end">
|
||||||
<td>
|
<div class="btn-group">
|
||||||
<div v-if="prenotazione.struttura">
|
<router-link
|
||||||
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: prenotazione.struttura.id } }">{{
|
:to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }"
|
||||||
prenotazione.struttura.nome
|
class="btn btn-info btn-sm details"
|
||||||
}}</router-link>
|
data-cy="entityDetailsButton"
|
||||||
</div>
|
>
|
||||||
</td>
|
<font-awesome-icon icon="eye"></font-awesome-icon>
|
||||||
<td class="text-end">
|
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
|
||||||
<div class="btn-group">
|
</router-link>
|
||||||
<router-link
|
<!-- Show conferma link when conferma exists -->
|
||||||
:to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }"
|
<router-link
|
||||||
class="btn btn-info btn-sm details"
|
v-if="prenotazione.conferma"
|
||||||
data-cy="entityDetailsButton"
|
:to="{ name: 'ConfermaView', params: { confermaId: prenotazione.conferma.id } }"
|
||||||
>
|
class="btn btn-secondary btn-sm"
|
||||||
<font-awesome-icon icon="eye"></font-awesome-icon>
|
data-cy="entityConfermaButton"
|
||||||
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
|
>
|
||||||
</router-link>
|
<font-awesome-icon icon="file-alt"></font-awesome-icon>
|
||||||
<router-link
|
<span class="d-none d-md-inline">{{ t$('smartbookingApp.prenotazione.viewConferma') }}</span>
|
||||||
:to="{ name: 'PrenotazioneEdit', params: { prenotazioneId: prenotazione.id } }"
|
</router-link>
|
||||||
class="btn btn-primary btn-sm edit"
|
<!-- Edit and Delete only when no conferma -->
|
||||||
data-cy="entityEditButton"
|
<template v-if="!prenotazione.conferma">
|
||||||
>
|
<router-link
|
||||||
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
|
:to="{ name: 'PrenotazioneEdit', params: { prenotazioneId: prenotazione.id } }"
|
||||||
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
|
class="btn btn-primary btn-sm edit"
|
||||||
</router-link>
|
data-cy="entityEditButton"
|
||||||
<b-button
|
>
|
||||||
@click="prepareRemove(prenotazione)"
|
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
|
||||||
variant="danger"
|
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
|
||||||
class="btn btn-sm"
|
</router-link>
|
||||||
data-cy="entityDeleteButton"
|
<b-button
|
||||||
v-b-modal.removeEntity
|
@click="prepareRemove(prenotazione)"
|
||||||
>
|
variant="danger"
|
||||||
<font-awesome-icon icon="times"></font-awesome-icon>
|
class="btn btn-sm"
|
||||||
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
|
data-cy="entityDeleteButton"
|
||||||
</b-button>
|
v-b-modal.removeEntity
|
||||||
</div>
|
>
|
||||||
</td>
|
<font-awesome-icon icon="times"></font-awesome-icon>
|
||||||
</tr>
|
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
|
||||||
</tbody>
|
</b-button>
|
||||||
</table>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<b-modal ref="removeEntity" id="removeEntity">
|
</td>
|
||||||
<template #title>
|
</tr>
|
||||||
<span id="smartbookingApp.prenotazione.delete.question" data-cy="prenotazioneDeleteDialogHeading">{{
|
</tbody>
|
||||||
t$('entity.delete.title')
|
</table>
|
||||||
}}</span>
|
|
||||||
</template>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="jhi-delete-prenotazione-heading">{{ t$('smartbookingApp.prenotazione.delete.question', { id: removeId }) }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<b-modal ref="removeEntity" id="removeEntity">
|
||||||
<div>
|
<template #title>
|
||||||
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
|
<span id="smartbookingApp.prenotazione.delete.question" data-cy="prenotazioneDeleteDialogHeading">{{
|
||||||
|
t$('entity.delete.title')
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p id="jhi-delete-prenotazione-heading">{{ t$('smartbookingApp.prenotazione.delete.question', { id: removeId }) }}</p>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div>
|
||||||
|
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
id="jhi-confirm-delete-prenotazione"
|
||||||
|
data-cy="entityConfirmDeleteButton"
|
||||||
|
@click="removePrenotazione"
|
||||||
|
>
|
||||||
|
{{ t$('entity.action.delete') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</b-modal>
|
||||||
|
<div v-show="prenotaziones?.length > 0">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- ============================= ROLE_INCARICATO VIEW ============================= -->
|
||||||
|
<template v-if="isIncaricato">
|
||||||
|
<h2 id="page-heading" data-cy="PrenotazioneHeading">
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.home.titleIncaricato') }}</span>
|
||||||
|
<div class="d-flex justify-content-end">
|
||||||
|
<button class="btn btn-info" @click="handleSyncList" :disabled="isFetching">
|
||||||
|
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.home.refreshListLabel') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<!-- Table 1: Pending (no conferma) -->
|
||||||
|
<h4>{{ t$('smartbookingApp.prenotazione.pendenti.title') }}</h4>
|
||||||
|
<div class="alert alert-warning" v-if="!isFetching && prenotazioniPendenti.length === 0">
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.pendenti.notFound') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive" v-if="prenotazioniPendenti.length > 0">
|
||||||
|
<table class="table table-striped" aria-describedby="prenotazioni-pendenti">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ t$('global.field.id') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.oraInizio') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.oraFine') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.stato') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.utente') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.struttura') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="prenotazione in prenotazioniPendenti" :key="prenotazione.id" data-cy="entityTablePendenti">
|
||||||
|
<td>
|
||||||
|
<router-link :to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }">{{
|
||||||
|
prenotazione.id
|
||||||
|
}}</router-link>
|
||||||
|
</td>
|
||||||
|
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
|
||||||
|
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
|
||||||
|
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="prenotazione.utente">{{ prenotazione.utente.username }}</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="prenotazione.struttura">{{ prenotazione.struttura.nome }}</div>
|
||||||
|
</td>
|
||||||
|
<td>{{ prenotazione.motivoEvento }}</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<div class="btn-group">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }"
|
||||||
|
class="btn btn-info btn-sm details"
|
||||||
|
data-cy="entityDetailsButton"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="eye"></font-awesome-icon>
|
||||||
|
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
|
||||||
|
</router-link>
|
||||||
|
<button
|
||||||
|
class="btn btn-success btn-sm"
|
||||||
|
data-cy="prendiInCaricoButton"
|
||||||
|
@click="prendiInCarico(prenotazione)"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="check"></font-awesome-icon>
|
||||||
|
<span class="d-none d-md-inline">{{ t$('smartbookingApp.prenotazione.prendiInCarico.button') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<!-- Table 2: Completed (with conferma) -->
|
||||||
|
<h4>{{ t$('smartbookingApp.prenotazione.completate.title') }}</h4>
|
||||||
|
<div class="alert alert-warning" v-if="!isFetching && prenotazioniCompletate.length === 0">
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.completate.notFound') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive" v-if="prenotazioniCompletate.length > 0">
|
||||||
|
<table class="table table-striped" aria-describedby="prenotazioni-completate">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{{ t$('global.field.id') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.oraInizio') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.oraFine') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.stato') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.utente') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.struttura') }}</th>
|
||||||
|
<th scope="col">{{ t$('smartbookingApp.prenotazione.conferma') }}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="prenotazione in prenotazioniCompletate" :key="prenotazione.id" data-cy="entityTableCompletate">
|
||||||
|
<td>
|
||||||
|
<router-link :to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }">{{
|
||||||
|
prenotazione.id
|
||||||
|
}}</router-link>
|
||||||
|
</td>
|
||||||
|
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
|
||||||
|
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
|
||||||
|
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="prenotazione.utente">{{ prenotazione.utente.username }}</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="prenotazione.struttura">{{ prenotazione.struttura.nome }}</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-success">
|
||||||
|
{{ t$('smartbookingApp.TipoConferma.' + prenotazione.conferma?.tipoConferma) }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<div class="btn-group">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }"
|
||||||
|
class="btn btn-info btn-sm details"
|
||||||
|
data-cy="entityDetailsButton"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="eye"></font-awesome-icon>
|
||||||
|
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
|
||||||
|
</router-link>
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'ConfermaView', params: { confermaId: prenotazione.conferma.id } }"
|
||||||
|
class="btn btn-secondary btn-sm"
|
||||||
|
data-cy="entityConfermaButton"
|
||||||
|
>
|
||||||
|
<font-awesome-icon icon="file-alt"></font-awesome-icon>
|
||||||
|
<span class="d-none d-md-inline">{{ t$('smartbookingApp.prenotazione.viewConferma') }}</span>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination (shared) -->
|
||||||
|
<div v-show="prenotaziones?.length > 0">
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- "Prendi in carico" modal -->
|
||||||
|
<b-modal v-model="showPrendiInCaricoModal" :title="t$('smartbookingApp.prenotazione.prendiInCarico.title')" @hidden="closePrendiInCaricoModal">
|
||||||
|
<div v-if="selectedPrenotazione">
|
||||||
|
<p class="text-muted mb-3">
|
||||||
|
{{ t$('smartbookingApp.prenotazione.prendiInCarico.subtitle', { id: selectedPrenotazione.id }) }}
|
||||||
|
</p>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="tipoConfermaSelect" class="form-label fw-bold">
|
||||||
|
{{ t$('smartbookingApp.conferma.tipoConferma') }} <span class="text-danger">*</span>
|
||||||
|
</label>
|
||||||
|
<select id="tipoConfermaSelect" class="form-select" v-model="confermaForm.tipoConferma">
|
||||||
|
<option value="">{{ t$('smartbookingApp.prenotazione.prendiInCarico.selectTipo') }}</option>
|
||||||
|
<option value="CONFERMATA">{{ t$('smartbookingApp.TipoConferma.CONFERMATA') }}</option>
|
||||||
|
<option value="RIFIUTATA">{{ t$('smartbookingApp.TipoConferma.RIFIUTATA') }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="motivoConfermaInput" class="form-label fw-bold">
|
||||||
|
{{ t$('smartbookingApp.conferma.motivoConferma') }}
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="motivoConfermaInput"
|
||||||
|
class="form-control"
|
||||||
|
rows="4"
|
||||||
|
v-model="confermaForm.motivoConferma"
|
||||||
|
:placeholder="t$('smartbookingApp.prenotazione.prendiInCarico.motivoPlaceholder')"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<button type="button" class="btn btn-secondary" @click="closePrendiInCaricoModal">
|
||||||
|
{{ t$('entity.action.cancel') }}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
id="jhi-confirm-delete-prenotazione"
|
:disabled="!confermaForm.tipoConferma || isSubmittingConferma"
|
||||||
data-cy="entityConfirmDeleteButton"
|
@click="submitConferma"
|
||||||
@click="removePrenotazione"
|
|
||||||
>
|
>
|
||||||
{{ t$('entity.action.delete') }}
|
<span v-if="isSubmittingConferma">
|
||||||
|
<b-spinner small></b-spinner>
|
||||||
|
</span>
|
||||||
|
{{ t$('smartbookingApp.prenotazione.prendiInCarico.submit') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</template>
|
||||||
</template>
|
</b-modal>
|
||||||
</b-modal>
|
</template>
|
||||||
<div v-show="prenotaziones?.length > 0">
|
|
||||||
<div class="d-flex justify-content-center">
|
|
||||||
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-center">
|
|
||||||
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
"smartbookingApp": {
|
"smartbookingApp": {
|
||||||
"prenotazione": {
|
"prenotazione": {
|
||||||
"home": {
|
"home": {
|
||||||
"title": "Prenotaziones",
|
"title": "Le mie prenotazioni",
|
||||||
"refreshListLabel": "Refresh list",
|
"titleIncaricato": "Gestione prenotazioni",
|
||||||
"createLabel": "Genera un nuovo Prenotazione",
|
"refreshListLabel": "Aggiorna lista",
|
||||||
|
"createLabel": "Nuova prenotazione",
|
||||||
"createOrEditLabel": "Genera o modifica un Prenotazione",
|
"createOrEditLabel": "Genera o modifica un Prenotazione",
|
||||||
"notFound": "No Prenotaziones found"
|
"notFound": "Nessuna prenotazione trovata"
|
||||||
},
|
},
|
||||||
"created": "È stato generato un nuovo Prenotazione con identificatore {{ param }}",
|
"created": "È stato generato un nuovo Prenotazione con identificatore {{ param }}",
|
||||||
"updated": "È stato aggiornato Prenotazione identificato da {{ param }}",
|
"updated": "È stato aggiornato Prenotazione identificato da {{ param }}",
|
||||||
@@ -27,6 +28,24 @@
|
|||||||
"conferma": "Conferma",
|
"conferma": "Conferma",
|
||||||
"utente": "Utente",
|
"utente": "Utente",
|
||||||
"struttura": "Struttura",
|
"struttura": "Struttura",
|
||||||
|
"viewConferma": "Vedi conferma",
|
||||||
|
"pendenti": {
|
||||||
|
"title": "Prenotazioni in attesa",
|
||||||
|
"notFound": "Nessuna prenotazione in attesa"
|
||||||
|
},
|
||||||
|
"completate": {
|
||||||
|
"title": "Prenotazioni gestite",
|
||||||
|
"notFound": "Nessuna prenotazione gestita"
|
||||||
|
},
|
||||||
|
"prendiInCarico": {
|
||||||
|
"button": "Prendi in carico",
|
||||||
|
"title": "Prendi in carico la prenotazione",
|
||||||
|
"subtitle": "Prenotazione #{id}",
|
||||||
|
"selectTipo": "-- Seleziona esito --",
|
||||||
|
"motivoPlaceholder": "Inserisci il motivo o le note relative alla decisione...",
|
||||||
|
"submit": "Conferma",
|
||||||
|
"success": "Prenotazione presa in carico con successo"
|
||||||
|
},
|
||||||
"userForm": {
|
"userForm": {
|
||||||
"title": "Nuova Prenotazione",
|
"title": "Nuova Prenotazione",
|
||||||
"bookingDetails": "Dettagli",
|
"bookingDetails": "Dettagli",
|
||||||
|
|||||||
Reference in New Issue
Block a user