diff --git a/src/app/app.config.ts b/src/app/app.config.ts index ccd7d8fc..339f1a0f 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -3,7 +3,7 @@ import { provideRouter } from '@angular/router'; import { routes } from './routes'; -import { fr_FR, provideNzI18n } from 'ng-zorro-antd/i18n'; +import { fr_FR, provideNzI18n, NZ_DATE_CONFIG } from 'ng-zorro-antd/i18n'; import { registerLocaleData } from '@angular/common'; import fr from '@angular/common/locales/fr'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; @@ -17,6 +17,7 @@ export const appConfig: ApplicationConfig = { provideBrowserGlobalErrorListeners(), provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideNzI18n(fr_FR), provideAnimationsAsync(), provideHttpClient(), + { provide: NZ_DATE_CONFIG, useValue: { firstDayOfWeek: 1 } }, provideApi('/api') ] }; diff --git a/src/app/components/pages/dashboard/dashboard.css b/src/app/components/pages/dashboard/dashboard.css index c18acc17..2d9c8c13 100644 --- a/src/app/components/pages/dashboard/dashboard.css +++ b/src/app/components/pages/dashboard/dashboard.css @@ -3,51 +3,57 @@ height: 100vh; background: #f5f4f0; overflow: hidden; + display: flex; + flex-direction: column; } .dashboard { - padding: 40px; - max-width: 900px; + padding: 10px 20px; + display: flex; + align-items: center; + gap: 16px; + background: #fff; + border-bottom: 1px solid #ede8e0; + flex-shrink: 0; } .dashboard-title { - font-size: 1.6rem; - font-weight: 600; - color: #2c2c2c; - margin-bottom: 32px; + font-size: 0.8rem; + font-weight: 700; + color: #aaa; + text-transform: uppercase; + letter-spacing: 1px; + margin: 0; + white-space: nowrap; } .dashboard-cards { display: flex; - flex-wrap: wrap; - gap: 16px; + gap: 8px; } .dashboard-card { display: flex; align-items: center; - gap: 16px; - padding: 20px 24px; - background: #fff; - border: 1px solid #ede8e0; - border-radius: 10px; + gap: 8px; + padding: 6px 14px; + background: #fdf6ed; + border: 1.5px solid #ede8e0; + border-radius: 20px; text-decoration: none; color: inherit; - min-width: 280px; - transition: box-shadow 0.15s ease, border-color 0.15s ease; + transition: border-color 0.15s ease, background 0.15s ease; cursor: pointer; } .dashboard-card:hover { border-color: #d4a574; - box-shadow: 0 4px 16px rgba(212, 165, 116, 0.15); + background: #faf0e4; } .card-icon { - width: 48px; - height: 48px; - background: #fdf6ed; - border-radius: 10px; + width: 20px; + height: 20px; display: flex; align-items: center; justify-content: center; @@ -55,29 +61,24 @@ flex-shrink: 0; } -.card-content { - flex: 1; -} - .card-content h2 { - font-size: 1rem; + font-size: 0.82rem; font-weight: 600; color: #2c2c2c; - margin: 0 0 4px; -} - -.card-content p { - font-size: 0.82rem; - color: #888; margin: 0; } -.card-arrow { - color: #ccc; - flex-shrink: 0; - transition: color 0.15s ease; +.card-content p { + display: none; } -.dashboard-card:hover .card-arrow { - color: #d4a574; +.card-arrow { + display: none; +} + +.outlet-wrapper { + flex: 1; + overflow: hidden; + display: flex; + flex-direction: column; } diff --git a/src/app/components/pages/dashboard/dashboard.html b/src/app/components/pages/dashboard/dashboard.html index f0763d9e..42acdf3c 100644 --- a/src/app/components/pages/dashboard/dashboard.html +++ b/src/app/components/pages/dashboard/dashboard.html @@ -4,7 +4,7 @@
- + @@ -13,13 +13,11 @@

Planning

-

Grille hebdomadaire des spectacles et camions

