Créneaux à la main + grille des besoins en axe des temps (30 min)
Un poste ne génère plus de créneaux à sa création : la coordination crée elle-même ceux dont elle a besoin, avec ses propres horaires de début et de fin (ConfigGrid.tsx). La génération depuis les créneaux types reste disponible en option (bouton « Générer les créneaux »). La grille des besoins devient un vrai axe des temps : une colonne = 30 min, bornée par jour à la plage réellement utilisée, avec les cases fusionnées pour correspondre aux horaires de chaque créneau (buildTimeGrid / placeInTimeGrid). La « Vue bénévoles » garde son ancien modèle (une colonne par créneau distinct), plus adapté à son tableau bénévole × créneau. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
f1d88302a4
commit
15109acfe5
@@ -18,6 +18,7 @@ import type { AccountRead } from '@/api/schema';
|
||||
import { queryKeys } from '@/api/hooks';
|
||||
import { AuthContext, AuthProvider, type AuthContextValue } from '@/auth/auth-context';
|
||||
import { routes } from '@/app/router';
|
||||
import { buildTimeGrid, placeInTimeGrid } from '@/lib/planning';
|
||||
import { BadgesPage } from '@/pages/BadgesPage';
|
||||
import { ConfigPage } from '@/pages/ConfigPage';
|
||||
import { FormBuilderPage } from '@/pages/FormBuilderPage';
|
||||
@@ -181,6 +182,57 @@ async function checkPositionSheets() {
|
||||
);
|
||||
}
|
||||
|
||||
/** Créneaux (mode mock) : un poste créé ne génère plus aucun créneau ; la
|
||||
* création manuelle à horaires libres fonctionne toujours ; « générer les
|
||||
* créneaux » (créneaux types) reste disponible en option ; un créneau à
|
||||
* horaires non alignés (19:15–22:45) se place bien dans la grille demi-heure
|
||||
* (`buildTimeGrid`/`placeInTimeGrid`), arrondi à la tranche englobante. */
|
||||
async function checkShiftCreation() {
|
||||
const position = await api.positions.create(e, { name: 'Smoke poste', category: 'OTHER' });
|
||||
const shiftsAfterCreate = await api.shifts.list(e, { positionId: position.id });
|
||||
|
||||
const edition = await api.editions.get(e);
|
||||
const shift = await api.shifts.create(e, {
|
||||
position_id: position.id,
|
||||
starts_at: `${edition.start_date}T19:15:00`,
|
||||
ends_at: `${edition.start_date}T22:45:00`,
|
||||
min_staff: 1,
|
||||
ideal_staff: 2,
|
||||
});
|
||||
const generated = await api.positions.generateShifts(e, position.id);
|
||||
|
||||
const grid = buildTimeGrid([shift]);
|
||||
const day = grid[0];
|
||||
const placement = day ? placeInTimeGrid(grid, [shift]).get(day.date)?.[0] : undefined;
|
||||
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{
|
||||
shiftsAfterPositionCreate: shiftsAfterCreate.length,
|
||||
manualShiftTimes: `${shift.starts_at}–${shift.ends_at}`,
|
||||
generateShiftsStillOptIn: generated.created,
|
||||
gridSlotCount: day?.slotLabels.length,
|
||||
gridFirstSlot: day?.slotLabels[0],
|
||||
placementSpan: placement?.columnSpan,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
if (shiftsAfterCreate.length !== 0) {
|
||||
throw new Error('création de poste : ne devrait générer aucun créneau automatiquement');
|
||||
}
|
||||
if (generated.created <= 0) {
|
||||
throw new Error('generate-shifts : devrait rester disponible en option');
|
||||
}
|
||||
// 19:15–22:45 (3 h 30) arrondi aux tranches de 30 min englobantes
|
||||
// (19:00–23:00) = 8 tranches.
|
||||
if (day?.slotLabels[0] !== '19:00' || placement?.columnSpan !== 8) {
|
||||
throw new Error('grille demi-heure : placement inattendu pour un créneau non aligné');
|
||||
}
|
||||
}
|
||||
|
||||
async function prefetchCore(client: QueryClient) {
|
||||
await Promise.all([
|
||||
client.prefetchQuery({ queryKey: queryKeys.volunteers, queryFn: () => api.volunteers.list(e) }),
|
||||
@@ -250,6 +302,7 @@ function renderPublic(path: string) {
|
||||
await checkAuth().catch((err) => fail('checkAuth', err));
|
||||
await checkPublicForm().catch((err) => fail('checkPublicForm', err));
|
||||
await checkPositionSheets().catch((err) => fail('checkPositionSheets', err));
|
||||
await checkShiftCreation().catch((err) => fail('checkShiftCreation', err));
|
||||
|
||||
renderPublic('/connexion');
|
||||
renderPublic('/connexion/coordination');
|
||||
|
||||
Reference in New Issue
Block a user