Primo rilascio

This commit is contained in:
2026-03-07 00:15:59 +01:00
commit dd5282dd69
609 changed files with 75246 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
<h2 mat-dialog-title>{{ title }}</h2>
<mat-dialog-content [formGroup]="shiftForm">
<!-- Messaggio errore validatore custom -->
<mat-error *ngIf="shiftForm.hasError('timeRange') && (shiftForm.get('start_time')?.touched || shiftForm.get('end_time')?.touched)">
L'orario di fine deve essere successivo all'orario di inizio.
</mat-error>
<div class="form-grid">
<mat-form-field appearance="fill" class="full-width-field">
<mat-label>Nome Definizione Turno</mat-label>
<input matInput formControlName="name" required>
<mat-error *ngIf="shiftForm.get('name')?.hasError('required')">
Il nome è obbligatorio.
</mat-error>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Orario Inizio</mat-label>
<input matInput type="time" formControlName="start_time" required placeholder="HH:MM">
<mat-error *ngIf="shiftForm.get('start_time')?.hasError('required')">Orario inizio obbligatorio.</mat-error>
<mat-error *ngIf="shiftForm.get('start_time')?.hasError('pattern')">Formato ora non valido (HH:MM).</mat-error>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Orario Fine</mat-label>
<input matInput type="time" formControlName="end_time" required placeholder="HH:MM">
<mat-error *ngIf="shiftForm.get('end_time')?.hasError('required')">Orario fine obbligatorio.</mat-error>
<mat-error *ngIf="shiftForm.get('end_time')?.hasError('pattern')">Formato ora non valido (HH:MM).</mat-error>
</mat-form-field>
<mat-form-field appearance="fill" class="full-width-field">
<mat-label>Note</mat-label>
<textarea matInput formControlName="notes" rows="3"></textarea>
</mat-form-field>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="onCancel()">Annulla</button>
<button mat-raised-button color="primary" (click)="onSave()" [disabled]="!shiftForm.valid">
{{ isEditMode ? 'Salva Modifiche' : 'Aggiungi' }}
</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,43 @@
/* Contenitore per la griglia */
.form-grid {
display: grid;
grid-template-columns: 1fr; /* Default: una colonna */
gap: 0 16px; /* Spazio tra colonne */
}
/* Campi a larghezza piena */
.form-grid .full-width-field {
grid-column: 1 / -1;
margin-top: 10px;
}
/* Media Query per schermi più larghi */
@media (min-width: 600px) {
.form-grid {
grid-template-columns: 1fr 1fr; /* Due colonne */
}
/* Fai occupare tutta la larghezza ai campi che devono stare da soli */
.form-grid mat-form-field:first-child, /* Nome */
.form-grid mat-form-field:has(textarea) /* Textarea */
{
grid-column: 1 / -1;
}
}
/* Stili generali per i campi */
mat-form-field {
width: 100%;
margin-bottom: 10px;
}
/* Contenuto dialog scrollabile */
mat-dialog-content {
max-height: 70vh;
overflow-y: auto;
}
/* Stile per errore validatore custom */
mat-dialog-content > mat-error {
margin-bottom: 15px;
display: block;
}

View File

@@ -0,0 +1,87 @@
import { Component, Inject, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { ShiftDefinition } from '../../services/shift-definition.service'; // Importa l'interfaccia
// Validatore custom per assicurare che end_time sia dopo start_time
export const timeRangeValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
const start = control.get('start_time');
const end = control.get('end_time');
// Confronta solo se entrambi i valori sono presenti e sembrano orari validi (HH:MM o HH:MM:SS)
const timeRegex = /^\d{2}:\d{2}(:\d{2})?$/;
if (start?.value && end?.value && timeRegex.test(start.value) && timeRegex.test(end.value)) {
// Confronto semplice delle stringhe funziona per HH:MM o HH:MM:SS
return start.value < end.value ? null : { timeRange: true }; // Errore se start >= end
}
return null;
};
@Component({
selector: 'app-shift-definition-dialog',
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule
],
templateUrl: './shift-definition-dialog.component.html',
styleUrl: './shift-definition-dialog.component.scss'
})
export class ShiftDefinitionDialogComponent implements OnInit {
shiftForm: FormGroup;
isEditMode: boolean;
title: string;
constructor(
public dialogRef: MatDialogRef<ShiftDefinitionDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: { shift?: ShiftDefinition },
private fb: FormBuilder
) {
this.isEditMode = !!data?.shift;
this.title = this.isEditMode ? 'Modifica Definizione Turno' : 'Aggiungi Nuova Definizione Turno';
// Validatore per formato HH:MM o HH:MM:SS
const timePattern = Validators.pattern(/^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/);
this.shiftForm = this.fb.group({
name: ['', Validators.required],
start_time: ['', [Validators.required, timePattern]],
end_time: ['', [Validators.required, timePattern]],
notes: ['']
}, { validators: timeRangeValidator }); // Applica validatore custom al gruppo
}
ngOnInit(): void {
if (this.isEditMode && this.data.shift) {
this.shiftForm.patchValue(this.data.shift);
}
}
onCancel(): void {
this.dialogRef.close();
}
onSave(): void {
if (this.shiftForm.valid) {
this.dialogRef.close(this.shiftForm.value);
} else {
console.log('Shift Form Invalid:', this.shiftForm.errors);
Object.keys(this.shiftForm.controls).forEach(key => {
const control = this.shiftForm.get(key);
if (control && control.errors) {
console.log(`Control Error - ${key}:`, control.errors);
}
});
this.shiftForm.markAllAsTouched();
}
}
}