Application complète de saisie et de suivi des trajets kilométriques avec calcul de distance routière (OpenRouteService), barème kilométrique, résumés et régularisation annuelle. Backend (ASP.NET Core .NET 8, EF Core, SQLite) : - Trajets (CRUD, réordonnancement, insertion), calcul de distance ORS avec fallback Haversine, géométrie d'itinéraire stockée par trajet, recalcul en masse. - Profil, véhicules (avec dénomination), carnet d'adresses nommées, cache d'adresses. - Barème kilométrique : tranches multiples par puissance fiscale, borne max exclusive avec 'illimité' (KmMax nullable), coefficient à 3 décimales, recopie du dernier barème connu. - Résumés mensuel/annuel, montants réglés, régularisation, export PDF. Frontend (Angular 22, zoneless + signals) : - Consultation par jour, navigation temporelle synchronisée, carte Leaflet, formulaire de trajet (adresses nommées, domicile, autocomplétion BAN). - Détection de changement zoneless (indépendante de zone.js). Hébergement : Docker Compose (nginx + backend), scripts run-dev.sh / run-docker.sh.
65 lines
1.8 KiB
TypeScript
65 lines
1.8 KiB
TypeScript
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
|
||
|
||
/**
|
||
* Expression validant strictement le format JJ/MM/AAAA
|
||
* (2 chiffres / 2 chiffres / 4 chiffres).
|
||
*/
|
||
const FORMAT_JJ_MM_AAAA = /^(\d{2})\/(\d{2})\/(\d{4})$/;
|
||
|
||
/**
|
||
* Vérifie qu'une chaîne au format JJ/MM/AAAA correspond à une date réelle
|
||
* (mois 1–12, jour cohérent avec le mois et l'année bissextile).
|
||
*
|
||
* @returns `true` si le format est correct ET la date existe, sinon `false`.
|
||
*/
|
||
export function estDateJjMmAAAAValide(valeur: string): boolean {
|
||
const correspondance = FORMAT_JJ_MM_AAAA.exec(valeur);
|
||
if (!correspondance) {
|
||
return false;
|
||
}
|
||
|
||
const jour = Number(correspondance[1]);
|
||
const mois = Number(correspondance[2]);
|
||
const annee = Number(correspondance[3]);
|
||
|
||
if (mois < 1 || mois > 12) {
|
||
return false;
|
||
}
|
||
if (jour < 1) {
|
||
return false;
|
||
}
|
||
|
||
// Nombre de jours du mois (tient compte des années bissextiles via Date).
|
||
const joursDansMois = new Date(annee, mois, 0).getDate();
|
||
if (jour > joursDansMois) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Validateur Angular pour un contrôle de date au format JJ/MM/AAAA.
|
||
*
|
||
* Retourne `{ dateInvalide: true }` si la valeur est présente mais mal formatée
|
||
* ou correspond à une date inexistante (Exigence 1.5). Une valeur vide est
|
||
* considérée valide ici : l'obligation de présence relève du validateur
|
||
* `Validators.required`.
|
||
*/
|
||
export function dateJjMmAAAAValidator(): ValidatorFn {
|
||
return (control: AbstractControl): ValidationErrors | null => {
|
||
const valeur = control.value;
|
||
|
||
// Champ vide : on laisse `required` gérer l'obligation.
|
||
if (valeur === null || valeur === undefined || valeur === '') {
|
||
return null;
|
||
}
|
||
|
||
if (typeof valeur !== 'string' || !estDateJjMmAAAAValide(valeur)) {
|
||
return { dateInvalide: true };
|
||
}
|
||
|
||
return null;
|
||
};
|
||
}
|