Écrans bénévole et référent redessinés, messages aux bénévoles
Étape 55 : écrans /mobile-benevole et /mobile-referent d'après la maquette (design/Planning bénévole mobile) — créneau en cours ou prochain mis en avant, planning par journée de festival avec frise horaire, compteurs et pointage du référent par créneau. Étape 56 : message de l'organisation (Edition.volunteer_message, onglet « Message aux bénévoles ») et message de chaque poste (Position.message, saisi par le référent), migration 0029, affichés sur l'écran bénévole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4a3f93e137
commit
16d8fb44a7
@@ -44,6 +44,7 @@ import type {
|
||||
VolunteerRead,
|
||||
EditionStats,
|
||||
} from '../schema';
|
||||
import { MESSAGE_MAX_LENGTH } from '../schema';
|
||||
import { getAuthToken } from '../session';
|
||||
import { ApiError, type PlanningApi } from '../types';
|
||||
import { buildMockState, type MockPendingSubmission, type MockState } from './dataset';
|
||||
@@ -836,6 +837,14 @@ function runSolver(): SolverRunResult {
|
||||
};
|
||||
}
|
||||
|
||||
/** Message (organisation, poste) comme l'API : bords retirés, vide = plus
|
||||
* de message, 2000 caractères au plus. */
|
||||
function checkMessage(value: string | null | undefined): string | null {
|
||||
const text = (value ?? '').trim() || null;
|
||||
if (text && text.length > MESSAGE_MAX_LENGTH) throw new ApiError(422, 'error.generic');
|
||||
return text;
|
||||
}
|
||||
|
||||
export function createMockApi(): PlanningApi {
|
||||
return {
|
||||
editions: {
|
||||
@@ -847,6 +856,13 @@ export function createMockApi(): PlanningApi {
|
||||
if (body.start_date) next.start_date = body.start_date;
|
||||
if (body.end_date) next.end_date = body.end_date;
|
||||
if ('retention_days' in body) next.retention_days = body.retention_days ?? null;
|
||||
if ('volunteer_message' in body) {
|
||||
const text = checkMessage(body.volunteer_message);
|
||||
if (text !== next.volunteer_message) {
|
||||
next.volunteer_message = text;
|
||||
next.volunteer_message_updated_at = text ? touch() : null;
|
||||
}
|
||||
}
|
||||
if (next.end_date < next.start_date) {
|
||||
throw new ApiError(422, 'edition.dates_inconsistent');
|
||||
}
|
||||
@@ -1124,6 +1140,8 @@ export function createMockApi(): PlanningApi {
|
||||
position_location: position?.location ?? null,
|
||||
referent_name: referent ? `${referent.first_name} ${referent.last_name}` : null,
|
||||
referent_phone: referent?.phone ?? null,
|
||||
position_message: position?.message ?? null,
|
||||
position_message_updated_at: position?.message_updated_at ?? null,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.starts_at.localeCompare(b.starts_at));
|
||||
@@ -1384,6 +1402,8 @@ export function createMockApi(): PlanningApi {
|
||||
location: body.location ?? null,
|
||||
category: body.category,
|
||||
lead_account_id: body.lead_account_id ?? null,
|
||||
message: null,
|
||||
message_updated_at: null,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
};
|
||||
@@ -1395,6 +1415,13 @@ export function createMockApi(): PlanningApi {
|
||||
update: (_edition, id, body) => {
|
||||
const p = state.positions.find((x) => x.id === id) ?? notFound();
|
||||
if ('lead_account_id' in body) checkLeadAccount(body.lead_account_id);
|
||||
if ('message' in body) {
|
||||
const text = checkMessage(body.message);
|
||||
if (text !== p.message) {
|
||||
p.message = text;
|
||||
p.message_updated_at = text ? touch() : null;
|
||||
}
|
||||
}
|
||||
Object.assign(p, {
|
||||
...('name' in body ? { name: body.name } : {}),
|
||||
...('location' in body ? { location: body.location ?? null } : {}),
|
||||
|
||||
Reference in New Issue
Block a user