Compare commits
6 Commits
f61e9b512c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a1164b185b | |||
| b152c255b4 | |||
|
|
35e3c51623 | ||
|
|
45968b28e2 | ||
|
|
78d3e17d02 | ||
|
|
b4d0ca4898 |
@@ -37,11 +37,11 @@
|
|||||||
"pagination": "pagination",
|
"pagination": "pagination",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "username",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "utenteApp",
|
"otherEntityName": "utenteApp",
|
||||||
"relationshipName": "utente",
|
"relationshipName": "utente",
|
||||||
"otherEntityField": "username"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -20,18 +20,18 @@
|
|||||||
"pagination": "pagination",
|
"pagination": "pagination",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "username",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "utenteApp",
|
"otherEntityName": "utenteApp",
|
||||||
"relationshipName": "confermataDa",
|
"relationshipName": "confermataDa",
|
||||||
"otherEntityField": "username"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relationshipSide": "right",
|
|
||||||
"relationshipType": "one-to-one",
|
|
||||||
"otherEntityName": "prenotazione",
|
"otherEntityName": "prenotazione",
|
||||||
"otherEntityRelationshipName": "conferma",
|
"otherEntityRelationshipName": "conferma",
|
||||||
"relationshipName": "prenotazione"
|
"relationshipName": "prenotazione",
|
||||||
|
"relationshipSide": "right",
|
||||||
|
"relationshipType": "one-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -44,12 +44,12 @@
|
|||||||
"pagination": "infinite-scroll",
|
"pagination": "infinite-scroll",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "nome",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "struttura",
|
"otherEntityName": "struttura",
|
||||||
"otherEntityRelationshipName": "disponibilita",
|
"otherEntityRelationshipName": "disponibilita",
|
||||||
"relationshipName": "struttura",
|
"relationshipName": "struttura",
|
||||||
"otherEntityField": "nome"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -13,18 +13,18 @@
|
|||||||
"name": "Liberatoria",
|
"name": "Liberatoria",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "username",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "utenteApp",
|
"otherEntityName": "utenteApp",
|
||||||
"otherEntityRelationshipName": "liberatorie",
|
"otherEntityRelationshipName": "liberatorie",
|
||||||
"relationshipName": "utente",
|
"relationshipName": "utente",
|
||||||
"otherEntityField": "username"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "modelloLiberatoria",
|
"otherEntityName": "modelloLiberatoria",
|
||||||
"relationshipName": "modelloLiberatoria"
|
"relationshipName": "modelloLiberatoria",
|
||||||
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -21,11 +21,11 @@
|
|||||||
"name": "Messaggio",
|
"name": "Messaggio",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "username",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "utenteApp",
|
"otherEntityName": "utenteApp",
|
||||||
"relationshipName": "utente",
|
"relationshipName": "utente",
|
||||||
"otherEntityField": "username"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -29,11 +29,11 @@
|
|||||||
"name": "ModelloLiberatoria",
|
"name": "ModelloLiberatoria",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "struttura",
|
"otherEntityName": "struttura",
|
||||||
"otherEntityRelationshipName": "moduliLiberatorie",
|
"otherEntityRelationshipName": "moduliLiberatorie",
|
||||||
"relationshipName": "struttura"
|
"relationshipName": "struttura",
|
||||||
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -41,10 +41,10 @@
|
|||||||
"pagination": "pagination",
|
"pagination": "pagination",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "conferma",
|
"otherEntityName": "conferma",
|
||||||
"relationshipName": "conferma"
|
"relationshipName": "conferma",
|
||||||
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -36,25 +36,25 @@
|
|||||||
"pagination": "pagination",
|
"pagination": "pagination",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
|
||||||
"relationshipType": "one-to-one",
|
|
||||||
"otherEntityName": "conferma",
|
"otherEntityName": "conferma",
|
||||||
"otherEntityRelationshipName": "prenotazione",
|
"otherEntityRelationshipName": "prenotazione",
|
||||||
"relationshipName": "conferma"
|
"relationshipName": "conferma",
|
||||||
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "one-to-one"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "username",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "utenteApp",
|
"otherEntityName": "utenteApp",
|
||||||
"relationshipName": "utente",
|
"relationshipName": "utente",
|
||||||
"otherEntityField": "username"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "nome",
|
||||||
"relationshipType": "many-to-one",
|
|
||||||
"otherEntityName": "struttura",
|
"otherEntityName": "struttura",
|
||||||
"relationshipName": "struttura",
|
"relationshipName": "struttura",
|
||||||
"otherEntityField": "nome"
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "many-to-one"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -43,18 +43,18 @@
|
|||||||
"pagination": "pagination",
|
"pagination": "pagination",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "right",
|
|
||||||
"relationshipType": "one-to-many",
|
|
||||||
"otherEntityName": "disponibilita",
|
"otherEntityName": "disponibilita",
|
||||||
"otherEntityRelationshipName": "struttura",
|
"otherEntityRelationshipName": "struttura",
|
||||||
"relationshipName": "disponibilita"
|
"relationshipName": "disponibilita",
|
||||||
|
"relationshipSide": "right",
|
||||||
|
"relationshipType": "one-to-many"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relationshipSide": "right",
|
|
||||||
"relationshipType": "one-to-many",
|
|
||||||
"otherEntityName": "modelloLiberatoria",
|
"otherEntityName": "modelloLiberatoria",
|
||||||
"otherEntityRelationshipName": "struttura",
|
"otherEntityRelationshipName": "struttura",
|
||||||
"relationshipName": "moduliLiberatorie"
|
"relationshipName": "moduliLiberatorie",
|
||||||
|
"relationshipSide": "right",
|
||||||
|
"relationshipType": "one-to-many"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
{
|
{
|
||||||
"fieldName": "ruolo",
|
"fieldName": "ruolo",
|
||||||
"fieldType": "Ruolo",
|
"fieldType": "Ruolo",
|
||||||
"fieldValues": "USER,INCARICATO,ADMIN",
|
"fieldValidateRules": ["required"],
|
||||||
"fieldValidateRules": ["required"]
|
"fieldValues": "USER,INCARICATO,ADMIN"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldName": "attivo",
|
"fieldName": "attivo",
|
||||||
@@ -74,19 +74,19 @@
|
|||||||
"name": "UtenteApp",
|
"name": "UtenteApp",
|
||||||
"relationships": [
|
"relationships": [
|
||||||
{
|
{
|
||||||
"relationshipSide": "left",
|
"otherEntityField": "login",
|
||||||
"relationshipType": "one-to-one",
|
|
||||||
"otherEntityName": "user",
|
"otherEntityName": "user",
|
||||||
"relationshipName": "internalUser",
|
"relationshipName": "internalUser",
|
||||||
"otherEntityField": "login",
|
"relationshipSide": "left",
|
||||||
|
"relationshipType": "one-to-one",
|
||||||
"relationshipWithBuiltInEntity": true
|
"relationshipWithBuiltInEntity": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"relationshipSide": "right",
|
|
||||||
"relationshipType": "one-to-many",
|
|
||||||
"otherEntityName": "liberatoria",
|
"otherEntityName": "liberatoria",
|
||||||
"otherEntityRelationshipName": "utente",
|
"otherEntityRelationshipName": "utente",
|
||||||
"relationshipName": "liberatorie"
|
"relationshipName": "liberatorie",
|
||||||
|
"relationshipSide": "right",
|
||||||
|
"relationshipType": "one-to-many"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"searchEngine": "no",
|
"searchEngine": "no",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
"lastLiquibaseTimestamp": 1765383090000,
|
"lastLiquibaseTimestamp": 1765383090000,
|
||||||
"microfrontend": null,
|
"microfrontend": null,
|
||||||
"microfrontends": [],
|
"microfrontends": [],
|
||||||
|
"monorepository": true,
|
||||||
"nativeLanguage": "it",
|
"nativeLanguage": "it",
|
||||||
"packageName": "it.sw.pa.comune.artegna",
|
"packageName": "it.sw.pa.comune.artegna",
|
||||||
"prodDatabaseType": "postgresql",
|
"prodDatabaseType": "postgresql",
|
||||||
@@ -42,10 +43,9 @@
|
|||||||
"rememberMeKey": "c3201ccf39b5d82ef696ad12b95009f33d980fc0468a86e957ad91487d1fe80d9440f72a1d09721585bc96b11048fda07240",
|
"rememberMeKey": "c3201ccf39b5d82ef696ad12b95009f33d980fc0468a86e957ad91487d1fe80d9440f72a1d09721585bc96b11048fda07240",
|
||||||
"serverPort": null,
|
"serverPort": null,
|
||||||
"serviceDiscoveryType": null,
|
"serviceDiscoveryType": null,
|
||||||
|
"skipCommitHook": true,
|
||||||
"syncUserWithIdp": null,
|
"syncUserWithIdp": null,
|
||||||
"testFrameworks": ["cypress"],
|
"testFrameworks": ["cypress"],
|
||||||
"withAdminUi": true,
|
"withAdminUi": true
|
||||||
"monorepository": true,
|
|
||||||
"skipCommitHook": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ dependencies {
|
|||||||
implementation "org.hibernate.orm:hibernate-jcache"
|
implementation "org.hibernate.orm:hibernate-jcache"
|
||||||
implementation "org.hibernate.validator:hibernate-validator"
|
implementation "org.hibernate.validator:hibernate-validator"
|
||||||
implementation "org.postgresql:postgresql"
|
implementation "org.postgresql:postgresql"
|
||||||
|
implementation "io.seruco.encoding:base62:0.1.3"
|
||||||
|
implementation "com.twilio.sdk:twilio:11.3.6"
|
||||||
|
|
||||||
testImplementation(libs.archunit.junit5.api) {
|
testImplementation(libs.archunit.junit5.api) {
|
||||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||||
}
|
}
|
||||||
|
|||||||
10
docker-compose/.yo-rc.json
Normal file
10
docker-compose/.yo-rc.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"generator-jhipster": {
|
||||||
|
"appsFolders": ["smartbooking"],
|
||||||
|
"deploymentType": "docker-compose",
|
||||||
|
"directoryPath": "../../",
|
||||||
|
"jwtSecretKey": "MDQwNzk2YjgyMzE3NjQxNWViNzQyZThjNmJjNjI1YzBmZGRiYzBmYzMxNjg2ODM4MGMxOTFjM2NiNGUxMDE1ZWFiODA0ZTA1M2JkZjM5NThhNTc3YzViY2MxY2IxYTNiYWQ0Zg==",
|
||||||
|
"monitoring": "no",
|
||||||
|
"serviceDiscoveryType": "no"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
docker-compose/README-DOCKER-COMPOSE.md
Normal file
14
docker-compose/README-DOCKER-COMPOSE.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# JHipster generated Docker-Compose configuration
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Launch all your infrastructure by running: `docker compose up -d`.
|
||||||
|
|
||||||
|
## Configured Docker services
|
||||||
|
|
||||||
|
### Applications and dependencies:
|
||||||
|
|
||||||
|
- smartbooking (monolith application)
|
||||||
|
- smartbooking's postgresql database
|
||||||
|
|
||||||
|
### Additional Services:
|
||||||
31
docker-compose/docker-compose.yml
Normal file
31
docker-compose/docker-compose.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
services:
|
||||||
|
smartbooking:
|
||||||
|
image: git.bigc.it/sbierti/smartbooking:latest
|
||||||
|
environment:
|
||||||
|
- _JAVA_OPTIONS=-Xmx512m -Xms256m
|
||||||
|
- SPRING_PROFILES_ACTIVE=prod,api-docs
|
||||||
|
- MANAGEMENT_PROMETHEUS_METRICS_EXPORT_ENABLED=true
|
||||||
|
- SPRING_DATASOURCE_URL=jdbc:postgresql://smartbooking-postgresql:5432/smartbooking
|
||||||
|
- SPRING_LIQUIBASE_URL=jdbc:postgresql://smartbooking-postgresql:5432/smartbooking
|
||||||
|
- JHIPSTER_SLEEP=30
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
depends_on:
|
||||||
|
- postgresql
|
||||||
|
postgresql:
|
||||||
|
image: postgres:18.1
|
||||||
|
# volumes:
|
||||||
|
# - ~/volumes/jhipster/smartbooking/postgresql/:/var/lib/postgresql/data/
|
||||||
|
environment:
|
||||||
|
- POSTGRES_USER=smartbooking
|
||||||
|
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||||
|
healthcheck:
|
||||||
|
test: [ 'CMD-SHELL', 'pg_isready -U $${POSTGRES_USER}' ]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
# If you want to expose these ports outside your dev PC,
|
||||||
|
# remove the "127.0.0.1:" prefix
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:5432:5432
|
||||||
|
|
||||||
78
features/visualizzazione-prenotazioni.md
Normal file
78
features/visualizzazione-prenotazioni.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
Ecco una bozza di specifiche tecniche strutturate in **Markdown**, ottimizzate per essere interpretate da un agente di coding (come un plugin IDE o un modello LLM focalizzato sullo sviluppo).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Specifiche Tecniche: Gestione e Visualizzazione Prenotazioni
|
||||||
|
|
||||||
|
## 1. Obiettivo
|
||||||
|
Implementare un sistema di visualizzazione e gestione delle prenotazioni basato sui ruoli utente (`ROLE_USER`, `ROLE_INCARICATO`), con logica di business legata all'esistenza di un oggetto `Conferma` correlato.
|
||||||
|
|
||||||
|
## 2. Modello Dati e Relazioni
|
||||||
|
* **Prenotazione (P):** Entità principale.
|
||||||
|
* **Conferma (C):** Entità correlata a `Prenotazione`.
|
||||||
|
* **Relazione:** One-to-One.
|
||||||
|
* **Chiave Primaria:** `C.id` deve coincidere con `P.id`.
|
||||||
|
* **Campi Conferma:**
|
||||||
|
* `tipoConferma` (Enum: `TipoConferma`)
|
||||||
|
* `motivoConferma` (String/Text)
|
||||||
|
* `codice` (String, Alfanumerico Base62, generato dal sistema).
|
||||||
|
|
||||||
|
## 3. Logica di Accesso e Visualizzazione
|
||||||
|
|
||||||
|
### 3.1 Vista: ROLE_USER
|
||||||
|
L'utente visualizza esclusivamente le proprie prenotazioni.
|
||||||
|
|
||||||
|
* **Query:** `SELECT * FROM Prenotazione WHERE utente_id = :current_user_id ORDER BY data_inserimento DESC`.
|
||||||
|
* **Interfaccia (Tabella):**
|
||||||
|
* **Caso A: Prenotazione SENZA Conferma**
|
||||||
|
* Azioni permesse: **Visualizza**, **Modifica**, **Cancella**.
|
||||||
|
* **Caso B: Prenotazione CON Conferma**
|
||||||
|
* Azioni permesse: **Visualizza** (Read-only), **Visualizza Conferma**.
|
||||||
|
* Inibizione: I tasti Modifica e Cancella devono essere disabilitati o nascosti.
|
||||||
|
|
||||||
|
### 3.2 Vista: ROLE_INCARICATO
|
||||||
|
L'utente visualizza tutte le prenotazioni del sistema create negli ultimi 12 mesi.
|
||||||
|
|
||||||
|
* **Filtro Temporale:** `data_prenotazione >= CURRENT_DATE - 12 mesi`.
|
||||||
|
* **Layout:** Due tabelle distinte.
|
||||||
|
|
||||||
|
#### Tabella 1: Prenotazioni Pendenti (Senza Conferma)
|
||||||
|
* **Contenuto:** Prenotazioni che non hanno un record corrispondente nella tabella `Conferma`.
|
||||||
|
* **Azioni:**
|
||||||
|
1. **Visualizza:** Apre il dettaglio della prenotazione.
|
||||||
|
2. **Prendi in carico:** Apre una finestra modale (Pop-up).
|
||||||
|
|
||||||
|
#### Tabella 2: Prenotazioni Completate (Con Conferma)
|
||||||
|
* **Contenuto:** Prenotazioni che hanno un record corrispondente nella tabella `Conferma`.
|
||||||
|
* **Azioni:** Visualizzazione del dettaglio e della relativa conferma.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Workflow "Prendi in carico" (Modale)
|
||||||
|
Al clic sul pulsante nella Tabella 1 del `ROLE_INCARICATO`:
|
||||||
|
|
||||||
|
1. **Apertura Modale:** Form di creazione per l'oggetto `Conferma`.
|
||||||
|
2. **Input Utente:**
|
||||||
|
* `tipoConferma`: Select box basata sull'Enum.
|
||||||
|
* `motivoConferma`: TextArea (Testo libero).
|
||||||
|
3. **Logica di Sistema (Generazione Codice):**
|
||||||
|
* Il campo `codice` deve essere generato lato server (o pre-calcolato) convertendo il timestamp corrente (data/ora) in una stringa **Base62** (caratteri `0-9`, `a-z`, `A-Z`).
|
||||||
|
4. **Salvataggio:**
|
||||||
|
* Creazione record `Conferma` con `id` identico a quello della `Prenotazione` selezionata.
|
||||||
|
5. **Post-Azione:**
|
||||||
|
* Chiusura modale.
|
||||||
|
* **Refresh Reattivo:** Le tabelle devono aggiornarsi senza ricaricare l'intera pagina (la prenotazione deve spostarsi dalla Tabella 1 alla Tabella 2).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Requisiti Tecnici Suggeriti
|
||||||
|
* **Sicurezza:** Verificare l'authority lato server (Spring Security o equivalente) per ogni richiesta API. Non basarsi solo sull'occultamento dei tasti lato UI.
|
||||||
|
* **Generazione Base62:** Implementare una funzione di encoding che trasformi `long timestamp` in `String Base62`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Definizione del Successo (Criteri di Accettazione)
|
||||||
|
* [ ] Un `ROLE_USER` non può cancellare una prenotazione se esiste una conferma.
|
||||||
|
* [ ] Un `ROLE_INCARICATO` vede solo i dati degli ultimi 12 mesi.
|
||||||
|
* [ ] Il salvataggio di una conferma sposta istantaneamente la riga tra le due tabelle dell'incaricato.
|
||||||
|
* [ ] Il codice della conferma è univoco e generato in Base62.
|
||||||
@@ -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,6 +1,8 @@
|
|||||||
package it.sw.pa.comune.artegna.repository;
|
package it.sw.pa.comune.artegna.repository;
|
||||||
|
|
||||||
import it.sw.pa.comune.artegna.domain.Prenotazione;
|
import it.sw.pa.comune.artegna.domain.Prenotazione;
|
||||||
|
import it.sw.pa.comune.artegna.domain.enumeration.StatoPrenotazione;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -39,4 +41,6 @@ public interface PrenotazioneRepository extends JpaRepository<Prenotazione, Long
|
|||||||
"select prenotazione from Prenotazione prenotazione left join fetch prenotazione.utente left join fetch prenotazione.struttura where prenotazione.id =:id"
|
"select prenotazione from Prenotazione prenotazione left join fetch prenotazione.utente left join fetch prenotazione.struttura where prenotazione.id =:id"
|
||||||
)
|
)
|
||||||
Optional<Prenotazione> findOneWithToOneRelationships(@Param("id") Long id);
|
Optional<Prenotazione> findOneWithToOneRelationships(@Param("id") Long id);
|
||||||
|
|
||||||
|
Long id(Long id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ public final class AuthoritiesConstants {
|
|||||||
|
|
||||||
public static final String ADMIN = "ROLE_ADMIN";
|
public static final String ADMIN = "ROLE_ADMIN";
|
||||||
|
|
||||||
|
public static final String INCARICATO = "ROLE_INCARICATO";
|
||||||
|
|
||||||
public static final String USER = "ROLE_USER";
|
public static final String USER = "ROLE_USER";
|
||||||
|
|
||||||
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
|
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
|
||||||
|
|||||||
@@ -117,4 +117,13 @@ public class MailService {
|
|||||||
LOG.debug("Sending password reset email to '{}'", user.getEmail());
|
LOG.debug("Sending password reset email to '{}'", user.getEmail());
|
||||||
sendEmailFromTemplateSync(user, "mail/passwordResetEmail", "email.reset.title");
|
sendEmailFromTemplateSync(user, "mail/passwordResetEmail", "email.reset.title");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// crea un metodo per l'invio di email che la prenotazione è stata confermata o rifiutata
|
||||||
|
@Async
|
||||||
|
public void sendBookingConfirmationEmail(User user, boolean confirmed) {
|
||||||
|
String templateName = confirmed ? "mail/bookingConfirmedEmail" : "mail/bookingRejectedEmail";
|
||||||
|
String titleKey = confirmed ? "email.booking.confirmed.title" : "email.booking.rejected.title";
|
||||||
|
LOG.debug("Sending {} email to '{}'", confirmed ? "confirmation" : "rejection", user.getEmail());
|
||||||
|
sendEmailFromTemplateSync(user, templateName, titleKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package it.sw.pa.comune.artegna.service;
|
package it.sw.pa.comune.artegna.service;
|
||||||
|
|
||||||
import it.sw.pa.comune.artegna.service.dto.PrenotazioneDTO;
|
import it.sw.pa.comune.artegna.service.dto.PrenotazioneDTO;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package it.sw.pa.comune.artegna.service;
|
||||||
|
|
||||||
|
import com.twilio.Twilio;
|
||||||
|
import com.twilio.converter.Promoter;
|
||||||
|
import com.twilio.rest.api.v2010.account.Message;
|
||||||
|
import com.twilio.type.PhoneNumber;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.net.URI;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
public class TwilioService {
|
||||||
|
|
||||||
|
@Value("${twilio.account.sid}")
|
||||||
|
private String accountSid;
|
||||||
|
|
||||||
|
@Value("${twilio.auth.token}")
|
||||||
|
private String authToken;
|
||||||
|
|
||||||
|
@Value("${twilio.whatsapp.number}")
|
||||||
|
private String fromWhatsAppNumber;
|
||||||
|
|
||||||
|
public TwilioService() {
|
||||||
|
// Initialize Twilio with account credentials
|
||||||
|
Twilio.init(accountSid, authToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sendWhatsAppMessage(String to, String messageBody) {
|
||||||
|
// Send a message via Twilio's API
|
||||||
|
Message message = Message.creator(
|
||||||
|
new PhoneNumber("whatsapp:" + to), // Recipient's WhatsApp number
|
||||||
|
new PhoneNumber(fromWhatsAppNumber), // Twilio WhatsApp number
|
||||||
|
messageBody
|
||||||
|
).create(); // Message body
|
||||||
|
|
||||||
|
return message.getSid(); // Return message SID to track status
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,4 +71,6 @@ public interface UtenteAppService {
|
|||||||
* @param id the id of the entity.
|
* @param id the id of the entity.
|
||||||
*/
|
*/
|
||||||
void delete(Long id);
|
void delete(Long id);
|
||||||
|
|
||||||
|
UtenteAppDTO fetchUtenteAppFromUser();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
package it.sw.pa.comune.artegna.service.impl;
|
package it.sw.pa.comune.artegna.service.impl;
|
||||||
|
|
||||||
|
import static it.sw.pa.comune.artegna.domain.enumeration.TipoEventoNotifica.ANNULLAMENTO;
|
||||||
|
|
||||||
|
import io.seruco.encoding.base62.Base62;
|
||||||
import it.sw.pa.comune.artegna.domain.Conferma;
|
import it.sw.pa.comune.artegna.domain.Conferma;
|
||||||
|
import it.sw.pa.comune.artegna.domain.Prenotazione;
|
||||||
|
import it.sw.pa.comune.artegna.domain.User;
|
||||||
|
import it.sw.pa.comune.artegna.domain.enumeration.StatoPrenotazione;
|
||||||
|
import it.sw.pa.comune.artegna.domain.enumeration.TipoConferma;
|
||||||
import it.sw.pa.comune.artegna.repository.ConfermaRepository;
|
import it.sw.pa.comune.artegna.repository.ConfermaRepository;
|
||||||
|
import it.sw.pa.comune.artegna.repository.PrenotazioneRepository;
|
||||||
import it.sw.pa.comune.artegna.service.ConfermaService;
|
import it.sw.pa.comune.artegna.service.ConfermaService;
|
||||||
|
import it.sw.pa.comune.artegna.service.UserService;
|
||||||
|
import it.sw.pa.comune.artegna.service.UtenteAppService;
|
||||||
import it.sw.pa.comune.artegna.service.dto.ConfermaDTO;
|
import it.sw.pa.comune.artegna.service.dto.ConfermaDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
||||||
import it.sw.pa.comune.artegna.service.mapper.ConfermaMapper;
|
import it.sw.pa.comune.artegna.service.mapper.ConfermaMapper;
|
||||||
|
import it.sw.pa.comune.artegna.service.mapper.UserMapper;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -14,6 +26,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -30,19 +43,67 @@ public class ConfermaServiceImpl implements ConfermaService {
|
|||||||
|
|
||||||
private final ConfermaMapper confermaMapper;
|
private final ConfermaMapper confermaMapper;
|
||||||
|
|
||||||
public ConfermaServiceImpl(ConfermaRepository confermaRepository, ConfermaMapper confermaMapper) {
|
private final PrenotazioneRepository prenotazioneRepository;
|
||||||
|
|
||||||
|
private final UtenteAppService utenteAppService;
|
||||||
|
|
||||||
|
public ConfermaServiceImpl(
|
||||||
|
ConfermaRepository confermaRepository,
|
||||||
|
ConfermaMapper confermaMapper,
|
||||||
|
PrenotazioneRepository prenotazioneRepository,
|
||||||
|
UtenteAppService utenteAppService
|
||||||
|
) {
|
||||||
this.confermaRepository = confermaRepository;
|
this.confermaRepository = confermaRepository;
|
||||||
this.confermaMapper = confermaMapper;
|
this.confermaMapper = confermaMapper;
|
||||||
|
this.prenotazioneRepository = prenotazioneRepository;
|
||||||
|
this.utenteAppService = utenteAppService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfermaDTO save(ConfermaDTO confermaDTO) {
|
public ConfermaDTO save(ConfermaDTO confermaDTO) {
|
||||||
LOG.debug("Request to save Conferma : {}", confermaDTO);
|
LOG.debug("Request to save Conferma : {}", confermaDTO);
|
||||||
|
confermaDTO.setConfermataDa(utenteAppService.fetchUtenteAppFromUser());
|
||||||
Conferma conferma = confermaMapper.toEntity(confermaDTO);
|
Conferma conferma = confermaMapper.toEntity(confermaDTO);
|
||||||
conferma = confermaRepository.save(conferma);
|
Long idPrenotazione = null;
|
||||||
|
if (conferma.getId() != null) {
|
||||||
|
idPrenotazione = conferma.getId();
|
||||||
|
conferma.setId(null);
|
||||||
|
conferma.setCodice(createCodice());
|
||||||
|
if (conferma.getTipoConferma() == null) {
|
||||||
|
conferma.setTipoConferma(TipoConferma.RIFIUTATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conferma = confermaRepository.saveAndFlush(conferma);
|
||||||
|
if (idPrenotazione != null) {
|
||||||
|
Prenotazione prenotazioneCollegata = prenotazioneRepository.findById(idPrenotazione).orElse(null);
|
||||||
|
if (prenotazioneCollegata != null) {
|
||||||
|
switch (conferma.getTipoConferma()) {
|
||||||
|
case CONFERMATA:
|
||||||
|
prenotazioneCollegata.setStato(StatoPrenotazione.CONFERMATA);
|
||||||
|
break;
|
||||||
|
case RIFIUTATA:
|
||||||
|
prenotazioneCollegata.setStato(StatoPrenotazione.ANNULLATA);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Tipo conferma non valido: " + conferma.getTipoConferma());
|
||||||
|
}
|
||||||
|
prenotazioneCollegata.setConferma(conferma);
|
||||||
|
prenotazioneRepository.saveAndFlush(prenotazioneCollegata);
|
||||||
|
}
|
||||||
|
}
|
||||||
return confermaMapper.toDto(conferma);
|
return confermaMapper.toDto(conferma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String createCodice() {
|
||||||
|
Base62 base62 = Base62.createInstance();
|
||||||
|
String currentDateTime = String.valueOf(java.time.Instant.now().toEpochMilli());
|
||||||
|
|
||||||
|
return new String(
|
||||||
|
base62.encode(currentDateTime.getBytes(java.nio.charset.StandardCharsets.UTF_8)),
|
||||||
|
java.nio.charset.StandardCharsets.UTF_8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfermaDTO update(ConfermaDTO confermaDTO) {
|
public ConfermaDTO update(ConfermaDTO confermaDTO) {
|
||||||
LOG.debug("Request to update Conferma : {}", confermaDTO);
|
LOG.debug("Request to update Conferma : {}", confermaDTO);
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package it.sw.pa.comune.artegna.service.impl;
|
package it.sw.pa.comune.artegna.service.impl;
|
||||||
|
|
||||||
import it.sw.pa.comune.artegna.domain.Prenotazione;
|
import it.sw.pa.comune.artegna.domain.Prenotazione;
|
||||||
|
import it.sw.pa.comune.artegna.domain.enumeration.StatoPrenotazione;
|
||||||
import it.sw.pa.comune.artegna.repository.PrenotazioneRepository;
|
import it.sw.pa.comune.artegna.repository.PrenotazioneRepository;
|
||||||
import it.sw.pa.comune.artegna.service.PrenotazioneService;
|
import it.sw.pa.comune.artegna.service.PrenotazioneService;
|
||||||
import it.sw.pa.comune.artegna.service.dto.PrenotazioneDTO;
|
import it.sw.pa.comune.artegna.service.dto.PrenotazioneDTO;
|
||||||
import it.sw.pa.comune.artegna.service.mapper.PrenotazioneMapper;
|
import it.sw.pa.comune.artegna.service.mapper.PrenotazioneMapper;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package it.sw.pa.comune.artegna.service.impl;
|
package it.sw.pa.comune.artegna.service.impl;
|
||||||
|
|
||||||
|
import it.sw.pa.comune.artegna.domain.Prenotazione;
|
||||||
import it.sw.pa.comune.artegna.domain.Struttura;
|
import it.sw.pa.comune.artegna.domain.Struttura;
|
||||||
|
import it.sw.pa.comune.artegna.domain.enumeration.StatoPrenotazione;
|
||||||
import it.sw.pa.comune.artegna.repository.StrutturaRepository;
|
import it.sw.pa.comune.artegna.repository.StrutturaRepository;
|
||||||
import it.sw.pa.comune.artegna.service.StrutturaService;
|
import it.sw.pa.comune.artegna.service.StrutturaService;
|
||||||
import it.sw.pa.comune.artegna.service.dto.StrutturaDTO;
|
import it.sw.pa.comune.artegna.service.dto.StrutturaDTO;
|
||||||
@@ -8,6 +10,7 @@ import it.sw.pa.comune.artegna.service.mapper.StrutturaMapper;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package it.sw.pa.comune.artegna.service.impl;
|
|||||||
|
|
||||||
import it.sw.pa.comune.artegna.domain.UtenteApp;
|
import it.sw.pa.comune.artegna.domain.UtenteApp;
|
||||||
import it.sw.pa.comune.artegna.repository.UtenteAppRepository;
|
import it.sw.pa.comune.artegna.repository.UtenteAppRepository;
|
||||||
|
import it.sw.pa.comune.artegna.service.UserService;
|
||||||
import it.sw.pa.comune.artegna.service.UtenteAppService;
|
import it.sw.pa.comune.artegna.service.UtenteAppService;
|
||||||
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.mapper.UserMapper;
|
||||||
import it.sw.pa.comune.artegna.service.mapper.UtenteAppMapper;
|
import it.sw.pa.comune.artegna.service.mapper.UtenteAppMapper;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,6 +15,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -29,9 +32,20 @@ public class UtenteAppServiceImpl implements UtenteAppService {
|
|||||||
|
|
||||||
private final UtenteAppMapper utenteAppMapper;
|
private final UtenteAppMapper utenteAppMapper;
|
||||||
|
|
||||||
public UtenteAppServiceImpl(UtenteAppRepository utenteAppRepository, UtenteAppMapper utenteAppMapper) {
|
private final UserService userService;
|
||||||
|
|
||||||
|
private final UserMapper userMapper;
|
||||||
|
|
||||||
|
public UtenteAppServiceImpl(
|
||||||
|
UtenteAppRepository utenteAppRepository,
|
||||||
|
UtenteAppMapper utenteAppMapper,
|
||||||
|
UserService userService,
|
||||||
|
UserMapper userMapper
|
||||||
|
) {
|
||||||
this.utenteAppRepository = utenteAppRepository;
|
this.utenteAppRepository = utenteAppRepository;
|
||||||
this.utenteAppMapper = utenteAppMapper;
|
this.utenteAppMapper = utenteAppMapper;
|
||||||
|
this.userService = userService;
|
||||||
|
this.userMapper = userMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -95,4 +109,12 @@ public class UtenteAppServiceImpl implements UtenteAppService {
|
|||||||
LOG.debug("Request to delete UtenteApp : {}", id);
|
LOG.debug("Request to delete UtenteApp : {}", id);
|
||||||
utenteAppRepository.deleteById(id);
|
utenteAppRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UtenteAppDTO fetchUtenteAppFromUser() {
|
||||||
|
String currentLogin = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||||
|
//User currentUser = userService.getUserWithAuthoritiesByLogin(currentLogin).orElseThrow();
|
||||||
|
UtenteAppDTO utenteAppDTO = utenteAppRepository.findByUsername(currentLogin).map(utenteAppMapper::toDto).orElseThrow();
|
||||||
|
return utenteAppDTO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
package it.sw.pa.comune.artegna.web.rest;
|
package it.sw.pa.comune.artegna.web.rest;
|
||||||
|
|
||||||
|
import it.sw.pa.comune.artegna.domain.User;
|
||||||
import it.sw.pa.comune.artegna.repository.ConfermaRepository;
|
import it.sw.pa.comune.artegna.repository.ConfermaRepository;
|
||||||
import it.sw.pa.comune.artegna.service.ConfermaQueryService;
|
import it.sw.pa.comune.artegna.service.ConfermaQueryService;
|
||||||
import it.sw.pa.comune.artegna.service.ConfermaService;
|
import it.sw.pa.comune.artegna.service.ConfermaService;
|
||||||
|
import it.sw.pa.comune.artegna.service.UserService;
|
||||||
import it.sw.pa.comune.artegna.service.criteria.ConfermaCriteria;
|
import it.sw.pa.comune.artegna.service.criteria.ConfermaCriteria;
|
||||||
import it.sw.pa.comune.artegna.service.dto.ConfermaDTO;
|
import it.sw.pa.comune.artegna.service.dto.ConfermaDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.mapper.UserMapper;
|
||||||
import it.sw.pa.comune.artegna.web.rest.errors.BadRequestAlertException;
|
import it.sw.pa.comune.artegna.web.rest.errors.BadRequestAlertException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.security.Principal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -18,6 +23,8 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
import tech.jhipster.web.util.HeaderUtil;
|
import tech.jhipster.web.util.HeaderUtil;
|
||||||
@@ -44,14 +51,22 @@ public class ConfermaResource {
|
|||||||
|
|
||||||
private final ConfermaQueryService confermaQueryService;
|
private final ConfermaQueryService confermaQueryService;
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
private final UserMapper userMapper;
|
||||||
|
|
||||||
public ConfermaResource(
|
public ConfermaResource(
|
||||||
ConfermaService confermaService,
|
ConfermaService confermaService,
|
||||||
ConfermaRepository confermaRepository,
|
ConfermaRepository confermaRepository,
|
||||||
ConfermaQueryService confermaQueryService
|
ConfermaQueryService confermaQueryService,
|
||||||
|
UserService userService,
|
||||||
|
UserMapper userMapper
|
||||||
) {
|
) {
|
||||||
this.confermaService = confermaService;
|
this.confermaService = confermaService;
|
||||||
this.confermaRepository = confermaRepository;
|
this.confermaRepository = confermaRepository;
|
||||||
this.confermaQueryService = confermaQueryService;
|
this.confermaQueryService = confermaQueryService;
|
||||||
|
this.userService = userService;
|
||||||
|
this.userMapper = userMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,11 +77,18 @@ public class ConfermaResource {
|
|||||||
* @throws URISyntaxException if the Location URI syntax is incorrect.
|
* @throws URISyntaxException if the Location URI syntax is incorrect.
|
||||||
*/
|
*/
|
||||||
@PostMapping("")
|
@PostMapping("")
|
||||||
public ResponseEntity<ConfermaDTO> createConferma(@RequestBody ConfermaDTO confermaDTO) throws URISyntaxException {
|
public ResponseEntity<ConfermaDTO> createConferma(@RequestBody ConfermaDTO confermaDTO, @AuthenticationPrincipal UserDetails principal)
|
||||||
|
throws URISyntaxException {
|
||||||
LOG.debug("REST request to save Conferma : {}", confermaDTO);
|
LOG.debug("REST request to save Conferma : {}", confermaDTO);
|
||||||
if (confermaDTO.getId() != null) {
|
/*if (confermaDTO.getId() != null) {
|
||||||
throw new BadRequestAlertException("A new conferma cannot already have an ID", ENTITY_NAME, "idexists");
|
throw new BadRequestAlertException("A new conferma cannot already have an ID", ENTITY_NAME, "idexists");
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
String currentLogin = principal.getUsername();
|
||||||
|
User currentUser = userService.getUserWithAuthoritiesByLogin(currentLogin).orElseThrow();
|
||||||
|
UtenteAppDTO utenteAppDTO = new UtenteAppDTO();
|
||||||
|
utenteAppDTO.setInternalUser(userMapper.userToUserDTO(currentUser));
|
||||||
|
confermaDTO.setConfermataDa(utenteAppDTO);
|
||||||
confermaDTO = confermaService.save(confermaDTO);
|
confermaDTO = confermaService.save(confermaDTO);
|
||||||
return ResponseEntity.created(new URI("/api/confermas/" + confermaDTO.getId()))
|
return ResponseEntity.created(new URI("/api/confermas/" + confermaDTO.getId()))
|
||||||
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, confermaDTO.getId().toString()))
|
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, confermaDTO.getId().toString()))
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
package it.sw.pa.comune.artegna.web.rest;
|
package it.sw.pa.comune.artegna.web.rest;
|
||||||
|
|
||||||
|
import it.sw.pa.comune.artegna.domain.User;
|
||||||
import it.sw.pa.comune.artegna.repository.PrenotazioneRepository;
|
import it.sw.pa.comune.artegna.repository.PrenotazioneRepository;
|
||||||
|
import it.sw.pa.comune.artegna.security.AuthoritiesConstants;
|
||||||
import it.sw.pa.comune.artegna.service.PrenotazioneQueryService;
|
import it.sw.pa.comune.artegna.service.PrenotazioneQueryService;
|
||||||
import it.sw.pa.comune.artegna.service.PrenotazioneService;
|
import it.sw.pa.comune.artegna.service.PrenotazioneService;
|
||||||
|
import it.sw.pa.comune.artegna.service.UserService;
|
||||||
|
import it.sw.pa.comune.artegna.service.UtenteAppService;
|
||||||
import it.sw.pa.comune.artegna.service.criteria.PrenotazioneCriteria;
|
import it.sw.pa.comune.artegna.service.criteria.PrenotazioneCriteria;
|
||||||
import it.sw.pa.comune.artegna.service.dto.PrenotazioneDTO;
|
import it.sw.pa.comune.artegna.service.dto.PrenotazioneDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.dto.UserDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
||||||
import it.sw.pa.comune.artegna.web.rest.errors.BadRequestAlertException;
|
import it.sw.pa.comune.artegna.web.rest.errors.BadRequestAlertException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
@@ -18,8 +24,11 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||||
|
import tech.jhipster.service.filter.LongFilter;
|
||||||
import tech.jhipster.web.util.HeaderUtil;
|
import tech.jhipster.web.util.HeaderUtil;
|
||||||
import tech.jhipster.web.util.PaginationUtil;
|
import tech.jhipster.web.util.PaginationUtil;
|
||||||
import tech.jhipster.web.util.ResponseUtil;
|
import tech.jhipster.web.util.ResponseUtil;
|
||||||
@@ -44,14 +53,21 @@ public class PrenotazioneResource {
|
|||||||
|
|
||||||
private final PrenotazioneQueryService prenotazioneQueryService;
|
private final PrenotazioneQueryService prenotazioneQueryService;
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
private final UtenteAppService utenteAppService;
|
||||||
|
|
||||||
public PrenotazioneResource(
|
public PrenotazioneResource(
|
||||||
PrenotazioneService prenotazioneService,
|
PrenotazioneService prenotazioneService,
|
||||||
PrenotazioneRepository prenotazioneRepository,
|
PrenotazioneRepository prenotazioneRepository,
|
||||||
PrenotazioneQueryService prenotazioneQueryService
|
PrenotazioneQueryService prenotazioneQueryService,
|
||||||
|
UserService userService,
|
||||||
|
UtenteAppService utenteAppService
|
||||||
) {
|
) {
|
||||||
this.prenotazioneService = prenotazioneService;
|
this.prenotazioneService = prenotazioneService;
|
||||||
this.prenotazioneRepository = prenotazioneRepository;
|
this.prenotazioneRepository = prenotazioneRepository;
|
||||||
this.prenotazioneQueryService = prenotazioneQueryService;
|
this.prenotazioneQueryService = prenotazioneQueryService;
|
||||||
|
this.userService = userService;
|
||||||
|
this.utenteAppService = utenteAppService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -152,13 +168,26 @@ public class PrenotazioneResource {
|
|||||||
@GetMapping("")
|
@GetMapping("")
|
||||||
public ResponseEntity<List<PrenotazioneDTO>> getAllPrenotaziones(
|
public ResponseEntity<List<PrenotazioneDTO>> getAllPrenotaziones(
|
||||||
PrenotazioneCriteria criteria,
|
PrenotazioneCriteria criteria,
|
||||||
@org.springdoc.core.annotations.ParameterObject Pageable pageable
|
@org.springdoc.core.annotations.ParameterObject Pageable pageable,
|
||||||
|
@AuthenticationPrincipal UserDetails principal
|
||||||
) {
|
) {
|
||||||
LOG.debug("REST request to get Prenotaziones by criteria: {}", criteria);
|
LOG.debug("REST request to get Prenotaziones by criteria: {}", criteria);
|
||||||
|
|
||||||
Page<PrenotazioneDTO> page = prenotazioneQueryService.findByCriteria(criteria, pageable);
|
String currentUser = principal.getUsername();
|
||||||
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
|
User user = userService.getUserWithAuthoritiesByLogin(currentUser).orElseThrow();
|
||||||
return ResponseEntity.ok().headers(headers).body(page.getContent());
|
|
||||||
|
// switch among user authorities
|
||||||
|
return switch (user.getAuthorities().stream().findFirst().orElseThrow().getName()) {
|
||||||
|
case AuthoritiesConstants.INCARICATO, AuthoritiesConstants.ADMIN -> ResponseEntity.ok().body(
|
||||||
|
prenotazioneQueryService.findByCriteria(criteria, pageable).getContent()
|
||||||
|
);
|
||||||
|
default -> {
|
||||||
|
UtenteAppDTO utenteAppDTO = utenteAppService.fetchUtenteAppFromUser();
|
||||||
|
criteria.setUtenteId(new LongFilter());
|
||||||
|
criteria.getUtenteId().setEquals(utenteAppDTO.getId());
|
||||||
|
yield ResponseEntity.ok().body(prenotazioneQueryService.findByCriteria(criteria, pageable).getContent());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package it.sw.pa.comune.artegna.web.rest;
|
package it.sw.pa.comune.artegna.web.rest;
|
||||||
|
|
||||||
|
import it.sw.pa.comune.artegna.domain.User;
|
||||||
import it.sw.pa.comune.artegna.repository.UtenteAppRepository;
|
import it.sw.pa.comune.artegna.repository.UtenteAppRepository;
|
||||||
import it.sw.pa.comune.artegna.security.SecurityUtils;
|
import it.sw.pa.comune.artegna.security.SecurityUtils;
|
||||||
|
import it.sw.pa.comune.artegna.service.UserService;
|
||||||
import it.sw.pa.comune.artegna.service.UtenteAppService;
|
import it.sw.pa.comune.artegna.service.UtenteAppService;
|
||||||
|
import it.sw.pa.comune.artegna.service.dto.UserDTO;
|
||||||
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
import it.sw.pa.comune.artegna.service.dto.UtenteAppDTO;
|
||||||
|
import it.sw.pa.comune.artegna.service.mapper.UserMapper;
|
||||||
import it.sw.pa.comune.artegna.web.rest.errors.BadRequestAlertException;
|
import it.sw.pa.comune.artegna.web.rest.errors.BadRequestAlertException;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@@ -16,6 +20,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import tech.jhipster.web.util.HeaderUtil;
|
import tech.jhipster.web.util.HeaderUtil;
|
||||||
import tech.jhipster.web.util.ResponseUtil;
|
import tech.jhipster.web.util.ResponseUtil;
|
||||||
@@ -38,9 +44,20 @@ public class UtenteAppResource {
|
|||||||
|
|
||||||
private final UtenteAppRepository utenteAppRepository;
|
private final UtenteAppRepository utenteAppRepository;
|
||||||
|
|
||||||
public UtenteAppResource(UtenteAppService utenteAppService, UtenteAppRepository utenteAppRepository) {
|
private final UserService userService;
|
||||||
|
|
||||||
|
private final UserMapper userMapper;
|
||||||
|
|
||||||
|
public UtenteAppResource(
|
||||||
|
UtenteAppService utenteAppService,
|
||||||
|
UtenteAppRepository utenteAppRepository,
|
||||||
|
UserService userService,
|
||||||
|
UserMapper userMapper
|
||||||
|
) {
|
||||||
this.utenteAppService = utenteAppService;
|
this.utenteAppService = utenteAppService;
|
||||||
this.utenteAppRepository = utenteAppRepository;
|
this.utenteAppRepository = utenteAppRepository;
|
||||||
|
this.userService = userService;
|
||||||
|
this.userMapper = userMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,11 +68,15 @@ public class UtenteAppResource {
|
|||||||
* @throws URISyntaxException if the Location URI syntax is incorrect.
|
* @throws URISyntaxException if the Location URI syntax is incorrect.
|
||||||
*/
|
*/
|
||||||
@PostMapping("")
|
@PostMapping("")
|
||||||
public ResponseEntity<UtenteAppDTO> createUtenteApp(@Valid @RequestBody UtenteAppDTO utenteAppDTO) throws URISyntaxException {
|
public ResponseEntity<UtenteAppDTO> createUtenteApp(
|
||||||
|
@Valid @RequestBody UtenteAppDTO utenteAppDTO,
|
||||||
|
@AuthenticationPrincipal UserDetails principal
|
||||||
|
) throws URISyntaxException {
|
||||||
LOG.debug("REST request to save UtenteApp : {}", utenteAppDTO);
|
LOG.debug("REST request to save UtenteApp : {}", utenteAppDTO);
|
||||||
if (utenteAppDTO.getId() != null) {
|
if (utenteAppDTO.getId() != null) {
|
||||||
throw new BadRequestAlertException("A new utenteApp cannot already have an ID", ENTITY_NAME, "idexists");
|
throw new BadRequestAlertException("A new utenteApp cannot already have an ID", ENTITY_NAME, "idexists");
|
||||||
}
|
}
|
||||||
|
|
||||||
utenteAppDTO = utenteAppService.save(utenteAppDTO);
|
utenteAppDTO = utenteAppService.save(utenteAppDTO);
|
||||||
return ResponseEntity.created(new URI("/api/utente-apps/" + utenteAppDTO.getId()))
|
return ResponseEntity.created(new URI("/api/utente-apps/" + utenteAppDTO.getId()))
|
||||||
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, utenteAppDTO.getId().toString()))
|
.headers(HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, utenteAppDTO.getId().toString()))
|
||||||
@@ -176,7 +197,10 @@ public class UtenteAppResource {
|
|||||||
* @throws URISyntaxException if the Location URI syntax is incorrect.
|
* @throws URISyntaxException if the Location URI syntax is incorrect.
|
||||||
*/
|
*/
|
||||||
@PostMapping("/current")
|
@PostMapping("/current")
|
||||||
public ResponseEntity<UtenteAppDTO> saveCurrentUserProfile(@Valid @RequestBody UtenteAppDTO utenteAppDTO) throws URISyntaxException {
|
public ResponseEntity<UtenteAppDTO> saveCurrentUserProfile(
|
||||||
|
@Valid @RequestBody UtenteAppDTO utenteAppDTO,
|
||||||
|
@AuthenticationPrincipal UserDetails principal
|
||||||
|
) throws URISyntaxException {
|
||||||
LOG.debug("REST request to save current user profile : {}", utenteAppDTO);
|
LOG.debug("REST request to save current user profile : {}", utenteAppDTO);
|
||||||
|
|
||||||
String currentUserLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() ->
|
String currentUserLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() ->
|
||||||
@@ -191,6 +215,10 @@ public class UtenteAppResource {
|
|||||||
// Update existing profile
|
// Update existing profile
|
||||||
result = utenteAppService.update(utenteAppDTO);
|
result = utenteAppService.update(utenteAppDTO);
|
||||||
} else {
|
} else {
|
||||||
|
// collect current user login infos
|
||||||
|
String currentLogin = principal.getUsername();
|
||||||
|
User currentUser = userService.getUserWithAuthoritiesByLogin(currentLogin).orElseThrow();
|
||||||
|
utenteAppDTO.setInternalUser(userMapper.userToUserDTO(currentUser));
|
||||||
// Create new profile
|
// Create new profile
|
||||||
result = utenteAppService.save(utenteAppDTO);
|
result = utenteAppService.save(utenteAppDTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,16 @@ spring:
|
|||||||
# Remove 'faker' if you do not want the sample data to be loaded automatically
|
# Remove 'faker' if you do not want the sample data to be loaded automatically
|
||||||
contexts: dev, faker
|
contexts: dev, faker
|
||||||
mail:
|
mail:
|
||||||
host: localhost
|
host: mail-eu.smtp2go.com
|
||||||
port: 25
|
port: 587
|
||||||
username:
|
username: artegna
|
||||||
password:
|
password: gpTottUCcB9GKG15
|
||||||
|
protocol: smtp
|
||||||
|
properties.mail.smtp:
|
||||||
|
auth: true
|
||||||
|
starttls.enable: true
|
||||||
|
starttls.required: true
|
||||||
|
|
||||||
messages:
|
messages:
|
||||||
cache-duration: PT1S # 1 second, see the ISO 8601 standard
|
cache-duration: PT1S # 1 second, see the ISO 8601 standard
|
||||||
thymeleaf:
|
thymeleaf:
|
||||||
|
|||||||
@@ -43,10 +43,15 @@ spring:
|
|||||||
liquibase:
|
liquibase:
|
||||||
contexts: prod
|
contexts: prod
|
||||||
mail:
|
mail:
|
||||||
host: localhost
|
host: mail-eu.smtp2go.com
|
||||||
port: 25
|
port: 587
|
||||||
username:
|
username: artegna
|
||||||
password:
|
password: gpTottUCcB9GKG15
|
||||||
|
protocol: smtp
|
||||||
|
properties.mail.smtp:
|
||||||
|
auth: true
|
||||||
|
starttls.enable: true
|
||||||
|
starttls.required: true
|
||||||
thymeleaf:
|
thymeleaf:
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ jhipster:
|
|||||||
# allow-credentials: true
|
# allow-credentials: true
|
||||||
# max-age: 1800
|
# max-age: 1800
|
||||||
mail:
|
mail:
|
||||||
from: smartbooking@localhost
|
from: noreply@bigc.it
|
||||||
api-docs:
|
api-docs:
|
||||||
default-include-pattern: /api/**
|
default-include-pattern: /api/**
|
||||||
management-include-pattern: /management/**
|
management-include-pattern: /management/**
|
||||||
@@ -222,3 +222,8 @@ jhipster:
|
|||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
# application:
|
# application:
|
||||||
|
# Twilio configuration
|
||||||
|
twilio:
|
||||||
|
accountSid: 'AC0ea64cd2bb43c6ed76e9acdf8087afa7'
|
||||||
|
authToken: 'cfd2943e70ce09b07ae75f3f1650ccb4'
|
||||||
|
phoneNumber: YOUR_PHONE_NUMBER
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
name
|
name
|
||||||
ROLE_ADMIN
|
ROLE_ADMIN
|
||||||
ROLE_USER
|
ROLE_USER
|
||||||
|
ROLE_INCARICATO
|
||||||
|
|||||||
|
@@ -139,11 +139,11 @@
|
|||||||
<button type="submit" :disabled="v$.$invalid" class="btn btn-primary" data-cy="submit">{{ t$('register.form.button') }}</button>
|
<button type="submit" :disabled="v$.$invalid" class="btn btn-primary" data-cy="submit">{{ t$('register.form.button') }}</button>
|
||||||
</form>
|
</form>
|
||||||
<p></p>
|
<p></p>
|
||||||
<div class="alert alert-warning">
|
<!--div class="alert alert-warning">
|
||||||
<span>{{ t$('global.messages.info.authenticated.prefix') }}</span>
|
<span>{{ t$('global.messages.info.authenticated.prefix') }}</span>
|
||||||
<a class="alert-link" @click="showLogin()">{{ t$('global.messages.info.authenticated.link') }}</a
|
<a class="alert-link" @click="showLogin()">{{ t$('global.messages.info.authenticated.link') }}</a
|
||||||
><span v-html="t$('global.messages.info.authenticated.suffix')"></span>
|
><span v-html="t$('global.messages.info.authenticated.suffix')"></span>
|
||||||
</div>
|
</div-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default defineComponent({
|
|||||||
const { showLogin } = useLoginModal();
|
const { showLogin } = useLoginModal();
|
||||||
const authenticated = inject<ComputedRef<boolean>>('authenticated');
|
const authenticated = inject<ComputedRef<boolean>>('authenticated');
|
||||||
const username = inject<ComputedRef<string>>('currentUsername');
|
const username = inject<ComputedRef<string>>('currentUsername');
|
||||||
const utenteAppService = inject<UtenteAppService>('utenteAppService', () => new UtenteAppService());
|
const utenteAppService = inject<UtenteAppService>('utenteAppService', () => new UtenteAppService(), true);
|
||||||
|
|
||||||
const profileIncomplete: Ref<boolean> = ref(false);
|
const profileIncomplete: Ref<boolean> = ref(false);
|
||||||
const checkingProfile: Ref<boolean> = ref(false);
|
const checkingProfile: Ref<boolean> = ref(false);
|
||||||
@@ -23,7 +23,7 @@ export default defineComponent({
|
|||||||
try {
|
try {
|
||||||
checkingProfile.value = true;
|
checkingProfile.value = true;
|
||||||
const utenteApp = await utenteAppService.getCurrentUser();
|
const utenteApp = await utenteAppService.getCurrentUser();
|
||||||
|
console.log('utenteApp', utenteApp);
|
||||||
// Check if essential profile fields are missing
|
// Check if essential profile fields are missing
|
||||||
if (
|
if (
|
||||||
!utenteApp ||
|
!utenteApp ||
|
||||||
|
|||||||
@@ -11,18 +11,21 @@
|
|||||||
<div class="alert alert-success" v-if="authenticated">
|
<div class="alert alert-success" v-if="authenticated">
|
||||||
<span v-if="username">{{ t$('home.logged.message', { username }) }}</span>
|
<span v-if="username">{{ t$('home.logged.message', { username }) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="btn btn-primary jh-create-entity create-prenotazione" v-if="authenticated && !profileIncomplete && !checkingProfile">
|
||||||
|
<router-link to="/prenotazione">{{ t$('home.prenotazioni') }}</router-link>
|
||||||
|
</button>
|
||||||
<div class="alert alert-warning" v-if="authenticated && profileIncomplete && !checkingProfile">
|
<div class="alert alert-warning" v-if="authenticated && profileIncomplete && !checkingProfile">
|
||||||
<span>{{ t$('home.profile.incomplete.message') }}</span>
|
<span>{{ t$('home.profile.incomplete.message') }}</span>
|
||||||
|
<div>
|
||||||
<router-link class="alert-link" to="/account/profile">{{ t$('home.profile.incomplete.link') }}</router-link>
|
<router-link class="alert-link" to="/account/profile">{{ t$('home.profile.incomplete.link') }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-warning" v-if="!authenticated">
|
<!--div class="alert alert-warning" v-if="!authenticated">
|
||||||
<span>{{ t$('global.messages.info.authenticated.prefix') }}</span>
|
<span>{{ t$('global.messages.info.authenticated.prefix') }}</span>
|
||||||
<a class="alert-link" @click="showLogin()">{{ t$('global.messages.info.authenticated.link') }}</a
|
<a class="alert-link" @click="showLogin()">{{ t$('global.messages.info.authenticated.link') }}</a
|
||||||
><span v-html="t$('global.messages.info.authenticated.suffix')"></span>
|
><span v-html="t$('global.messages.info.authenticated.suffix')"></span>
|
||||||
</div>
|
</div-->
|
||||||
<div class="alert alert-warning" v-if="!authenticated">
|
<div class="alert alert-warning" v-if="!authenticated">
|
||||||
<span>{{ t$('global.messages.info.register.noaccount') }}</span
|
<span>{{ t$('global.messages.info.register.noaccount') }}</span
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -125,8 +125,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<span ref="infiniteScrollEl"></span>
|
|
||||||
</table>
|
</table>
|
||||||
|
<span ref="infiniteScrollEl"></span>
|
||||||
</div>
|
</div>
|
||||||
<b-modal ref="removeEntity" id="removeEntity">
|
<b-modal ref="removeEntity" id="removeEntity">
|
||||||
<template #title>
|
<template #title>
|
||||||
|
|||||||
@@ -311,7 +311,7 @@
|
|||||||
class="btn btn-sm btn-outline-primary"
|
class="btn btn-sm btn-outline-primary"
|
||||||
>
|
>
|
||||||
<font-awesome-icon icon="download"></font-awesome-icon>
|
<font-awesome-icon icon="download"></font-awesome-icon>
|
||||||
{{ t$('entity.action.download') }}
|
{{ t$('smartbookingApp.modelloLiberatoria.download') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,37 @@
|
|||||||
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
|
import { type ComputedRef, 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';
|
||||||
|
|
||||||
|
import UtenteAppService from '@/entities/utente-app/utente-app.service';
|
||||||
|
import account from '@/router/account.ts';
|
||||||
|
import type { IUtenteApp } from '@/shared/model/utente-app.model.ts';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const baseApiUrl = 'api/utente-apps';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Prenotazione',
|
name: 'Prenotazione',
|
||||||
setup() {
|
setup() {
|
||||||
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 authenticated = inject<ComputedRef<boolean>>('authenticated');
|
||||||
|
const utenteAppService = inject<UtenteAppService>('utenteAppService', () => new UtenteAppService(), true);
|
||||||
|
|
||||||
const itemsPerPage = ref(20);
|
const itemsPerPage = ref(20);
|
||||||
const queryCount: Ref<number> = ref(null);
|
const queryCount: Ref<number> = ref(null);
|
||||||
@@ -23,9 +41,76 @@ 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);
|
||||||
|
|
||||||
|
// CONTROLLIAMO SE L'UTENTE HA UN PROFILO IMPOSTATO+
|
||||||
|
const profileIncomplete: Ref<boolean> = ref(false);
|
||||||
|
const checkingProfile: Ref<boolean> = ref(false);
|
||||||
|
|
||||||
|
const getCurrentUser = async () => {
|
||||||
|
return new Promise<IUtenteApp>((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.get(`${baseApiUrl}/current`)
|
||||||
|
.then(res => {
|
||||||
|
resolve(res.data);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkProfileCompletion = async () => {
|
||||||
|
if (!authenticated.value) {
|
||||||
|
profileIncomplete.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
checkingProfile.value = true;
|
||||||
|
const utenteApp = await getCurrentUser();
|
||||||
|
// Check if essential profile fields are missing
|
||||||
|
if (
|
||||||
|
!utenteApp ||
|
||||||
|
!utenteApp.nome ||
|
||||||
|
!utenteApp.cognome ||
|
||||||
|
!utenteApp.dataNascita ||
|
||||||
|
!utenteApp.luogoNascita ||
|
||||||
|
!utenteApp.residente ||
|
||||||
|
!utenteApp.telefono
|
||||||
|
) {
|
||||||
|
profileIncomplete.value = true;
|
||||||
|
} else {
|
||||||
|
console.log('Profile is complete');
|
||||||
|
profileIncomplete.value = false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// If UtenteApp doesn't exist, profile is incomplete
|
||||||
|
profileIncomplete.value = true;
|
||||||
|
} finally {
|
||||||
|
checkingProfile.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHIUDIAMO IL CONTROLLO DEL PROFILO IMPOSTATO
|
||||||
|
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
page.value = 1;
|
page.value = 1;
|
||||||
};
|
};
|
||||||
@@ -63,6 +148,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await retrievePrenotaziones();
|
await retrievePrenotaziones();
|
||||||
|
await checkProfileCompletion();
|
||||||
});
|
});
|
||||||
|
|
||||||
const removeId: Ref<number> = ref(null);
|
const removeId: Ref<number> = ref(null);
|
||||||
@@ -87,6 +173,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,22 +213,22 @@ 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();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(page, async () => {
|
||||||
|
await checkProfileCompletion();
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prenotaziones,
|
prenotaziones,
|
||||||
handleSyncList,
|
handleSyncList,
|
||||||
@@ -132,6 +249,22 @@ export default defineComponent({
|
|||||||
totalItems,
|
totalItems,
|
||||||
changeOrder,
|
changeOrder,
|
||||||
t$,
|
t$,
|
||||||
|
authenticated,
|
||||||
|
profileIncomplete,
|
||||||
|
checkingProfile,
|
||||||
|
checkProfileCompletion,
|
||||||
|
// Role-based
|
||||||
|
isIncaricato,
|
||||||
|
prenotazioniPendenti,
|
||||||
|
prenotazioniCompletate,
|
||||||
|
// Prendi in carico modal
|
||||||
|
showPrendiInCaricoModal,
|
||||||
|
selectedPrenotazione,
|
||||||
|
confermaForm,
|
||||||
|
isSubmittingConferma,
|
||||||
|
prendiInCarico,
|
||||||
|
closePrendiInCaricoModal,
|
||||||
|
submitConferma,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<!-- ============================= ROLE_USER VIEW ============================= -->
|
||||||
|
<template v-if="!isIncaricato">
|
||||||
|
<div class="alert alert-warning" v-if="authenticated && profileIncomplete && !checkingProfile">
|
||||||
|
<span>{{ t$('home.profile.incomplete.message') }}</span>
|
||||||
|
<div>
|
||||||
|
<router-link class="alert-link" to="/account/profile">{{ t$('home.profile.incomplete.link') }}</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="authenticated && !profileIncomplete && !checkingProfile">
|
||||||
<h2 id="page-heading" data-cy="PrenotazioneHeading">
|
<h2 id="page-heading" data-cy="PrenotazioneHeading">
|
||||||
<span id="prenotazione">{{ t$('smartbookingApp.prenotazione.home.title') }}</span>
|
<span id="prenotazione">{{ t$('smartbookingApp.prenotazione.home.title') }}</span>
|
||||||
<div class="d-flex justify-content-end">
|
<div class="d-flex justify-content-end">
|
||||||
@@ -7,7 +16,7 @@
|
|||||||
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
|
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.home.refreshListLabel') }}</span>
|
<span>{{ t$('smartbookingApp.prenotazione.home.refreshListLabel') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<router-link :to="{ name: 'PrenotazioneCreate' }" custom v-slot="{ navigate }">
|
<router-link :to="{ name: 'PrenotazioneNuova' }" custom v-slot="{ navigate }">
|
||||||
<button
|
<button
|
||||||
@click="navigate"
|
@click="navigate"
|
||||||
id="jh-create-entity"
|
id="jh-create-entity"
|
||||||
@@ -44,30 +53,14 @@
|
|||||||
<span>{{ t$('smartbookingApp.prenotazione.stato') }}</span>
|
<span>{{ t$('smartbookingApp.prenotazione.stato') }}</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="'stato'"></jhi-sort-indicator>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" @click="changeOrder('motivoEvento')">
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</span>
|
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'motivoEvento'"></jhi-sort-indicator>
|
|
||||||
</th>
|
|
||||||
<th scope="col" @click="changeOrder('numeroPartecipanti')">
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.numeroPartecipanti') }}</span>
|
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'numeroPartecipanti'"></jhi-sort-indicator>
|
|
||||||
</th>
|
|
||||||
<th scope="col" @click="changeOrder('noteUtente')">
|
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.noteUtente') }}</span>
|
|
||||||
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'noteUtente'"></jhi-sort-indicator>
|
|
||||||
</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')">
|
<th scope="col" @click="changeOrder('struttura.nome')">
|
||||||
<span>{{ t$('smartbookingApp.prenotazione.struttura') }}</span>
|
<span>{{ t$('smartbookingApp.prenotazione.struttura') }}</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="'struttura.nome'"></jhi-sort-indicator>
|
||||||
</th>
|
</th>
|
||||||
|
<th scope="col" @click="changeOrder('motivoEvento')">
|
||||||
|
<span>{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</span>
|
||||||
|
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'motivoEvento'"></jhi-sort-indicator>
|
||||||
|
</th>
|
||||||
<th scope="col"></th>
|
<th scope="col"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -81,30 +74,10 @@
|
|||||||
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
|
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
|
||||||
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
|
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
|
||||||
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
|
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
|
||||||
|
<td>
|
||||||
|
<div v-if="prenotazione.struttura">{{ prenotazione.struttura.nome }}</div>
|
||||||
|
</td>
|
||||||
<td>{{ prenotazione.motivoEvento }}</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>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div v-if="prenotazione.utente">
|
|
||||||
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: prenotazione.utente.id } }">{{
|
|
||||||
prenotazione.utente.username
|
|
||||||
}}</router-link>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div v-if="prenotazione.struttura">
|
|
||||||
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: prenotazione.struttura.id } }">{{
|
|
||||||
prenotazione.struttura.nome
|
|
||||||
}}</router-link>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<router-link
|
<router-link
|
||||||
@@ -115,6 +88,18 @@
|
|||||||
<font-awesome-icon icon="eye"></font-awesome-icon>
|
<font-awesome-icon icon="eye"></font-awesome-icon>
|
||||||
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
|
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<!-- Show conferma link when conferma exists -->
|
||||||
|
<router-link
|
||||||
|
v-if="prenotazione.conferma"
|
||||||
|
: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>
|
||||||
|
<!-- Edit and Delete only when no conferma -->
|
||||||
|
<template v-if="!prenotazione.conferma">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'PrenotazioneEdit', params: { prenotazioneId: prenotazione.id } }"
|
:to="{ name: 'PrenotazioneEdit', params: { prenotazioneId: prenotazione.id } }"
|
||||||
class="btn btn-primary btn-sm edit"
|
class="btn btn-primary btn-sm edit"
|
||||||
@@ -133,6 +118,7 @@
|
|||||||
<font-awesome-icon icon="times"></font-awesome-icon>
|
<font-awesome-icon icon="times"></font-awesome-icon>
|
||||||
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
|
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
|
||||||
</b-button>
|
</b-button>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -172,6 +158,207 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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
|
||||||
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
:disabled="!confermaForm.tipoConferma || isSubmittingConferma"
|
||||||
|
@click="submitConferma"
|
||||||
|
>
|
||||||
|
<span v-if="isSubmittingConferma">
|
||||||
|
<b-spinner small></b-spinner>
|
||||||
|
</span>
|
||||||
|
{{ t$('smartbookingApp.prenotazione.prendiInCarico.submit') }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</b-modal>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" src="./prenotazione.component.ts"></script>
|
<script lang="ts" src="./prenotazione.component.ts"></script>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { faEye } from '@fortawesome/free-solid-svg-icons/faEye';
|
|||||||
import { faFlag } from '@fortawesome/free-solid-svg-icons/faFlag';
|
import { faFlag } from '@fortawesome/free-solid-svg-icons/faFlag';
|
||||||
import { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart';
|
import { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart';
|
||||||
import { faHome } from '@fortawesome/free-solid-svg-icons/faHome';
|
import { faHome } from '@fortawesome/free-solid-svg-icons/faHome';
|
||||||
|
import { faIdCard } from '@fortawesome/free-solid-svg-icons/faIdCard';
|
||||||
import { faList } from '@fortawesome/free-solid-svg-icons/faList';
|
import { faList } from '@fortawesome/free-solid-svg-icons/faList';
|
||||||
import { faLock } from '@fortawesome/free-solid-svg-icons/faLock';
|
import { faLock } from '@fortawesome/free-solid-svg-icons/faLock';
|
||||||
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons/faPencilAlt';
|
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons/faPencilAlt';
|
||||||
@@ -69,6 +70,7 @@ export function initFortAwesome(vue: App) {
|
|||||||
faFlag,
|
faFlag,
|
||||||
faHeart,
|
faHeart,
|
||||||
faHome,
|
faHome,
|
||||||
|
faIdCard,
|
||||||
faList,
|
faList,
|
||||||
faLock,
|
faLock,
|
||||||
faPencilAlt,
|
faPencilAlt,
|
||||||
|
|||||||
BIN
src/main/webapp/content/images/artegna.png
Normal file
BIN
src/main/webapp/content/images/artegna.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
@@ -61,7 +61,7 @@ Main page styles
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 347px;
|
width: 347px;
|
||||||
height: 497px;
|
height: 497px;
|
||||||
background: url('/content/images/jhipster_family_member_0.svg') no-repeat center top;
|
background: url('/content/images/artegna.png') no-repeat center top;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ Main page styles
|
|||||||
only screen and (min-resolution: 192dpi),
|
only screen and (min-resolution: 192dpi),
|
||||||
only screen and (min-resolution: 2dppx) {
|
only screen and (min-resolution: 2dppx) {
|
||||||
.hipster {
|
.hipster {
|
||||||
background: url('/content/images/jhipster_family_member_0.svg') no-repeat center top;
|
background: url('/content/images/artegna.png') no-repeat center top;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"home": {
|
"home": {
|
||||||
"title": "Benvenuto, Java Hipster!",
|
"title": "Benvenuto!",
|
||||||
"subtitle": "Questa è la tua home page",
|
"subtitle": "Questa è l'home page del sistema smARTbooking.",
|
||||||
"logged": {
|
"logged": {
|
||||||
"message": "Autenticato come \"{ username }\"."
|
"message": "Autenticato come \"{ username }\"."
|
||||||
},
|
},
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"link": "Completa il profilo"
|
"link": "Completa il profilo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"question": "In caso di domande su JHipster:",
|
"question": "Cosa è possibile fare con smARTbooking:",
|
||||||
"link": {
|
"link": {
|
||||||
"homepage": "Homepage JHipster",
|
"homepage": "Homepage JHipster",
|
||||||
"stackoverflow": "JHipster su Stack Overflow",
|
"stackoverflow": "JHipster su Stack Overflow",
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
"follow": "segui {'@'}jhipster su Twitter"
|
"follow": "segui {'@'}jhipster su Twitter"
|
||||||
},
|
},
|
||||||
"like": "Se ti piace JHipster, non dimenticarti di darci una stella su",
|
"like": "Se ti piace JHipster, non dimenticarti di darci una stella su",
|
||||||
"github": "GitHub"
|
"github": "GitHub",
|
||||||
|
"prenotazioni": "Vai alle tue prenotazioni"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"nome": "Nome",
|
"nome": "Nome",
|
||||||
"testo": "Testo",
|
"testo": "Testo",
|
||||||
"documento": "Documento",
|
"documento": "Documento",
|
||||||
|
"download": "Download documento",
|
||||||
"validoDal": "Valido Dal",
|
"validoDal": "Valido Dal",
|
||||||
"validoAl": "Valido Al",
|
"validoAl": "Valido Al",
|
||||||
"struttura": "Struttura"
|
"struttura": "Struttura"
|
||||||
|
|||||||
@@ -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