Fiches de poste rapides, badges sans initiales, vue par bénévole sur l'axe des temps
Étape 62 : les fiches de poste intégraient la photo d'origine de chaque bénévole pour chaque créneau (CPU à 300 %, puis erreur) — photos réduites à la vignette une fois par PDF ; badges : photo recadrée une fois par génération et décodée à taille réduite. Étape 61 : sans photo, le cadre de la photo reste vide sur le badge. Étape 60 : vue par bénévole en tranches de 30 min, affectations étirées sur toute leur durée, postes simultanés empilés, ligne de l'heure actuelle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c57c70569c
commit
c6ea7378c7
@@ -2,7 +2,6 @@ import type {
|
||||
ArtistRead,
|
||||
AssignmentRead,
|
||||
DayPartRead,
|
||||
MatrixResponse,
|
||||
PositionCategory,
|
||||
ShiftRead,
|
||||
Violation,
|
||||
@@ -108,22 +107,6 @@ export function candidateChanceScore(params: {
|
||||
return score;
|
||||
}
|
||||
|
||||
/** Colonne de la grille : un créneau distinct (date, heure de début, heure de
|
||||
* fin) — pas seulement une heure de début : deux créneaux qui démarrent à la
|
||||
* même heure mais durent différemment ont chacun leur colonne. */
|
||||
export interface LatticeColumn {
|
||||
key: string; // `YYYY-MM-DD|HH:MM|HH:MM`
|
||||
date: string;
|
||||
time: string;
|
||||
endTime: string;
|
||||
label: string; // « 17:00 → 22:00 »
|
||||
}
|
||||
|
||||
export interface LatticeDay {
|
||||
date: string;
|
||||
columns: LatticeColumn[];
|
||||
}
|
||||
|
||||
/** Frontière du jour (« journée » au sens § 3 du CLAUDE.md) : début du plus
|
||||
* long creux laissé par les créneaux types sur le cadran de 24 h (l'heure où
|
||||
* le dernier de la journée se termine) — même règle que
|
||||
@@ -169,68 +152,6 @@ export function dayBoundaryFromDayParts(
|
||||
return clockLabel(bestStart);
|
||||
}
|
||||
|
||||
/** Construit le treillis de colonnes à partir de créneaux (grille alignée).
|
||||
* `dayBoundary` (`HH:MM`, défaut minuit) regroupe et trie les colonnes par
|
||||
* « journée de festival » plutôt que par date calendaire brute : un créneau
|
||||
* commençant avant cette heure (ex. 02:00, suite d'une soirée qui a passé
|
||||
* minuit) est rattaché au jour précédent et trié après 23:00, pas avant
|
||||
* 19:00 — voir CLAUDE.md § 3. */
|
||||
export function buildLattice(
|
||||
starts: Array<{ starts_at: string; ends_at: string }>,
|
||||
dayBoundary = '00:00',
|
||||
): {
|
||||
days: LatticeDay[];
|
||||
columns: LatticeColumn[];
|
||||
} {
|
||||
const boundaryMinutes = minutesOfDay(dayBoundary);
|
||||
const seen = new Map<string, LatticeColumn & { festivalDay: string; sortMinutes: number }>();
|
||||
for (const s of starts) {
|
||||
const date = datePart(s.starts_at);
|
||||
const time = timePart(s.starts_at);
|
||||
const endTime = timePart(s.ends_at);
|
||||
const key = `${date}|${time}|${endTime}`;
|
||||
if (!seen.has(key)) {
|
||||
const minutes = minutesOfDay(time);
|
||||
const festivalDay = minutes < boundaryMinutes ? addDays(date, -1) : date;
|
||||
const sortMinutes = (minutes - boundaryMinutes + 24 * 60) % (24 * 60);
|
||||
seen.set(key, { key, date, time, endTime, label: `${time}–${endTime}`, festivalDay, sortMinutes });
|
||||
}
|
||||
}
|
||||
const ordered = [...seen.values()].sort(
|
||||
(a, b) => a.festivalDay.localeCompare(b.festivalDay) || a.sortMinutes - b.sortMinutes,
|
||||
);
|
||||
const columns: LatticeColumn[] = ordered.map(({ key, date, time, endTime, label }) => ({
|
||||
key,
|
||||
date,
|
||||
time,
|
||||
endTime,
|
||||
label,
|
||||
}));
|
||||
const days: LatticeDay[] = [];
|
||||
for (const column of ordered) {
|
||||
let day = days.find((d) => d.date === column.festivalDay);
|
||||
if (!day) {
|
||||
day = { date: column.festivalDay, columns: [] };
|
||||
days.push(day);
|
||||
}
|
||||
day.columns.push({
|
||||
key: column.key,
|
||||
date: column.date,
|
||||
time: column.time,
|
||||
endTime: column.endTime,
|
||||
label: column.label,
|
||||
});
|
||||
}
|
||||
return { days, columns };
|
||||
}
|
||||
|
||||
export function latticeFromMatrix(matrix: MatrixResponse, dayBoundary?: string) {
|
||||
return buildLattice(
|
||||
matrix.positions.flatMap((p) => p.shifts.map((s) => ({ starts_at: s.starts_at, ends_at: s.ends_at }))),
|
||||
dayBoundary,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Largeur (px) des tranches de 30 min d'une journée, en fonction de leur
|
||||
* nombre : une journée courte (peu de tranches) reste lisible en large,
|
||||
@@ -247,9 +168,8 @@ export function columnWidthPx(slotsInDay: number): number {
|
||||
// --------------------------------------------------------------------------- //
|
||||
// Grille des besoins : une colonne = 30 min (§ 4 CLAUDE.md). Les créneaux, //
|
||||
// eux, gardent des horaires libres (voir `ShiftCreate`) — ils sont replacés //
|
||||
// dans cette grille fixe en fusionnant les cases qu'ils couvrent. //
|
||||
// (Distinct de `buildLattice` ci-dessus, gardé pour la « Vue bénévoles », //
|
||||
// une colonne par créneau distinct plutôt qu'un axe temporel continu.) //
|
||||
// dans cette grille fixe en fusionnant les cases qu'ils couvrent. Même axe //
|
||||
// pour la « Vue par bénévole » (`VolunteerViewPage.tsx`). //
|
||||
// --------------------------------------------------------------------------- //
|
||||
const TIME_GRID_SLOT_MINUTES = 30;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user