Files
pyrofetes-frontend/src/app/components/pages/planning/planning.html
T
cernont ecccab90fd feat(planning): gestion des statuts automatiques, suppression de spectacles et améliorations d'affichage
- Statuts camions calculés automatiquement selon les shows assignés
- Gestion manuelle limitée aux statuts "En panne" et "En maintenance"
- Bouton pour supprimer un spectacle directement depuis la grille ou le panneau
- Ajustement de la largeur dynamique des évènements et camions dans les créneaux
- Nouveau style pour les badges de statut et indices visuels des actions
- Indications sur les statuts automatiques dans le formulaire camion
2026-06-08 12:00:53 +02:00

368 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div class="background">
<div class="planning">
<!-- ── Grille hebdomadaire ─────────────────────────────── -->
<div class="left">
<div class="week-section">
<div class="week-toolbar">
<div class="week-actions">
<button [class]="isCamionFilterActive ? 'action-btn active' : 'action-btn'"
(click)="camionFilter()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<rect x="1" y="3" width="15" height="13" rx="2" ry="2" stroke-width="2"/>
<path d="M16 8h5l3 3v5h-4" stroke-width="2"/>
<circle cx="5.5" cy="18.5" r="2.5" stroke-width="2"/>
<circle cx="18.5" cy="18.5" r="2.5" stroke-width="2"/>
</svg>
Camion
</button>
<button [class]="isShowFilterActive ? 'action-btn active' : 'action-btn'"
(click)="showFilter()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke-width="2"/>
</svg>
Show
</button>
</div>
<div class="week-nav">
<button class="nav-button-week" (click)="previousWeek()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M15 18L9 12L15 6" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<span class="week-label">Semaine {{ getWeekNumber() }}</span>
<button class="today-btn" (click)="goToToday()">Aujourd'hui</button>
<button class="nav-button-week" (click)="nextWeek()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none">
<path d="M9 18L15 12L9 6" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
<button class="new-show-btn" (click)="showModal()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 5v14M5 12h14" stroke-width="2.5" stroke-linecap="round"/>
</svg>
Nouveau spectacle
</button>
</div>
<div class="week-calendar" #weekCalendar>
<div class="week-grid">
<div class="time-column">
<div class="time-header"></div>
<div class="time-slot" *ngFor="let hour of getHours()">{{ hour }}</div>
</div>
<div class="day-column" *ngFor="let date of selectedDates">
<div class="day-header"
[class.today]="isToday(date)"
[class.selected-day]="isDaySelected(date)"
(click)="selectDay(date)">
<div class="day-name">{{ getDayName(date) }}</div>
<div class="day-date">{{ date.getDate() }}</div>
</div>
<div class="day-slots">
@if (isToday(date)) {
<div class="now-line" [style.top.px]="getNowTopPx()"></div>
}
<div class="hour-slot"
*ngFor="let hour of getHours()"
(click)="selectDay(date)">
@for (show of getShowsForSlot(date, hour); track show.id) {
<div class="show-event"
[style.top.px]="show.date ? getEventTopPx(show.date) : 0"
[style.left]="'calc(' + (show.colIndex / show.colCount * 100) + '% + 3px)'"
[style.right]="'calc(' + ((show.colCount - show.colIndex - 1) / show.colCount * 100) + '% + 3px)'">
<span class="show-event-name">{{ show.name }}</span>
<span class="show-event-time" *ngIf="show.date">{{ formatShowTime(show.date) }}</span>
</div>
}
@for (truck of getTrucksForSlot(date, hour); track truck.id) {
<div class="truck-event"
[style.top.px]="truck.showId ? 0 : 0"
[style.left]="'calc(' + (truck.colIndex / truck.colCount * 100) + '% + 3px)'"
[style.right]="'calc(' + ((truck.colCount - truck.colIndex - 1) / truck.colCount * 100) + '% + 3px)'">
<span class="truck-event-name">{{ truck.type || 'Camion' }}</span>
<span class="truck-event-statut">{{ getComputedTruckStatus(truck) }}</span>
</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ── Panneau droit ────────────────────────────────────── -->
<div class="right">
<div class="calendar-section">
<div class="calendar-title">CALENDRIER</div>
<div class="card">
<div class="calendar-header">
<button class="nav-button" (click)="previousMonth()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
<path d="M15 18L9 12L15 6" stroke="#d4a574" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<h2 class="month-title">{{ currentMonthYear }}</h2>
<button class="nav-button" (click)="nextMonth()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
<path d="M9 18L15 12L9 6" stroke="#d4a574" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
<nz-calendar
[nzFullscreen]="false"
[ngModel]="currentDate"
(nzSelectChange)="onValueChange($event)"
(nzPanelChange)="onPanelChange($event)"
[nzDateFullCell]="dateCellTemplate"
></nz-calendar>
<ng-template #dateCellTemplate let-date>
<div class="ant-picker-cell-inner" [class.in-selection]="isDateSelected(date)">
{{ date.getDate() }}
</div>
</ng-template>
</div>
</div>
<div class="details">
<div class="sidebar-header">
<h3 class="sidebar-title">
@if (selectedDay) {
{{ formatSelectedDay(selectedDay) }}
} @else {
Détails
}
</h3>
</div>
<div class="sidebar-content">
<div class="sidebar-block">
<h4>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke-width="2"/>
</svg>
Spectacles du jour
</h4>
@if (getDayShows().length === 0) {
<p class="no-items">Aucun spectacle ce jour</p>
} @else {
<div class="slot-info">
@for (show of getDayShows(); track show.id) {
<div class="show-card">
<div class="show-card-header">
<strong>{{ show.name }}</strong>
<div style="display:flex; align-items:center; gap:6px;">
<span class="show-time" *ngIf="show.date">{{ formatShowTime(show.date) }}</span>
<button class="show-delete-btn" (click)="deleteShow(show.id!)">×</button>
</div>
</div>
<p *ngIf="show.place">{{ show.place }}</p>
<p *ngIf="show.description">{{ show.description }}</p>
<div class="show-trucks-row">
@for (truck of getTrucksForShow(show.id!); track truck.id) {
<span class="truck-tag">
{{ truck.type }}
<span class="truck-tag-statut" [class]="'statut-' + getComputedTruckStatus(truck).toLowerCase().replace(' ', '-')">
{{ getComputedTruckStatus(truck) }}
</span>
<button class="truck-edit" (click)="openEditTruckModal(truck)"></button>
<button class="truck-remove" (click)="removeTruck(truck.id!)">×</button>
</span>
}
@if (getAvailableTrucks().length > 0) {
<select class="truck-select" (change)="onTruckAssign($event, show.id!)">
<option value="">+ Assigner</option>
@for (truck of getAvailableTrucks(); track truck.id) {
<option [value]="truck.id">{{ truck.type }}</option>
}
</select>
}
<button class="truck-create-btn" (click)="showTruckModal(show.id!)">+ Nouveau</button>
</div>
</div>
}
</div>
}
</div>
<div class="sidebar-block">
<h4>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<rect x="1" y="3" width="15" height="13" rx="2" ry="2" stroke-width="2"/>
<path d="M16 8h5l3 3v5h-4" stroke-width="2"/>
<circle cx="5.5" cy="18.5" r="2.5" stroke-width="2"/>
<circle cx="18.5" cy="18.5" r="2.5" stroke-width="2"/>
</svg>
Camions du jour
</h4>
@if (getDayTrucks().length === 0) {
<p class="no-items">Aucun camion ce jour</p>
} @else {
<div class="slot-info">
@for (truck of getDayTrucks(); track truck.id) {
<div class="show-card truck-card">
<div class="show-card-header">
<strong>{{ truck.type || 'Camion' }}</strong>
<div style="display:flex; align-items:center; gap:6px;">
<span class="truck-statut" [class]="'statut-' + getComputedTruckStatus(truck).toLowerCase().replace(' ', '-')">
{{ getComputedTruckStatus(truck) }}
</span>
<button class="truck-edit-card" (click)="openEditTruckModal(truck)"></button>
</div>
</div>
<p *ngIf="truck.sizes">Taille : {{ truck.sizes }}</p>
<p *ngIf="truck.maxExplosiveCapacity">Capacité : {{ truck.maxExplosiveCapacity }} kg</p>
</div>
}
</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
<nz-modal
[nzVisible]="isVisible()"
(nzVisibleChange)="isVisible.set($event)"
[nzFooter]="null"
[nzWidth]="480"
nzClassName="create-show-modal"
(nzOnCancel)="handleCancel()">
<ng-container *nzModalContent>
<div class="create-form">
<div class="create-form-title">
<div class="create-form-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" stroke-width="1.5"/>
</svg>
</div>
<div>
<h3>Créer un spectacle</h3>
<p>Renseignez les informations du spectacle</p>
</div>
</div>
<div class="form-field">
<label class="form-label">Nom du spectacle <span class="form-required">*</span></label>
<input class="form-input" placeholder="Ex: Feu d'artifice 14 juillet"
[(ngModel)]="newShow.name" name="name"/>
</div>
<div class="form-row-2">
<div class="form-field">
<label class="form-label">Lieu</label>
<input class="form-input" placeholder="Ex: Place de la mairie"
[(ngModel)]="newShow.place" name="place"/>
</div>
<div class="form-field">
<label class="form-label">Date et heure</label>
<div class="form-datepicker-wrap">
<nz-date-picker
nzShowTime
nzFormat="dd/MM/yyyy HH:mm"
[(ngModel)]="newShowDate"
nzPlaceHolder="Choisir une date..."
nzDropdownClassName="pyro-datepicker-dropdown"
name="date">
</nz-date-picker>
</div>
</div>
</div>
<div class="form-field">
<label class="form-label">Description</label>
<textarea class="form-input form-textarea"
placeholder="Notes, consignes, détails techniques..."
[(ngModel)]="newShow.description"
name="description">
</textarea>
</div>
<div class="form-actions">
<button class="form-btn-cancel" (click)="handleCancel()">Annuler</button>
<button class="form-btn-submit" [disabled]="!newShow.name" (click)="handleOk()">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 5v14M5 12h14" stroke-width="2.5" stroke-linecap="round"/>
</svg>
Créer le spectacle
</button>
</div>
</div>
</ng-container>
</nz-modal>
<nz-modal
[nzVisible]="isTruckModalVisible()"
(nzVisibleChange)="isTruckModalVisible.set($event)"
[nzFooter]="null"
[nzWidth]="440"
(nzOnCancel)="handleTruckCancel()">
<ng-container *nzModalContent>
<div class="create-form">
<div class="create-form-title">
<div class="create-form-icon" style="background: linear-gradient(135deg, #605DC8, #4e4aaa)">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<rect x="1" y="3" width="15" height="13" rx="2" ry="2" stroke-width="1.5"/>
<path d="M16 8h5l3 3v5h-4" stroke-width="1.5"/>
<circle cx="5.5" cy="18.5" r="2.5" stroke-width="1.5"/>
<circle cx="18.5" cy="18.5" r="2.5" stroke-width="1.5"/>
</svg>
</div>
<div>
<h3>{{ editTruckId ? 'Modifier le camion' : 'Nouveau camion' }}</h3>
<p>{{ editTruckId ? 'Modifiez les informations du camion' : 'Renseignez les informations du camion' }}</p>
</div>
</div>
<div class="form-field">
<label class="form-label">Plaque d'immatriculation <span class="form-required">*</span></label>
<input class="form-input" placeholder="Ex: AB-123-CD"
[(ngModel)]="newTruck.type" name="truckType"/>
</div>
<div class="form-row-2">
<div class="form-field">
<label class="form-label">Dimensions</label>
<input class="form-input" placeholder="Ex: 12m x 2.5m"
[(ngModel)]="newTruck.sizes" name="truckSizes"/>
</div>
<div class="form-field">
<label class="form-label">Capacité max (kg)</label>
<input class="form-input" type="number" placeholder="Ex: 500"
[(ngModel)]="newTruck.maxExplosiveCapacity" name="truckCapacity"/>
</div>
</div>
<!-- Statut : uniquement En panne et En maintenance sont modifiables manuellement -->
<div class="form-field">
<label class="form-label">Statut manuel</label>
<select class="form-input" [(ngModel)]="newTruck.status" name="truckStatus">
<option value="">-- Automatique --</option>
<option value="En panne">En panne</option>
<option value="En maintenance">En maintenance</option>
</select>
<p class="form-hint">Les statuts Disponible, Indisponible et En déplacement sont calculés automatiquement selon le show assigné.</p>
</div>
<div class="form-actions">
<button class="form-btn-cancel" (click)="handleTruckCancel()">Annuler</button>
<button class="form-btn-submit" [disabled]="!newTruck.type" (click)="handleTruckOk()"
style="background: linear-gradient(135deg, #605DC8, #4e4aaa)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 5v14M5 12h14" stroke-width="2.5" stroke-linecap="round"/>
</svg>
{{ editTruckId ? 'Enregistrer' : 'Créer le camion' }}
</button>
</div>
</div>
</ng-container>
</nz-modal>