Fix Team Race duplicate-membership bug and two related team-roster gaps
Reported by the user: creating a team, adding the wrong driver, then moving that driver to another team by ticking them on the new team's edit form left the driver on both teams at once. Root cause: there was never a "move" action - the edit form only ever added a driver to the team being saved, never removed them from wherever they already were. Live laps from a driver on two teams were then silently credited to only the first-matching team, with no clear error. reassignTeamMembers (event_race_logic.js) now strips a driver/car being saved onto one team out of every other team in the same event, and the team checkbox list shows which team a driver is already on before you move them. Also fixed two related gaps found while investigating, at the user's request to fix everything: getTeamDriverPool had regressed to ignoring the event's class/participant scoping entirely (showing every driver in the club), and deleting a driver or car left them behind in team rosters forever. Added a duplicate_team_members Race Day preflight check as defense in depth for any already-corrupted saved state. Verified with new unit tests for reassignTeamMembers, getTeamDriverPool and the new preflight check, plus a new permanent browser test reproducing the user's exact reported scenario end to end. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -560,10 +560,36 @@ export function getEventTeams(event, { normalizeRaceTeam }) {
|
||||
|
||||
|
||||
export function getTeamDriverPool(event, { getEventDrivers, state }) {
|
||||
return {
|
||||
drivers: Array.isArray(state?.drivers) ? [...state.drivers] : [],
|
||||
fallback: false,
|
||||
};
|
||||
const scopedDrivers = getEventDrivers(event);
|
||||
if (scopedDrivers.length) {
|
||||
return { drivers: scopedDrivers, fallback: false };
|
||||
}
|
||||
// No driver matched the event's class or configured participant list (e.g. a team is
|
||||
// being set up before drivers/participants exist yet) - fall back to every driver in
|
||||
// the club rather than leaving the admin with zero checkboxes and no way to proceed.
|
||||
const allDrivers = Array.isArray(state?.drivers) ? [...state.drivers] : [];
|
||||
return { drivers: allDrivers, fallback: allDrivers.length > 0 };
|
||||
}
|
||||
|
||||
|
||||
|
||||
// A driver or car can only be a member of one team at a time. There is no separate "move
|
||||
// to another team" action in the UI - ticking a driver's checkbox on a different team's
|
||||
// form IS the move - so saving a team's roster here must pull that driver/car out of
|
||||
// whichever other team currently has them, or the same driver ends up listed on two teams
|
||||
// at once (their live passings then get silently credited to only the first match).
|
||||
export function reassignTeamMembers(teams, { excludeTeamId = "", driverIds = [], carIds = [] } = {}) {
|
||||
const driverSet = new Set(driverIds);
|
||||
const carSet = new Set(carIds);
|
||||
return (Array.isArray(teams) ? teams : []).map((team) => {
|
||||
if (team.id === excludeTeamId) return team;
|
||||
const nextDriverIds = (team.driverIds || []).filter((id) => !driverSet.has(id));
|
||||
const nextCarIds = (team.carIds || []).filter((id) => !carSet.has(id));
|
||||
if (nextDriverIds.length === (team.driverIds || []).length && nextCarIds.length === (team.carIds || []).length) {
|
||||
return team;
|
||||
}
|
||||
return { ...team, driverIds: nextDriverIds, carIds: nextCarIds };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user