course creation
This commit is contained in:
@@ -1,18 +1,28 @@
|
||||
import { Hippodrome } from './hippodrome';
|
||||
import { Reunion } from './reunion';
|
||||
|
||||
export enum CourseType {
|
||||
TIERCE = 'TIERCE',
|
||||
QUARTE = 'QUARTE + TIERCE',
|
||||
QUINTE = 'QUINTE + TIERCE',
|
||||
GAGNANT = 'GAGNANT',
|
||||
PLACE = 'PLACE',
|
||||
JUMELE_GAGNANT = 'JUMELE_GAGNANT',
|
||||
JUMELE_PLACE = "JUMELE_PLACE",
|
||||
JUMELE_ORDRE = "JUMELE_ORDRE",
|
||||
TRIO = "TRIO",
|
||||
TRIO_ORDRE = "TRIO_ORDRE",
|
||||
TRIPLET = "TRIPLET",
|
||||
QUATRO = "QUATRO",
|
||||
QUINTE = "QUINTE"
|
||||
}
|
||||
|
||||
export enum CourseStatut {
|
||||
PROGRAMMEE = 'PROGRAMMEE',
|
||||
CREATED = 'CREATED',
|
||||
VALIDATED = 'VALIDATED',
|
||||
RUNNING = 'RUNNING',
|
||||
CLOSED = 'CLOSED',
|
||||
CANCELED = 'CANCELED',
|
||||
BROUILLON = 'BROUILLON',
|
||||
VALIDE = 'VALIDE',
|
||||
OUVERT = 'OUVERT',
|
||||
FERME = 'FERME',
|
||||
RESULTAT_PROVISOIRE = 'RESULTAT_PROVISOIRE',
|
||||
RESULTAT_OFFICIEL = 'RESULTAT_OFFICIEL',
|
||||
REGLEE = 'REGLEE',
|
||||
ANNULEE = 'ANNULEE'
|
||||
}
|
||||
|
||||
export enum ResultatStatut {
|
||||
@@ -25,34 +35,21 @@ export enum ResultatStatut {
|
||||
|
||||
export interface Course {
|
||||
id: string;
|
||||
type: CourseType | string; // API returns "Plat" as string
|
||||
numero: number;
|
||||
hippodrome: Hippodrome | undefined;
|
||||
reunionNumero: number;
|
||||
reunionDate: string;
|
||||
nom: string;
|
||||
|
||||
dateDepartCourse: string;
|
||||
dateDebutParis: string;
|
||||
dateFinParis: string;
|
||||
|
||||
reunion: Reunion;
|
||||
reunionCourse: number;
|
||||
|
||||
particularite?: string;
|
||||
partants: number;
|
||||
distance: number;
|
||||
condition?: string;
|
||||
|
||||
statut: CourseStatut | string; // API returns "PROGRAMMEE" as string
|
||||
|
||||
nonPartants: string[];
|
||||
|
||||
// Additional API fields
|
||||
estTerminee?: boolean;
|
||||
estAnnulee?: boolean;
|
||||
nombreChevauxInscrits?: number;
|
||||
adeadHeat?: boolean;
|
||||
|
||||
createdBy: string;
|
||||
validatedBy?: string | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
numero: number;
|
||||
heureDepartPrevue: string;
|
||||
discipline: string;
|
||||
distanceMetres: number;
|
||||
categorie: string;
|
||||
nombrePartants: number;
|
||||
statut: string;
|
||||
annulee: boolean;
|
||||
reporteeMemeJour: boolean;
|
||||
reporteeAutreJour: boolean;
|
||||
incidentTechnique: boolean;
|
||||
nonPartants: Array<unknown>;
|
||||
typesParisOuverts: Array<string>
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ export interface Hippodrome {
|
||||
actif: boolean;
|
||||
capacite?: number;
|
||||
description?: string;
|
||||
reunionCount?: number;
|
||||
courseCount?: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
@@ -1,197 +1,197 @@
|
||||
import { Course, CourseType, CourseStatut, ResultatStatut } from '../interfaces/course';
|
||||
import { REUNIONS_MOCK } from './reunion.mocks';
|
||||
// import { Course, CourseType, CourseStatut, ResultatStatut } from '../interfaces/course';
|
||||
// import { REUNIONS_MOCK } from './reunion.mocks';
|
||||
|
||||
const now = new Date();
|
||||
const COURSES_PER_REUNION_BASE = 6;
|
||||
// const now = new Date();
|
||||
// const COURSES_PER_REUNION_BASE = 6;
|
||||
|
||||
function requiredLength(t: CourseType): number {
|
||||
switch (t) {
|
||||
case CourseType.TIERCE:
|
||||
return 3;
|
||||
case CourseType.QUARTE:
|
||||
return 4;
|
||||
case CourseType.QUINTE:
|
||||
return 5;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// function requiredLength(t: CourseType): number {
|
||||
// switch (t) {
|
||||
// case CourseType.TIERCE:
|
||||
// return 3;
|
||||
// case CourseType.QUARTE:
|
||||
// return 4;
|
||||
// case CourseType.QUINTE:
|
||||
// return 5;
|
||||
// default:
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
function rngPick<T>(arr: T[], seed: number): T {
|
||||
const x = Math.abs(Math.sin(seed) * 10000);
|
||||
const idx = Math.floor((x - Math.floor(x)) * arr.length) % arr.length;
|
||||
return arr[idx];
|
||||
}
|
||||
// function rngPick<T>(arr: T[], seed: number): T {
|
||||
// const x = Math.abs(Math.sin(seed) * 10000);
|
||||
// const idx = Math.floor((x - Math.floor(x)) * arr.length) % arr.length;
|
||||
// return arr[idx];
|
||||
// }
|
||||
|
||||
function makeMockResultat(
|
||||
type: CourseType,
|
||||
partants: number,
|
||||
nonPartantsNums: number[],
|
||||
seed: number
|
||||
): number[][] {
|
||||
const req = requiredLength(type);
|
||||
const np = new Set(nonPartantsNums);
|
||||
const all = Array.from({ length: partants }, (_, i) => i + 1).filter((n) => !np.has(n));
|
||||
const used = new Set<number>();
|
||||
const places: number[][] = [];
|
||||
// function makeMockResultat(
|
||||
// type: CourseType,
|
||||
// partants: number,
|
||||
// nonPartantsNums: number[],
|
||||
// seed: number
|
||||
// ): number[][] {
|
||||
// const req = requiredLength(type);
|
||||
// const np = new Set(nonPartantsNums);
|
||||
// const all = Array.from({ length: partants }, (_, i) => i + 1).filter((n) => !np.has(n));
|
||||
// const used = new Set<number>();
|
||||
// const places: number[][] = [];
|
||||
|
||||
const tiePlace = Math.abs(seed) % 10 === 0 ? ((seed % req) + req) % req : -1;
|
||||
// const tiePlace = Math.abs(seed) % 10 === 0 ? ((seed % req) + req) % req : -1;
|
||||
|
||||
for (let i = 0; i < req; i++) {
|
||||
const remaining = all.filter((n) => !used.has(n));
|
||||
if (remaining.length === 0) {
|
||||
places.push([]);
|
||||
continue;
|
||||
}
|
||||
const first = rngPick(remaining, seed + i * 7);
|
||||
used.add(first);
|
||||
const slot = [first];
|
||||
// for (let i = 0; i < req; i++) {
|
||||
// const remaining = all.filter((n) => !used.has(n));
|
||||
// if (remaining.length === 0) {
|
||||
// places.push([]);
|
||||
// continue;
|
||||
// }
|
||||
// const first = rngPick(remaining, seed + i * 7);
|
||||
// used.add(first);
|
||||
// const slot = [first];
|
||||
|
||||
if (i === tiePlace) {
|
||||
const remaining2 = all.filter((n) => !used.has(n));
|
||||
if (remaining2.length > 0) {
|
||||
const second = rngPick(remaining2, seed + i * 13);
|
||||
used.add(second);
|
||||
slot.push(second);
|
||||
slot.sort((a, b) => a - b);
|
||||
}
|
||||
}
|
||||
// if (i === tiePlace) {
|
||||
// const remaining2 = all.filter((n) => !used.has(n));
|
||||
// if (remaining2.length > 0) {
|
||||
// const second = rngPick(remaining2, seed + i * 13);
|
||||
// used.add(second);
|
||||
// slot.push(second);
|
||||
// slot.sort((a, b) => a - b);
|
||||
// }
|
||||
// }
|
||||
|
||||
places.push(slot);
|
||||
}
|
||||
// places.push(slot);
|
||||
// }
|
||||
|
||||
return places;
|
||||
}
|
||||
// return places;
|
||||
// }
|
||||
|
||||
const COURSE_NAMES = [
|
||||
'Prix du Delta',
|
||||
'Coupe du Fleuve Niger',
|
||||
'Trophée du Mandé',
|
||||
'Challenge du Nord',
|
||||
'Prix de Bamako',
|
||||
'Grand Prix de Tombouctou',
|
||||
'Prix du Sahara',
|
||||
'Trophée du Mali',
|
||||
'Prix de la Savane',
|
||||
'Course de la Paix',
|
||||
'Grand Prix du Sud',
|
||||
'Coupe de l’Avenir',
|
||||
'Prix du Coton',
|
||||
'Prix de la Liberté',
|
||||
'Prix du Marché Central',
|
||||
'Prix du Rail',
|
||||
'Challenge du Faso',
|
||||
'Prix du Soleil',
|
||||
'Prix du Soudan',
|
||||
'Grand Prix du Président',
|
||||
'Prix de la Jeunesse',
|
||||
'Coupe de la Nation',
|
||||
'Prix des Cavaliers',
|
||||
'Trophée de l’Unité',
|
||||
'Prix du Bénin',
|
||||
'Grand Prix de Sikasso',
|
||||
'Prix du Commerce',
|
||||
'Prix du Plateau',
|
||||
'Course des Champions',
|
||||
'Trophée de l’Espoir',
|
||||
'Prix du Développement',
|
||||
'Prix de l’Amitié',
|
||||
'Grand Prix International',
|
||||
'Prix du Peuple',
|
||||
'Prix de la Baie',
|
||||
'Trophée des Pionniers',
|
||||
'Prix du Littoral',
|
||||
];
|
||||
// const COURSE_NAMES = [
|
||||
// 'Prix du Delta',
|
||||
// 'Coupe du Fleuve Niger',
|
||||
// 'Trophée du Mandé',
|
||||
// 'Challenge du Nord',
|
||||
// 'Prix de Bamako',
|
||||
// 'Grand Prix de Tombouctou',
|
||||
// 'Prix du Sahara',
|
||||
// 'Trophée du Mali',
|
||||
// 'Prix de la Savane',
|
||||
// 'Course de la Paix',
|
||||
// 'Grand Prix du Sud',
|
||||
// 'Coupe de l’Avenir',
|
||||
// 'Prix du Coton',
|
||||
// 'Prix de la Liberté',
|
||||
// 'Prix du Marché Central',
|
||||
// 'Prix du Rail',
|
||||
// 'Challenge du Faso',
|
||||
// 'Prix du Soleil',
|
||||
// 'Prix du Soudan',
|
||||
// 'Grand Prix du Président',
|
||||
// 'Prix de la Jeunesse',
|
||||
// 'Coupe de la Nation',
|
||||
// 'Prix des Cavaliers',
|
||||
// 'Trophée de l’Unité',
|
||||
// 'Prix du Bénin',
|
||||
// 'Grand Prix de Sikasso',
|
||||
// 'Prix du Commerce',
|
||||
// 'Prix du Plateau',
|
||||
// 'Course des Champions',
|
||||
// 'Trophée de l’Espoir',
|
||||
// 'Prix du Développement',
|
||||
// 'Prix de l’Amitié',
|
||||
// 'Grand Prix International',
|
||||
// 'Prix du Peuple',
|
||||
// 'Prix de la Baie',
|
||||
// 'Trophée des Pionniers',
|
||||
// 'Prix du Littoral',
|
||||
// ];
|
||||
|
||||
const COURSE_TYPES = [CourseType.TIERCE, CourseType.QUARTE, CourseType.QUINTE];
|
||||
const COURSE_STATUTS = [
|
||||
CourseStatut.CREATED,
|
||||
CourseStatut.VALIDATED,
|
||||
CourseStatut.RUNNING,
|
||||
CourseStatut.CLOSED,
|
||||
CourseStatut.CANCELED,
|
||||
];
|
||||
// const COURSE_TYPES = [CourseType.TIERCE, CourseType.QUARTE, CourseType.QUINTE];
|
||||
// const COURSE_STATUTS = [
|
||||
// CourseStatut.CREATED,
|
||||
// CourseStatut.VALIDATED,
|
||||
// CourseStatut.RUNNING,
|
||||
// CourseStatut.CLOSED,
|
||||
// CourseStatut.CANCELED,
|
||||
// ];
|
||||
|
||||
const coursesPerReunion = new Map<string, number>();
|
||||
// const coursesPerReunion = new Map<string, number>();
|
||||
|
||||
const courses: Course[] = [];
|
||||
// const courses: Course[] = [];
|
||||
|
||||
REUNIONS_MOCK.forEach((reunion, reunionIndex) => {
|
||||
const courseCount = COURSES_PER_REUNION_BASE + (reunionIndex % 2);
|
||||
const reunionDate = new Date(`${reunion.date}T00:00:00`);
|
||||
// REUNIONS_MOCK.forEach((reunion, reunionIndex) => {
|
||||
// const courseCount = COURSES_PER_REUNION_BASE + (reunionIndex % 2);
|
||||
// const reunionDate = new Date(`${reunion.date}T00:00:00`);
|
||||
|
||||
for (let i = 0; i < courseCount; i++) {
|
||||
const globalIndex = courses.length;
|
||||
const type = COURSE_TYPES[(globalIndex + i) % COURSE_TYPES.length];
|
||||
const statut = COURSE_STATUTS[(globalIndex + reunionIndex) % COURSE_STATUTS.length];
|
||||
// for (let i = 0; i < courseCount; i++) {
|
||||
// const globalIndex = courses.length;
|
||||
// const type = COURSE_TYPES[(globalIndex + i) % COURSE_TYPES.length];
|
||||
// const statut = COURSE_STATUTS[(globalIndex + reunionIndex) % COURSE_STATUTS.length];
|
||||
|
||||
const numberWithinReunion = (coursesPerReunion.get(reunion.id) ?? 0) + 1;
|
||||
coursesPerReunion.set(reunion.id, numberWithinReunion);
|
||||
// const numberWithinReunion = (coursesPerReunion.get(reunion.id) ?? 0) + 1;
|
||||
// coursesPerReunion.set(reunion.id, numberWithinReunion);
|
||||
|
||||
const dateDebutParis = new Date(reunionDate);
|
||||
dateDebutParis.setHours(8 + i, 0, 0, 0);
|
||||
const dateFinParis = new Date(dateDebutParis);
|
||||
dateFinParis.setHours(dateDebutParis.getHours() + 2);
|
||||
const dateDepartCourse = new Date(reunionDate);
|
||||
dateDepartCourse.setHours(12 + i, 30, 0, 0);
|
||||
// const dateDebutParis = new Date(reunionDate);
|
||||
// dateDebutParis.setHours(8 + i, 0, 0, 0);
|
||||
// const dateFinParis = new Date(dateDebutParis);
|
||||
// dateFinParis.setHours(dateDebutParis.getHours() + 2);
|
||||
// const dateDepartCourse = new Date(reunionDate);
|
||||
// dateDepartCourse.setHours(12 + i, 30, 0, 0);
|
||||
|
||||
const partants = 10 + ((reunionIndex + i) % 6) * 2;
|
||||
// const partants = 10 + ((reunionIndex + i) % 6) * 2;
|
||||
|
||||
const nonPartants: string[] = numberWithinReunion % 4 === 0 ? [crypto.randomUUID()] : [];
|
||||
// const nonPartants: string[] = numberWithinReunion % 4 === 0 ? [crypto.randomUUID()] : [];
|
||||
|
||||
const nonPartantsNums = nonPartants.map((np) => Number(np));
|
||||
// const nonPartantsNums = nonPartants.map((np) => Number(np));
|
||||
|
||||
let resultat: number[][] | undefined;
|
||||
let resultatStatut: ResultatStatut = ResultatStatut.NONE;
|
||||
// let resultat: number[][] | undefined;
|
||||
// let resultatStatut: ResultatStatut = ResultatStatut.NONE;
|
||||
|
||||
if (statut === CourseStatut.CLOSED) {
|
||||
resultat = makeMockResultat(type, partants, nonPartantsNums, globalIndex * 31);
|
||||
resultatStatut = ResultatStatut.CONFIRMED;
|
||||
} else if (statut === CourseStatut.VALIDATED) {
|
||||
resultat = makeMockResultat(type, partants, nonPartantsNums, globalIndex * 17);
|
||||
resultatStatut = ResultatStatut.VALIDATED;
|
||||
} else if (statut === CourseStatut.RUNNING && (globalIndex + reunionIndex) % 3 === 0) {
|
||||
resultat = makeMockResultat(type, partants, nonPartantsNums, globalIndex * 7);
|
||||
resultatStatut = ResultatStatut.CREATED;
|
||||
}
|
||||
// if (statut === CourseStatut.CLOSED) {
|
||||
// resultat = makeMockResultat(type, partants, nonPartantsNums, globalIndex * 31);
|
||||
// resultatStatut = ResultatStatut.CONFIRMED;
|
||||
// } else if (statut === CourseStatut.VALIDATED) {
|
||||
// resultat = makeMockResultat(type, partants, nonPartantsNums, globalIndex * 17);
|
||||
// resultatStatut = ResultatStatut.VALIDATED;
|
||||
// } else if (statut === CourseStatut.RUNNING && (globalIndex + reunionIndex) % 3 === 0) {
|
||||
// resultat = makeMockResultat(type, partants, nonPartantsNums, globalIndex * 7);
|
||||
// resultatStatut = ResultatStatut.CREATED;
|
||||
// }
|
||||
|
||||
courses.push({
|
||||
id: crypto.randomUUID(),
|
||||
type,
|
||||
numero: globalIndex + 1,
|
||||
nom: `${COURSE_NAMES[(globalIndex + reunionIndex) % COURSE_NAMES.length]} - ${
|
||||
reunion.hippodrome.ville
|
||||
}`,
|
||||
dateDebutParis: dateDebutParis.toISOString(),
|
||||
dateFinParis: dateFinParis.toISOString(),
|
||||
dateDepartCourse: dateDepartCourse.toISOString(),
|
||||
reunion,
|
||||
reunionCourse: numberWithinReunion,
|
||||
particularite:
|
||||
(globalIndex + reunionIndex) % 2 === 0
|
||||
? 'Course de galop - conditions variées'
|
||||
: 'Trot attelé - catégorie nationale',
|
||||
partants,
|
||||
distance: 2000 + ((reunionIndex + i) % 5) * 200,
|
||||
condition:
|
||||
(globalIndex + reunionIndex) % 3 === 0
|
||||
? 'Réservée aux chevaux de 3 ans et plus'
|
||||
: 'Course mixte - catégorie B',
|
||||
statut,
|
||||
nonPartants,
|
||||
createdBy: `user-${((globalIndex + reunionIndex) % 5) + 1}`,
|
||||
validatedBy: statut === CourseStatut.VALIDATED ? 'admin-1' : undefined,
|
||||
createdAt: now.toISOString(),
|
||||
updatedAt: now.toISOString(),
|
||||
});
|
||||
}
|
||||
});
|
||||
// courses.push({
|
||||
// id: crypto.randomUUID(),
|
||||
// type,
|
||||
// numero: globalIndex + 1,
|
||||
// nom: `${COURSE_NAMES[(globalIndex + reunionIndex) % COURSE_NAMES.length]} - ${
|
||||
// reunion.hippodrome.ville
|
||||
// }`,
|
||||
// dateDebutParis: dateDebutParis.toISOString(),
|
||||
// dateFinParis: dateFinParis.toISOString(),
|
||||
// dateDepartCourse: dateDepartCourse.toISOString(),
|
||||
// reunion,
|
||||
// reunionCourse: numberWithinReunion,
|
||||
// particularite:
|
||||
// (globalIndex + reunionIndex) % 2 === 0
|
||||
// ? 'Course de galop - conditions variées'
|
||||
// : 'Trot attelé - catégorie nationale',
|
||||
// partants,
|
||||
// distance: 2000 + ((reunionIndex + i) % 5) * 200,
|
||||
// condition:
|
||||
// (globalIndex + reunionIndex) % 3 === 0
|
||||
// ? 'Réservée aux chevaux de 3 ans et plus'
|
||||
// : 'Course mixte - catégorie B',
|
||||
// statut,
|
||||
// nonPartants,
|
||||
// createdBy: `user-${((globalIndex + reunionIndex) % 5) + 1}`,
|
||||
// validatedBy: statut === CourseStatut.VALIDATED ? 'admin-1' : undefined,
|
||||
// createdAt: now.toISOString(),
|
||||
// updatedAt: now.toISOString(),
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
coursesPerReunion.forEach((count, reunionId) => {
|
||||
const reunion = REUNIONS_MOCK.find((r) => r.id === reunionId);
|
||||
if (reunion) {
|
||||
reunion.totalCourses = count;
|
||||
}
|
||||
});
|
||||
// coursesPerReunion.forEach((count, reunionId) => {
|
||||
// const reunion = REUNIONS_MOCK.find((r) => r.id === reunionId);
|
||||
// if (reunion) {
|
||||
// reunion.totalCourses = count;
|
||||
// }
|
||||
// });
|
||||
|
||||
export const COURSES_MOCK: Course[] = courses;
|
||||
// export const COURSES_MOCK: Course[] = courses;
|
||||
|
||||
@@ -1,110 +1,110 @@
|
||||
import { Course } from '../interfaces/course';
|
||||
import {
|
||||
CourseReportDetail,
|
||||
CourseReportDetailRow,
|
||||
CourseReportSummary,
|
||||
} from '../interfaces/report';
|
||||
import { COURSES_MOCK } from './course.mocks';
|
||||
// import { Course } from '../interfaces/course';
|
||||
// import {
|
||||
// CourseReportDetail,
|
||||
// CourseReportDetailRow,
|
||||
// CourseReportSummary,
|
||||
// } from '../interfaces/report';
|
||||
// import { COURSES_MOCK } from './course.mocks';
|
||||
|
||||
function randomInt(min: number, max: number) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
// function randomInt(min: number, max: number) {
|
||||
// return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
// }
|
||||
|
||||
export function payoutRowsForCourse(c: Course): CourseReportDetailRow[] {
|
||||
const base: CourseReportDetailRow[] = [
|
||||
{
|
||||
typeGain: 'QUINTE ORDRE',
|
||||
typeJeu: 'Quinte+',
|
||||
montant: 2840500,
|
||||
nombre: randomInt(1, 30),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'QUINTE DESORDRE',
|
||||
typeJeu: 'Quinte+',
|
||||
montant: 40000,
|
||||
nombre: randomInt(300, 5000),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'BONUS 4',
|
||||
typeJeu: 'Quinte+',
|
||||
montant: 2000,
|
||||
nombre: randomInt(5000, 25000),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'REMBOURSEMENT',
|
||||
typeJeu: 'Quinte+',
|
||||
montant: 300,
|
||||
nombre: randomInt(10, 500),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'TIERCE ORDRE',
|
||||
typeJeu: 'Tierce',
|
||||
montant: 37000,
|
||||
nombre: randomInt(100, 2000),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'TIERCE DESORDRE',
|
||||
typeJeu: 'Tierce',
|
||||
montant: 6000,
|
||||
nombre: randomInt(500, 6000),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'TRANSFORME COUPLE',
|
||||
typeJeu: 'Tierce',
|
||||
montant: 3000,
|
||||
nombre: randomInt(200, 2000),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
{
|
||||
typeGain: 'TRANSFORME SIMPLE',
|
||||
typeJeu: 'Tierce',
|
||||
montant: 1500,
|
||||
nombre: randomInt(10, 500),
|
||||
statut: 'Validée',
|
||||
distributed: false,
|
||||
externe: false,
|
||||
},
|
||||
];
|
||||
return base;
|
||||
}
|
||||
// export function payoutRowsForCourse(c: Course): CourseReportDetailRow[] {
|
||||
// const base: CourseReportDetailRow[] = [
|
||||
// {
|
||||
// typeGain: 'QUINTE ORDRE',
|
||||
// typeJeu: 'Quinte+',
|
||||
// montant: 2840500,
|
||||
// nombre: randomInt(1, 30),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'QUINTE DESORDRE',
|
||||
// typeJeu: 'Quinte+',
|
||||
// montant: 40000,
|
||||
// nombre: randomInt(300, 5000),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'BONUS 4',
|
||||
// typeJeu: 'Quinte+',
|
||||
// montant: 2000,
|
||||
// nombre: randomInt(5000, 25000),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'REMBOURSEMENT',
|
||||
// typeJeu: 'Quinte+',
|
||||
// montant: 300,
|
||||
// nombre: randomInt(10, 500),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'TIERCE ORDRE',
|
||||
// typeJeu: 'Tierce',
|
||||
// montant: 37000,
|
||||
// nombre: randomInt(100, 2000),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'TIERCE DESORDRE',
|
||||
// typeJeu: 'Tierce',
|
||||
// montant: 6000,
|
||||
// nombre: randomInt(500, 6000),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'TRANSFORME COUPLE',
|
||||
// typeJeu: 'Tierce',
|
||||
// montant: 3000,
|
||||
// nombre: randomInt(200, 2000),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// {
|
||||
// typeGain: 'TRANSFORME SIMPLE',
|
||||
// typeJeu: 'Tierce',
|
||||
// montant: 1500,
|
||||
// nombre: randomInt(10, 500),
|
||||
// statut: 'Validée',
|
||||
// distributed: false,
|
||||
// externe: false,
|
||||
// },
|
||||
// ];
|
||||
// return base;
|
||||
// }
|
||||
|
||||
export const REPORT_SUMMARIES_MOCK: CourseReportSummary[] = COURSES_MOCK.filter(
|
||||
(c) => c.statut === 'CLOSED'
|
||||
)
|
||||
.slice(0, 300)
|
||||
.map(
|
||||
(c) => ({ id: c.id, course: c, statut: 'En attente', confirmed: false } as CourseReportSummary)
|
||||
);
|
||||
// export const REPORT_SUMMARIES_MOCK: CourseReportSummary[] = COURSES_MOCK.filter(
|
||||
// (c) => c.statut === 'CLOSED'
|
||||
// )
|
||||
// .slice(0, 300)
|
||||
// .map(
|
||||
// (c) => ({ id: c.id, course: c, statut: 'En attente', confirmed: false } as CourseReportSummary)
|
||||
// );
|
||||
|
||||
export function buildDetailByCourseId(id: string): CourseReportDetail | undefined {
|
||||
const summary = REPORT_SUMMARIES_MOCK.find((s) => s.id === id);
|
||||
if (!summary) return undefined;
|
||||
const rows = payoutRowsForCourse(summary.course as Course);
|
||||
return { summary, rows } as CourseReportDetail;
|
||||
}
|
||||
// export function buildDetailByCourseId(id: string): CourseReportDetail | undefined {
|
||||
// const summary = REPORT_SUMMARIES_MOCK.find((s) => s.id === id);
|
||||
// if (!summary) return undefined;
|
||||
// const rows = payoutRowsForCourse(summary.course as Course);
|
||||
// return { summary, rows } as CourseReportDetail;
|
||||
// }
|
||||
|
||||
// Pre-built rows map for in-memory updates
|
||||
export const REPORT_DETAILS_MOCK = new Map<string, CourseReportDetailRow[]>();
|
||||
for (const c of COURSES_MOCK.filter((c) => c.statut === 'CLOSED').slice(0, 300)) {
|
||||
REPORT_DETAILS_MOCK.set(c.id, payoutRowsForCourse(c));
|
||||
}
|
||||
// // Pre-built rows map for in-memory updates
|
||||
// export const REPORT_DETAILS_MOCK = new Map<string, CourseReportDetailRow[]>();
|
||||
// for (const c of COURSES_MOCK.filter((c) => c.statut === 'CLOSED').slice(0, 300)) {
|
||||
// REPORT_DETAILS_MOCK.set(c.id, payoutRowsForCourse(c));
|
||||
// }
|
||||
|
||||
@@ -213,7 +213,7 @@ export class AgentLimitService {
|
||||
sortDir: 'asc',
|
||||
} as any).pipe(
|
||||
switchMap((result) => {
|
||||
const limits = result.data;
|
||||
const limits = result.content;
|
||||
const previousDefault = limits.find((l) => l.isDefault && l.id !== newDefaultLimitId);
|
||||
|
||||
const operations: Observable<any>[] = [];
|
||||
|
||||
@@ -451,7 +451,7 @@ export class AgentService {
|
||||
sortDir: 'asc',
|
||||
} as any).pipe(
|
||||
switchMap((result) => {
|
||||
const agents = result.data;
|
||||
const agents = result.content;
|
||||
if (agents.length === 0) {
|
||||
return of(true);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,16 +7,18 @@ import { normalizePage } from '@shared/paging/normalize-page';
|
||||
import { PaginatedHttpService } from '@shared/paging/paginated-http.service';
|
||||
import { ListParams, PagedResult } from '@shared/paging/paging';
|
||||
import { environment } from 'src/environments/environment.development';
|
||||
import { ServicesUtils } from './services-utils';
|
||||
|
||||
const USE_SERVER = true;
|
||||
const API_BASE = '/api/v1/hippodromes';
|
||||
const API_BASE = '/api/hippodromes';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class HippodromeService {
|
||||
private apiUrl = environment.apiBaseUrl + API_BASE;
|
||||
private store = signal<Hippodrome[]>([]);
|
||||
|
||||
constructor(private http: HttpClient, private paginatedHttp: PaginatedHttpService) {}
|
||||
|
||||
constructor(private http: HttpClient, private paginatedHttp: PaginatedHttpService, private servicesUtils:ServicesUtils) {}
|
||||
|
||||
// Helper method to get ngrok bypass headers
|
||||
private getNgrokHeaders(): Record<string, string> {
|
||||
@@ -30,326 +32,13 @@ export class HippodromeService {
|
||||
// LISTE — supporte client & serveur
|
||||
list(
|
||||
params: ListParams,
|
||||
usePaginationEndpoint: boolean = false
|
||||
usePaginationEndpoint: boolean = true
|
||||
): Observable<PagedResult<Hippodrome>> {
|
||||
if (USE_SERVER) {
|
||||
// If there's a search query, use the search endpoint
|
||||
if (params.search && params.search.trim()) {
|
||||
return this.search(params.search.trim()).pipe(
|
||||
switchMap((hippodromes) => {
|
||||
// Fetch all reunions and courses to calculate counts
|
||||
return forkJoin({
|
||||
reunions: this.http
|
||||
.get<any[]>(`${environment.apiBaseUrl}/api/v1/reunions`, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
})
|
||||
.pipe(
|
||||
catchError(() => of([])),
|
||||
map((data) => ({ data: data || [], meta: { total: (data || []).length } }))
|
||||
),
|
||||
courses: this.http
|
||||
.get<any[]>(`${environment.apiBaseUrl}/api/v1/courses`, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
})
|
||||
.pipe(
|
||||
catchError(() => of([])),
|
||||
map((data) => ({ data: data || [], meta: { total: (data || []).length } }))
|
||||
),
|
||||
}).pipe(
|
||||
map(({ reunions, courses }) => {
|
||||
// Count reunions per hippodrome
|
||||
const reunionCountMap = new Map<string, number>();
|
||||
reunions.data.forEach((reunion: any) => {
|
||||
const hippodromeId = String(reunion.hippodromeId || reunion.hippodrome?.id);
|
||||
if (hippodromeId && hippodromeId !== 'undefined' && hippodromeId !== 'null') {
|
||||
reunionCountMap.set(hippodromeId, (reunionCountMap.get(hippodromeId) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
// Create a map of reunionId -> hippodromeId from reunions
|
||||
const reunionToHippodromeMap = new Map<string, string>();
|
||||
reunions.data.forEach((reunion: any) => {
|
||||
const reunionId = String(reunion.id);
|
||||
const hippodromeId = String(reunion.hippodromeId || reunion.hippodrome?.id);
|
||||
if (
|
||||
reunionId &&
|
||||
reunionId !== 'undefined' &&
|
||||
reunionId !== 'null' &&
|
||||
hippodromeId &&
|
||||
hippodromeId !== 'undefined' &&
|
||||
hippodromeId !== 'null'
|
||||
) {
|
||||
reunionToHippodromeMap.set(reunionId, hippodromeId);
|
||||
}
|
||||
});
|
||||
|
||||
// Count courses per hippodrome using the reunion -> hippodrome mapping
|
||||
const courseCountMap = new Map<string, number>();
|
||||
courses.data.forEach((course: any) => {
|
||||
const reunionId = String(course.reunionId || course.reunion?.id);
|
||||
if (reunionId && reunionId !== 'undefined' && reunionId !== 'null') {
|
||||
const hippodromeId = reunionToHippodromeMap.get(reunionId);
|
||||
if (hippodromeId) {
|
||||
courseCountMap.set(hippodromeId, (courseCountMap.get(hippodromeId) || 0) + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add counts to hippodromes
|
||||
const hippodromesWithCounts = hippodromes.map((h) => ({
|
||||
...h,
|
||||
reunionCount: reunionCountMap.get(String(h.id)) ?? 0,
|
||||
courseCount: courseCountMap.get(String(h.id)) ?? 0,
|
||||
}));
|
||||
|
||||
// Apply client-side sorting and pagination
|
||||
let filtered = this.applyClientFilters(hippodromesWithCounts, {
|
||||
...params,
|
||||
search: '', // Already filtered by search endpoint
|
||||
});
|
||||
const total = filtered.length;
|
||||
const start = (params.page - 1) * params.perPage;
|
||||
const pageData = filtered.slice(start, start + params.perPage);
|
||||
|
||||
const uniqueCountries = new Set(filtered.map((h) => h.pays)).size;
|
||||
const uniqueCities = new Set(filtered.map((h) => h.ville)).size;
|
||||
const averageByCountry = filtered.length
|
||||
? Math.round(filtered.length / uniqueCountries)
|
||||
: 0;
|
||||
const totalReunions = filtered.reduce((acc, h) => acc + (h.reunionCount ?? 0), 0);
|
||||
const totalCourses = filtered.reduce((acc, h) => acc + (h.courseCount ?? 0), 0);
|
||||
|
||||
return normalizePage<Hippodrome>(
|
||||
{
|
||||
data: pageData,
|
||||
meta: {
|
||||
total,
|
||||
uniqueCountries,
|
||||
uniqueCities,
|
||||
averageByCountry,
|
||||
totalReunions,
|
||||
totalCourses,
|
||||
},
|
||||
},
|
||||
params.page,
|
||||
params.perPage
|
||||
);
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((err) => {
|
||||
console.error('Error searching hippodromes:', err);
|
||||
return of(
|
||||
normalizePage<Hippodrome>(
|
||||
{
|
||||
data: [],
|
||||
meta: {
|
||||
total: 0,
|
||||
uniqueCountries: 0,
|
||||
uniqueCities: 0,
|
||||
averageByCountry: 0,
|
||||
totalReunions: 0,
|
||||
totalCourses: 0,
|
||||
},
|
||||
},
|
||||
params.page,
|
||||
params.perPage
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (usePaginationEndpoint) {
|
||||
return this.paginatedHttp
|
||||
.fetch<Hippodrome>(this.apiUrl, params, {
|
||||
zeroBasedPageIndex: false,
|
||||
buildSort: (key, dir) => (key && dir ? ['sort', `${key},${dir}`] : null),
|
||||
mapClientSortKey: (k) => {
|
||||
const alias: Record<string, string> = {
|
||||
name: 'nom',
|
||||
city: 'ville',
|
||||
country: 'pays',
|
||||
};
|
||||
return k ? alias[k] ?? k : undefined;
|
||||
},
|
||||
})
|
||||
.pipe(
|
||||
catchError((err) => {
|
||||
console.error('Error fetching hippodromes:', err);
|
||||
return of(
|
||||
normalizePage<Hippodrome>(
|
||||
{
|
||||
data: [],
|
||||
meta: {
|
||||
total: 0,
|
||||
uniqueCountries: 0,
|
||||
uniqueCities: 0,
|
||||
averageByCountry: 0,
|
||||
totalReunions: 0,
|
||||
totalCourses: 0,
|
||||
},
|
||||
},
|
||||
params.page,
|
||||
params.perPage
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Fetch all data and apply client-side pagination
|
||||
return this.http
|
||||
.get<Hippodrome[]>(`${this.apiUrl}/actifs`, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
})
|
||||
.pipe(
|
||||
switchMap((allData) => {
|
||||
// Fetch all reunions and courses directly from API to calculate counts
|
||||
// We fetch directly to avoid circular dependency with ReunionService and CourseService
|
||||
return forkJoin({
|
||||
reunions: this.http
|
||||
.get<any[]>(`${environment.apiBaseUrl}/api/v1/reunions`, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
})
|
||||
.pipe(
|
||||
catchError(() => of([])),
|
||||
map((data) => ({ data, meta: { total: data.length } }))
|
||||
),
|
||||
courses: this.http
|
||||
.get<any[]>(`${environment.apiBaseUrl}/api/v1/courses`, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
})
|
||||
.pipe(
|
||||
catchError(() => of([])),
|
||||
map((data) => ({ data, meta: { total: data.length } }))
|
||||
),
|
||||
}).pipe(
|
||||
map(({ reunions, courses }) => {
|
||||
// Count reunions per hippodrome
|
||||
const reunionCountMap = new Map<string, number>();
|
||||
reunions.data.forEach((reunion: any) => {
|
||||
const hippodromeId = String(reunion.hippodromeId || reunion.hippodrome?.id);
|
||||
if (hippodromeId && hippodromeId !== 'undefined' && hippodromeId !== 'null') {
|
||||
reunionCountMap.set(
|
||||
hippodromeId,
|
||||
(reunionCountMap.get(hippodromeId) || 0) + 1
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Create a map of reunionId -> hippodromeId from reunions
|
||||
const reunionToHippodromeMap = new Map<string, string>();
|
||||
reunions.data.forEach((reunion: any) => {
|
||||
const reunionId = String(reunion.id);
|
||||
const hippodromeId = String(reunion.hippodromeId || reunion.hippodrome?.id);
|
||||
if (
|
||||
reunionId &&
|
||||
reunionId !== 'undefined' &&
|
||||
reunionId !== 'null' &&
|
||||
hippodromeId &&
|
||||
hippodromeId !== 'undefined' &&
|
||||
hippodromeId !== 'null'
|
||||
) {
|
||||
reunionToHippodromeMap.set(reunionId, hippodromeId);
|
||||
}
|
||||
});
|
||||
|
||||
// Count courses per hippodrome using the reunion -> hippodrome mapping
|
||||
const courseCountMap = new Map<string, number>();
|
||||
courses.data.forEach((course: any) => {
|
||||
const reunionId = String(course.reunionId || course.reunion?.id);
|
||||
if (reunionId && reunionId !== 'undefined' && reunionId !== 'null') {
|
||||
const hippodromeId = reunionToHippodromeMap.get(reunionId);
|
||||
if (hippodromeId) {
|
||||
courseCountMap.set(
|
||||
hippodromeId,
|
||||
(courseCountMap.get(hippodromeId) || 0) + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add counts to hippodromes
|
||||
const hippodromesWithCounts = allData.map((h) => ({
|
||||
...h,
|
||||
reunionCount: reunionCountMap.get(String(h.id)) ?? 0,
|
||||
courseCount: courseCountMap.get(String(h.id)) ?? 0,
|
||||
}));
|
||||
|
||||
// Apply client-side filtering, sorting, and pagination
|
||||
let filtered = this.applyClientFilters(hippodromesWithCounts, params);
|
||||
const total = filtered.length;
|
||||
const start = (params.page - 1) * params.perPage;
|
||||
const pageData = filtered.slice(start, start + params.perPage);
|
||||
|
||||
const uniqueCountries = new Set(filtered.map((h) => h.pays)).size;
|
||||
const uniqueCities = new Set(filtered.map((h) => h.ville)).size;
|
||||
const averageByCountry = filtered.length
|
||||
? Math.round(filtered.length / uniqueCountries)
|
||||
: 0;
|
||||
const totalReunions = filtered.reduce((acc, h) => acc + (h.reunionCount ?? 0), 0);
|
||||
const totalCourses = filtered.reduce((acc, h) => acc + (h.courseCount ?? 0), 0);
|
||||
|
||||
return normalizePage<Hippodrome>(
|
||||
{
|
||||
data: pageData,
|
||||
meta: {
|
||||
total,
|
||||
uniqueCountries,
|
||||
uniqueCities,
|
||||
averageByCountry,
|
||||
totalReunions,
|
||||
totalCourses,
|
||||
},
|
||||
},
|
||||
params.page,
|
||||
params.perPage
|
||||
);
|
||||
})
|
||||
);
|
||||
}),
|
||||
catchError((err) => {
|
||||
console.error('Error fetching hippodromes:', err);
|
||||
return of(
|
||||
normalizePage<Hippodrome>(
|
||||
{
|
||||
data: [],
|
||||
meta: {
|
||||
total: 0,
|
||||
uniqueCountries: 0,
|
||||
uniqueCities: 0,
|
||||
averageByCountry: 0,
|
||||
totalReunions: 0,
|
||||
totalCourses: 0,
|
||||
},
|
||||
},
|
||||
params.page,
|
||||
params.perPage
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Mock mode disabled - return empty result
|
||||
return of(
|
||||
normalizePage<Hippodrome>(
|
||||
{
|
||||
data: [],
|
||||
meta: {
|
||||
total: 0,
|
||||
uniqueCountries: 0,
|
||||
uniqueCities: 0,
|
||||
averageByCountry: 0,
|
||||
totalReunions: 0,
|
||||
totalCourses: 0,
|
||||
},
|
||||
},
|
||||
params.page,
|
||||
params.perPage
|
||||
)
|
||||
);
|
||||
const hippodromeList = this.http.get<PagedResult<Hippodrome>>(this.apiUrl, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
params: this.servicesUtils.getParamsFromModel(params)
|
||||
})
|
||||
return hippodromeList;
|
||||
}
|
||||
|
||||
private applyClientFilters(data: Hippodrome[], params: ListParams): Hippodrome[] {
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
import { Injectable, signal } from '@angular/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { CourseReportDetail, CourseReportDetailRow, CourseReportSummary } from '../interfaces/report';
|
||||
import { REPORT_SUMMARIES_MOCK, REPORT_DETAILS_MOCK } from '../mocks/report.mocks';
|
||||
import { normalizePage } from '@shared/paging/normalize-page';
|
||||
import { ListParams, PagedResult, SortDir } from '@shared/paging/paging';
|
||||
// import { Injectable, signal } from '@angular/core';
|
||||
// import { Observable, of } from 'rxjs';
|
||||
// import { CourseReportDetail, CourseReportDetailRow, CourseReportSummary } from '../interfaces/report';
|
||||
// import { REPORT_SUMMARIES_MOCK, REPORT_DETAILS_MOCK } from '../mocks/report.mocks';
|
||||
// import { normalizePage } from '@shared/paging/normalize-page';
|
||||
// import { ListParams, PagedResult, SortDir } from '@shared/paging/paging';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ReportService {
|
||||
private summaries = signal<CourseReportSummary[]>([...REPORT_SUMMARIES_MOCK]);
|
||||
// @Injectable({ providedIn: 'root' })
|
||||
// export class ReportService {
|
||||
// private summaries = signal<CourseReportSummary[]>([...REPORT_SUMMARIES_MOCK]);
|
||||
|
||||
list(params: ListParams): Observable<PagedResult<CourseReportSummary>> {
|
||||
let data = [...this.summaries()];
|
||||
const q = (params.search ?? '').toLowerCase();
|
||||
if (q) {
|
||||
data = data.filter((r) =>
|
||||
[
|
||||
r.course.nom,
|
||||
r.course.type,
|
||||
r.course.reunion?.hippodrome?.nom,
|
||||
String(r.course.numero),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.map((s) => String(s).toLowerCase())
|
||||
.some((s) => s.includes(q))
|
||||
);
|
||||
}
|
||||
if (params.sortKey && params.sortDir) {
|
||||
const { sortKey, sortDir } = params as { sortKey: string; sortDir: SortDir };
|
||||
const get = (o: any, k: string) => k.split('.').reduce((a, b) => a?.[b], o);
|
||||
data = [...data].sort((a, b) => String(get(a, sortKey) ?? '').localeCompare(String(get(b, sortKey) ?? ''), 'fr', { numeric: true }) * (sortDir === 'asc' ? 1 : -1));
|
||||
}
|
||||
const start = (params.page - 1) * params.perPage;
|
||||
const pageData = data.slice(start, start + params.perPage);
|
||||
return of(normalizePage<CourseReportSummary>({ data: pageData, meta: { total: data.length } }, params.page, params.perPage));
|
||||
}
|
||||
// list(params: ListParams): Observable<PagedResult<CourseReportSummary>> {
|
||||
// let data = [...this.summaries()];
|
||||
// const q = (params.search ?? '').toLowerCase();
|
||||
// if (q) {
|
||||
// data = data.filter((r) =>
|
||||
// [
|
||||
// r.course.nom,
|
||||
// r.course.type,
|
||||
// r.course.reunion?.hippodrome?.nom,
|
||||
// String(r.course.numero),
|
||||
// ]
|
||||
// .filter(Boolean)
|
||||
// .map((s) => String(s).toLowerCase())
|
||||
// .some((s) => s.includes(q))
|
||||
// );
|
||||
// }
|
||||
// if (params.sortKey && params.sortDir) {
|
||||
// const { sortKey, sortDir } = params as { sortKey: string; sortDir: SortDir };
|
||||
// const get = (o: any, k: string) => k.split('.').reduce((a, b) => a?.[b], o);
|
||||
// data = [...data].sort((a, b) => String(get(a, sortKey) ?? '').localeCompare(String(get(b, sortKey) ?? ''), 'fr', { numeric: true }) * (sortDir === 'asc' ? 1 : -1));
|
||||
// }
|
||||
// const start = (params.page - 1) * params.perPage;
|
||||
// const pageData = data.slice(start, start + params.perPage);
|
||||
// return of(normalizePage<CourseReportSummary>({ data: pageData, meta: { total: data.length } }, params.page, params.perPage));
|
||||
// }
|
||||
|
||||
getDetail(courseId: string): Observable<CourseReportDetail | undefined> {
|
||||
const summary = this.summaries().find((s) => s.id === courseId);
|
||||
if (!summary) return of(undefined);
|
||||
const rows = REPORT_DETAILS_MOCK.get(courseId) ?? [];
|
||||
return of({ summary, rows });
|
||||
}
|
||||
// getDetail(courseId: string): Observable<CourseReportDetail | undefined> {
|
||||
// const summary = this.summaries().find((s) => s.id === courseId);
|
||||
// if (!summary) return of(undefined);
|
||||
// const rows = REPORT_DETAILS_MOCK.get(courseId) ?? [];
|
||||
// return of({ summary, rows });
|
||||
// }
|
||||
|
||||
// === Actions ===
|
||||
validate(courseId: string): Observable<CourseReportSummary | undefined> {
|
||||
let updated: CourseReportSummary | undefined;
|
||||
this.summaries.set(
|
||||
this.summaries().map((s) => (s.id === courseId ? ((updated = { ...s, statut: 'Validé', confirmed: false }), updated) : s))
|
||||
);
|
||||
return of(updated);
|
||||
}
|
||||
// // === Actions ===
|
||||
// validate(courseId: string): Observable<CourseReportSummary | undefined> {
|
||||
// let updated: CourseReportSummary | undefined;
|
||||
// this.summaries.set(
|
||||
// this.summaries().map((s) => (s.id === courseId ? ((updated = { ...s, statut: 'Validé', confirmed: false }), updated) : s))
|
||||
// );
|
||||
// return of(updated);
|
||||
// }
|
||||
|
||||
confirm(courseId: string): Observable<CourseReportSummary | undefined> {
|
||||
let updated: CourseReportSummary | undefined;
|
||||
this.summaries.set(
|
||||
this.summaries().map((s) => (s.id === courseId ? ((updated = { ...s, statut: 'Validé', confirmed: true }), updated) : s))
|
||||
);
|
||||
return of(updated);
|
||||
}
|
||||
// confirm(courseId: string): Observable<CourseReportSummary | undefined> {
|
||||
// let updated: CourseReportSummary | undefined;
|
||||
// this.summaries.set(
|
||||
// this.summaries().map((s) => (s.id === courseId ? ((updated = { ...s, statut: 'Validé', confirmed: true }), updated) : s))
|
||||
// );
|
||||
// return of(updated);
|
||||
// }
|
||||
|
||||
resetStatus(courseId: string): Observable<CourseReportSummary | undefined> {
|
||||
let updated: CourseReportSummary | undefined;
|
||||
this.summaries.set(
|
||||
this.summaries().map((s) => (s.id === courseId ? ((updated = { ...s, statut: 'Non Validé', confirmed: false }), updated) : s))
|
||||
);
|
||||
return of(updated);
|
||||
}
|
||||
// resetStatus(courseId: string): Observable<CourseReportSummary | undefined> {
|
||||
// let updated: CourseReportSummary | undefined;
|
||||
// this.summaries.set(
|
||||
// this.summaries().map((s) => (s.id === courseId ? ((updated = { ...s, statut: 'Non Validé', confirmed: false }), updated) : s))
|
||||
// );
|
||||
// return of(updated);
|
||||
// }
|
||||
|
||||
modifyRows(courseId: string, rows: CourseReportDetailRow[]): Observable<boolean> {
|
||||
REPORT_DETAILS_MOCK.set(courseId, rows);
|
||||
return of(true);
|
||||
}
|
||||
}
|
||||
// modifyRows(courseId: string, rows: CourseReportDetailRow[]): Observable<boolean> {
|
||||
// REPORT_DETAILS_MOCK.set(courseId, rows);
|
||||
// return of(true);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ interface ReunionApiResponse {
|
||||
}
|
||||
|
||||
const USE_SERVER = true;
|
||||
const API_BASE = '/api/v1/reunions';
|
||||
const API_BASE = '/api/reunions';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ReunionService {
|
||||
@@ -49,7 +49,7 @@ export class ReunionService {
|
||||
|
||||
list(
|
||||
params: ListParams,
|
||||
usePaginationEndpoint: boolean = false
|
||||
usePaginationEndpoint: boolean = true
|
||||
): Observable<PagedResult<Reunion>> {
|
||||
if (USE_SERVER) {
|
||||
if (usePaginationEndpoint) {
|
||||
@@ -61,30 +61,28 @@ export class ReunionService {
|
||||
.pipe(
|
||||
switchMap((pagedResult) => {
|
||||
// Handle empty data case
|
||||
if (!pagedResult.data || pagedResult.data.length === 0) {
|
||||
if (!pagedResult.content || pagedResult.content.length === 0) {
|
||||
return of({
|
||||
...pagedResult,
|
||||
data: [],
|
||||
meta: {
|
||||
...pagedResult.meta,
|
||||
uniqueHippodromes: 0,
|
||||
content: [],
|
||||
pageable: {
|
||||
...pagedResult.pageable,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Extract unique hippodrome IDs from the paginated data
|
||||
const uniqueHippodromeIds = [
|
||||
...new Set(pagedResult.data.map((r) => String(r.hippodromeId))),
|
||||
...new Set(pagedResult.content.map((r) => String(r.hippodromeId))),
|
||||
];
|
||||
|
||||
// Handle case where there are no unique IDs
|
||||
if (uniqueHippodromeIds.length === 0) {
|
||||
return of({
|
||||
...pagedResult,
|
||||
data: [],
|
||||
meta: {
|
||||
...pagedResult.meta,
|
||||
uniqueHippodromes: 0,
|
||||
content: [],
|
||||
pageable: {
|
||||
...pagedResult.pageable,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -93,12 +91,12 @@ export class ReunionService {
|
||||
const hippodromeRequests = uniqueHippodromeIds.map((id) =>
|
||||
this.hippodromeService
|
||||
.getById(id)
|
||||
.pipe(catchError(() => of<Hippodrome | undefined>(undefined)))
|
||||
.pipe(catchError(() => of<Hippodrome>()))
|
||||
);
|
||||
|
||||
// Fetch courses to calculate counts per reunion
|
||||
const coursesRequest = this.http
|
||||
.get<any[]>(`${environment.apiBaseUrl}/api/v1/courses`, {
|
||||
.get<any[]>(`${environment.apiBaseUrl}/api/courses`, {
|
||||
headers: this.getNgrokHeaders(),
|
||||
})
|
||||
.pipe(
|
||||
@@ -133,7 +131,7 @@ export class ReunionService {
|
||||
});
|
||||
|
||||
// Transform API responses to Reunion objects
|
||||
const transformedData: Reunion[] = pagedResult.data
|
||||
const transformedData: Reunion[] = pagedResult.content
|
||||
.map((apiReunion) => {
|
||||
const hippodrome = hippodromeMap.get(String(apiReunion.hippodromeId));
|
||||
if (!hippodrome) {
|
||||
@@ -155,19 +153,10 @@ export class ReunionService {
|
||||
} as Reunion;
|
||||
})
|
||||
.filter((r): r is Reunion => r !== null && r !== undefined);
|
||||
|
||||
// Calculate unique hippodromes count
|
||||
const uniqueHippodromes = new Set(transformedData.map((r) => r.hippodrome.id))
|
||||
.size;
|
||||
|
||||
return {
|
||||
...pagedResult,
|
||||
data: transformedData,
|
||||
meta: {
|
||||
...pagedResult.meta,
|
||||
uniqueHippodromes,
|
||||
},
|
||||
};
|
||||
return {
|
||||
...pagedResult,
|
||||
content: transformedData,
|
||||
}
|
||||
})
|
||||
);
|
||||
}),
|
||||
|
||||
16
src/app/core/services/services-utils.ts
Normal file
16
src/app/core/services/services-utils.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { HttpParams } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ListParams } from "@shared/paging/paging";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class ServicesUtils{
|
||||
getParamsFromModel(params:ListParams):HttpParams{
|
||||
let httpParams = new HttpParams();
|
||||
Object.entries(params).forEach(([key, value])=>{
|
||||
if(params != null && params!=undefined){
|
||||
httpParams.set(key, String(value))
|
||||
}
|
||||
})
|
||||
return httpParams;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user