Registering or editing a driver with a transponder already assigned to a different driver (e.g. a wrong-class typo) previously saved silently - the only symptom was that driver's laps never registering during their heat, with no indication why. Now a confirm dialog names the conflicting driver and their class before saving; the same person's own multiple class entries sharing one physical transponder are correctly never flagged. Also confirms two things the user asked to verify: the race clock already counts down for all timed session types (only open practice counts up unbounded), and a driver not entered in a heat already has their laps fully discarded rather than recorded - both were already correct, no changes needed there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
63 lines
2.8 KiB
JavaScript
63 lines
2.8 KiB
JavaScript
function normalizeProfileName(value) {
|
|
return String(value || "").trim().toLocaleLowerCase().replace(/\s+/g, " ");
|
|
}
|
|
|
|
export function getDriverProfileId(driver) {
|
|
const explicitId = String(driver?.profileId || "").trim();
|
|
if (explicitId) return explicitId;
|
|
const legacyName = normalizeProfileName(driver?.name);
|
|
return legacyName ? `legacy:${legacyName}` : `driver:${String(driver?.id || "unknown")}`;
|
|
}
|
|
|
|
export function getDriverProfileGroups(state) {
|
|
const groups = new Map();
|
|
(Array.isArray(state?.drivers) ? state.drivers : []).forEach((driver) => {
|
|
const profileId = getDriverProfileId(driver);
|
|
const group = groups.get(profileId) || { id: profileId, drivers: [] };
|
|
group.drivers.push(driver);
|
|
groups.set(profileId, group);
|
|
});
|
|
|
|
return [...groups.values()].map((group) => ({
|
|
...group,
|
|
representative: group.drivers.find((driver) => String(driver.id || "") === group.id) || group.drivers[0] || null,
|
|
club: String(group.drivers.find((driver) => String(driver.club || "").trim())?.club || "").trim(),
|
|
country: String(group.drivers.find((driver) => String(driver.country || "").trim())?.country || "").trim(),
|
|
driverIds: group.drivers.map((driver) => String(driver.id || "")).filter(Boolean),
|
|
classIds: [...new Set(group.drivers.map((driver) => String(driver.classId || "")).filter(Boolean))],
|
|
}));
|
|
}
|
|
|
|
export function getDriverProfile(state, reference) {
|
|
const normalizedReference = String(reference || "");
|
|
return getDriverProfileGroups(state).find((group) => (
|
|
group.id === normalizedReference
|
|
|| group.driverIds.includes(normalizedReference)
|
|
)) || null;
|
|
}
|
|
|
|
export function getDriverProfileReferences(state, reference) {
|
|
const profile = getDriverProfile(state, reference);
|
|
const references = new Set([String(reference || "")].filter(Boolean));
|
|
if (!profile) return references;
|
|
references.add(profile.id);
|
|
profile.driverIds.forEach((driverId) => references.add(driverId));
|
|
return references;
|
|
}
|
|
|
|
// A transponder is one physical chip, so the same value legitimately repeats across a
|
|
// single person's own multi-class driver entries (same profile) - that is not a
|
|
// conflict. It only means something went wrong when it also shows up on a driver
|
|
// belonging to a DIFFERENT profile, since two different people can't share one chip:
|
|
// most often a typo at registration that quietly grabbed someone else's transponder.
|
|
export function findTransponderConflict(drivers, { transponder, profileId, excludeDriverId } = {}) {
|
|
const value = String(transponder || "").trim();
|
|
if (!value) return null;
|
|
const list = Array.isArray(drivers) ? drivers : [];
|
|
return list.find((driver) => (
|
|
String(driver.id || "") !== String(excludeDriverId || "")
|
|
&& String(driver.transponder || "").trim() === value
|
|
&& getDriverProfileId(driver) !== String(profileId || "")
|
|
)) || null;
|
|
}
|