- - -
- +
+ +
diff --git a/src/app/components/pages/planning/planning.css b/src/app/components/pages/planning/planning.css index ab72bdef..229c75f5 100644 --- a/src/app/components/pages/planning/planning.css +++ b/src/app/components/pages/planning/planning.css @@ -1,7 +1,14 @@ /* ── Layout général ─────────────────────────────────────── */ +:host { + display: flex; + flex: 1; + overflow: hidden; + min-height: 0; +} + .background { width: 100%; - height: 100vh; + height: 100%; background: #f5f4f0; overflow: hidden; display: flex; @@ -135,6 +142,28 @@ color: #fff; } +.new-show-btn { + display: flex; + align-items: center; + gap: 6px; + padding: 7px 16px; + background: linear-gradient(135deg, #d4a574, #c49563); + border: none; + border-radius: 20px; + font-size: 12px; + font-family: 'Be Vietnam Pro', sans-serif; + font-weight: 700; + color: #fff; + cursor: pointer; + transition: all 0.15s; + white-space: nowrap; +} + +.new-show-btn:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(212, 165, 116, 0.4); +} + /* ── Grille semaine ─────────────────────────────────────── */ .week-calendar { flex: 1; @@ -482,12 +511,9 @@ /* ── Panneau droit — Détails ────────────────────────────── */ .details { - flex: 1; padding: 12px 14px 16px; display: flex; flex-direction: column; - overflow: hidden; - min-height: 0; } .sidebar-header { @@ -502,8 +528,6 @@ } .sidebar-content { - flex: 1; - overflow-y: auto; display: flex; flex-direction: column; gap: 10px; @@ -584,6 +608,95 @@ margin-top: 2px; } +.show-trucks-row { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-top: 7px; + align-items: center; +} + +.truck-tag { + display: flex; + align-items: center; + gap: 3px; + background: rgba(96, 93, 200, 0.1); + border: 1px solid rgba(96, 93, 200, 0.3); + border-radius: 12px; + padding: 2px 6px 2px 8px; + font-size: 10px; + font-weight: 600; + color: #605DC8; +} + +.truck-edit, .truck-remove { + border: none; + background: none; + color: #605DC8; + cursor: pointer; + padding: 0 2px; + font-size: 11px; + line-height: 1; + opacity: 0.5; + transition: opacity 0.1s; +} + +.truck-edit:hover, .truck-remove:hover { + opacity: 1; +} + +.truck-edit-card { + border: none; + background: none; + color: #605DC8; + cursor: pointer; + font-size: 13px; + opacity: 0.5; + transition: opacity 0.1s; + padding: 0; +} + +.truck-edit-card:hover { + opacity: 1; +} + +.truck-select { + border: 1px dashed #ddd; + background: transparent; + border-radius: 12px; + padding: 2px 8px; + font-size: 10px; + color: #999; + cursor: pointer; + outline: none; + font-family: 'Be Vietnam Pro', sans-serif; + transition: all 0.15s; +} + +.truck-select:hover { + border-color: #605DC8; + color: #605DC8; +} + +.truck-create-btn { + border: 1px dashed #605DC8; + background: transparent; + border-radius: 12px; + padding: 2px 8px; + font-size: 10px; + font-weight: 600; + color: #605DC8; + cursor: pointer; + font-family: 'Be Vietnam Pro', sans-serif; + transition: all 0.15s; + opacity: 0.7; +} + +.truck-create-btn:hover { + opacity: 1; + background: rgba(96, 93, 200, 0.08); +} + .sidebar-btn { display: flex; align-items: center; diff --git a/src/app/components/pages/planning/planning.html b/src/app/components/pages/planning/planning.html index 29e8bc69..3c7efdf5 100644 --- a/src/app/components/pages/planning/planning.html +++ b/src/app/components/pages/planning/planning.html @@ -39,6 +39,12 @@ +
@@ -151,6 +157,24 @@

{{ show.place }}

{{ show.description }}

+
+ @for (truck of getTrucksForShow(show.id!); track truck.id) { + + {{ truck.type }} + + + + } + @if (getAvailableTrucks().length > 0) { + + } + +
} @@ -175,7 +199,10 @@
{{ truck.type || 'Camion' }} - {{ truck.statut }} +
+ {{ truck.statut }} + +

Taille : {{ truck.sizes }}

Capacité : {{ truck.maxExplosiveCapacity }} kg

@@ -185,28 +212,6 @@ }
- @@ -282,4 +287,72 @@ + + + + +
+
+
+ + + + + + +
+
+

{{ editTruckId ? 'Modifier le camion' : 'Nouveau camion' }}

+

{{ editTruckId ? 'Modifiez les informations du camion' : 'Renseignez les informations du camion' }}

+
+
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+
+
\ No newline at end of file diff --git a/src/app/components/pages/planning/planning.ts b/src/app/components/pages/planning/planning.ts index f5b221fb..364578de 100644 --- a/src/app/components/pages/planning/planning.ts +++ b/src/app/components/pages/planning/planning.ts @@ -5,6 +5,7 @@ import {FormsModule} from '@angular/forms'; import { PyroFetesDTOShowRequestCreateShowDto, PyroFetesDTOShowResponseReadShowDto, + PyroFetesDTOTruckRequestCreateTruckDto, PyroFetesDTOTruckResponseReadTruckDto, ShowsService, TrucksService @@ -32,6 +33,11 @@ export class Planning implements OnInit, AfterViewInit { newShow: PyroFetesDTOShowRequestCreateShowDto = {}; newShowDate: Date | null = null; + isTruckModalVisible = signal(false); + newTruck: PyroFetesDTOTruckRequestCreateTruckDto = {}; + newTruckShowId: number | null = null; + editTruckId: number | null = null; + readonly slotHeight = 48; async ngOnInit() { @@ -272,6 +278,87 @@ export class Planning implements OnInit, AfterViewInit { return this.getTrucksForDay(this.selectedDay); } + getTrucksForShow(showId: number): PyroFetesDTOTruckResponseReadTruckDto[] { + return this.trucks().filter(t => t.showId === showId); + } + + getAvailableTrucks(): PyroFetesDTOTruckResponseReadTruckDto[] { + return this.trucks().filter(t => !t.showId); + } + + async assignTruck(truckId: number, showId: number): Promise { + await firstValueFrom(this.trucksService.pyroFetesEndpointsTruckUpdateTruckEndpoint( + truckId, { showId } + )); + await this.fetchTrucks(); + } + + async removeTruck(truckId: number): Promise { + await firstValueFrom(this.trucksService.pyroFetesEndpointsTruckUpdateTruckEndpoint( + truckId, { showId: 0 } + )); + await this.fetchTrucks(); + } + + async onTruckAssign(event: Event, showId: number): Promise { + const select = event.target as HTMLSelectElement; + const truckId = parseInt(select.value); + if (!truckId) return; + await this.assignTruck(truckId, showId); + select.value = ''; + } + + showTruckModal(showId: number): void { + this.editTruckId = null; + this.newTruckShowId = showId; + this.newTruck = {}; + this.isTruckModalVisible.set(true); + } + + openEditTruckModal(truck: PyroFetesDTOTruckResponseReadTruckDto): void { + this.editTruckId = truck.id ?? null; + this.newTruckShowId = truck.showId ?? null; + this.newTruck = { + type: truck.type ?? undefined, + sizes: truck.sizes ?? undefined, + maxExplosiveCapacity: truck.maxExplosiveCapacity ?? undefined, + status: truck.statut ?? undefined, + }; + this.isTruckModalVisible.set(true); + } + + async handleTruckOk(): Promise { + if (!this.newTruck.type) return; + if (this.editTruckId !== null) { + await firstValueFrom(this.trucksService.pyroFetesEndpointsTruckUpdateTruckEndpoint( + this.editTruckId, { + type: this.newTruck.type, + sizes: this.newTruck.sizes, + maxExplosiveCapacity: this.newTruck.maxExplosiveCapacity?.toString(), + statut: this.newTruck.status, + showId: this.newTruckShowId ?? undefined + } + )); + } else { + await firstValueFrom(this.trucksService.pyroFetesEndpointsTruckCreateTruckEndpoint({ + ...this.newTruck, + showId: this.newTruckShowId ?? undefined + })); + } + await this.fetchTrucks(); + this.newTruck = {}; + this.newTruckShowId = null; + this.editTruckId = null; + this.isTruckModalVisible.set(false); + } + + handleTruckCancel(): void { + this.newTruck = {}; + this.newTruckShowId = null; + this.editTruckId = null; + this.isTruckModalVisible.set(false); + } + formatSelectedDay(date: Date): string { const days = ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi']; const months = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',