Skip to content

Commit dafb5ba

Browse files
committed
Update featuredCompetitors list when assignments are changed
1 parent 9e87d51 commit dafb5ba

File tree

1 file changed

+186
-74
lines changed

1 file changed

+186
-74
lines changed

src/store/reducers/competitorAssignments.ts

Lines changed: 186 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import {
44
upsertAssignmentsOnPerson,
55
} from '../../lib/domain/persons';
66
import { mapIn, updateIn } from '../../lib/utils/utils';
7+
import {
8+
getGroupifierActivityConfig,
9+
setGroupifierActivityConfig,
10+
} from '../../lib/wcif/extensions/groupifier';
711
import { validateWcif } from '../../lib/wcif/validation';
812
import {
913
type AddPersonAssignmentsPayload,
@@ -14,7 +18,7 @@ import {
1418
type UpsertPersonAssignmentsPayload,
1519
} from '../actions';
1620
import { type AppState } from '../initialState';
17-
import type { Assignment, Person } from '@wca/helpers';
21+
import type { Activity, Assignment, Competition, Person } from '@wca/helpers';
1822

1923
const determineErrors = (state: AppState): AppState => {
2024
if (!state.wcif) return state;
@@ -24,6 +28,77 @@ const determineErrors = (state: AppState): AppState => {
2428
};
2529
};
2630

31+
/**
32+
* Removes a person from featuredCompetitors for all activities where they don't have
33+
* a competitor assignment. This ensures featuredCompetitors stays in sync with actual
34+
* competitor assignments.
35+
*
36+
* @param wcif - The WCIF object to clean up
37+
* @param registrantId - The registrant ID of the person to clean up
38+
* @returns Updated WCIF with cleaned featuredCompetitors
39+
*/
40+
const fixFeaturedCompetitors = (wcif: Competition, registrantId: number): Competition => {
41+
const person = wcif.persons.find((p) => p.registrantId === registrantId);
42+
if (!person?.wcaUserId) {
43+
return wcif;
44+
}
45+
46+
const wcaUserId = person.wcaUserId;
47+
48+
// Get all activity IDs where this person has a competitor assignment
49+
const competitorActivityIds = new Set(
50+
person.assignments?.filter((a) => a.assignmentCode === 'competitor').map((a) => a.activityId) ||
51+
[]
52+
);
53+
54+
const updateFeaturedCompetitors = (activity: Activity): Activity => {
55+
const config = getGroupifierActivityConfig(activity);
56+
if (!config?.featuredCompetitorWcaUserIds) {
57+
return activity;
58+
}
59+
60+
// Check if person should be removed from this activity's featuredCompetitors
61+
const isFeatured = config.featuredCompetitorWcaUserIds.includes(wcaUserId);
62+
const hasCompetitorAssignment = competitorActivityIds.has(activity.id);
63+
64+
// Remove from featured if they're listed but don't have a competitor assignment
65+
if (isFeatured && !hasCompetitorAssignment) {
66+
const updatedIds = config.featuredCompetitorWcaUserIds.filter((id) => id !== wcaUserId);
67+
68+
return setGroupifierActivityConfig(activity, {
69+
...config,
70+
featuredCompetitorWcaUserIds: updatedIds,
71+
});
72+
}
73+
74+
return activity;
75+
};
76+
77+
const newSchedule = updateIn(wcif.schedule, 'venues', (venues) =>
78+
venues.map((venue) =>
79+
updateIn(venue, 'rooms', (rooms) =>
80+
rooms.map((room) =>
81+
updateIn(room, 'activities', (activities) =>
82+
activities.map((activity) => {
83+
return {
84+
...updateFeaturedCompetitors(activity),
85+
childActivities: activity.childActivities.map((childActivity) =>
86+
updateFeaturedCompetitors(childActivity)
87+
),
88+
};
89+
})
90+
)
91+
)
92+
)
93+
)
94+
);
95+
96+
return {
97+
...wcif,
98+
schedule: newSchedule,
99+
};
100+
};
101+
27102
export const addPersonAssignments = (
28103
state: AppState,
29104
action: AddPersonAssignmentsPayload
@@ -44,36 +119,44 @@ export const addPersonAssignments = (
44119
export const removePersonAssignments = (
45120
state: AppState,
46121
action: RemovePersonAssignmentsPayload
47-
): AppState =>
48-
determineErrors({
122+
): AppState => {
123+
if (!state.wcif) return state;
124+
125+
let updatedWcif: Competition = mapIn(state.wcif, 'persons', (p) =>
126+
p.registrantId === action.registrantId ? removeAssignmentsFromPerson(p, action.activityId) : p
127+
);
128+
129+
updatedWcif = fixFeaturedCompetitors(updatedWcif, action.registrantId);
130+
131+
return determineErrors({
49132
...state,
50133
needToSave: true,
51134
changedKeys: new Set([...state.changedKeys, 'persons']),
52-
wcif:
53-
state.wcif &&
54-
mapIn(state.wcif, 'persons', (person) =>
55-
person.registrantId === action.registrantId
56-
? removeAssignmentsFromPerson(person, action.activityId)
57-
: person
58-
),
135+
wcif: updatedWcif,
59136
});
137+
};
60138

61139
export const upsertPersonAssignments = (
62140
state: AppState,
63141
action: UpsertPersonAssignmentsPayload
64-
): AppState =>
65-
determineErrors({
142+
): AppState => {
143+
if (!state.wcif) return determineErrors(state);
144+
145+
let updatedWcif: Competition = mapIn(state.wcif, 'persons', (person) =>
146+
person.registrantId === action.registrantId
147+
? upsertAssignmentsOnPerson(person, action.assignments)
148+
: person
149+
);
150+
151+
updatedWcif = fixFeaturedCompetitors(updatedWcif, action.registrantId);
152+
153+
return determineErrors({
66154
...state,
67155
needToSave: true,
68156
changedKeys: new Set([...state.changedKeys, 'persons']),
69-
wcif:
70-
state.wcif &&
71-
mapIn(state.wcif, 'persons', (person) =>
72-
person.registrantId === action.registrantId
73-
? upsertAssignmentsOnPerson(person, action.assignments)
74-
: person
75-
),
157+
wcif: updatedWcif,
76158
});
159+
};
77160

78161
/**
79162
* @param {*} state
@@ -112,70 +195,99 @@ export const bulkAddPersonAssignments = (
112195
export const bulkRemovePersonAssignments = (
113196
state: AppState,
114197
action: BulkRemovePersonAssignmentsPayload
115-
): AppState =>
116-
determineErrors({
198+
): AppState => {
199+
if (!state.wcif) return state;
200+
201+
// Track registrant IDs that had assignments removed
202+
const affectedRegistrantIds = new Set<number>();
203+
204+
let updatedWcif: Competition = mapIn(state.wcif, 'persons', (person) => {
205+
if (person.assignments?.length === 0 || !person.assignments) {
206+
return person;
207+
}
208+
209+
// Find arguments to keep assignment: that is, return true
210+
return updateIn(person, 'assignments', (assignments) =>
211+
assignments?.filter((personAssignment: Assignment) => {
212+
const filtersApplicable = action.assignments.filter((a) => {
213+
const filterByRegistrantId = a.registrantId
214+
? a.registrantId === person.registrantId
215+
: null;
216+
const filterByActivityId = a.activityId
217+
? a.activityId === personAssignment.activityId
218+
: null;
219+
const filterByAssignmentCode = a.assignmentCode
220+
? a.assignmentCode === personAssignment.assignmentCode
221+
: null;
222+
223+
// return true if any filter is applicable
224+
// We are looking for at least 1 false. If so, return no applicable filters
225+
return !(
226+
filterByRegistrantId === false ||
227+
filterByActivityId === false ||
228+
filterByAssignmentCode === false
229+
); // note do actually want these values to be "false" and not "null"
230+
});
231+
232+
const isBeingRemoved = filtersApplicable.length > 0;
233+
234+
if (isBeingRemoved) {
235+
affectedRegistrantIds.add(person.registrantId);
236+
}
237+
238+
// At least 1 filter is filtering them out
239+
return !isBeingRemoved;
240+
})
241+
);
242+
});
243+
244+
// Clean up featuredCompetitors for all affected persons
245+
for (const registrantId of affectedRegistrantIds) {
246+
updatedWcif = fixFeaturedCompetitors(updatedWcif, registrantId);
247+
}
248+
249+
return determineErrors({
117250
...state,
118251
needToSave: true,
119252
changedKeys: new Set([...state.changedKeys, 'persons']),
120-
wcif:
121-
state.wcif &&
122-
mapIn(state.wcif, 'persons', (person) => {
123-
if (person.assignments?.length === 0 || !person.assignments) {
124-
return person;
125-
}
126-
127-
// Find arguments to keep assignment: that is, return true
128-
return updateIn(person, 'assignments', (assignments) =>
129-
assignments?.filter((personAssignment: Assignment) => {
130-
const filtersApplicable = action.assignments.filter((a) => {
131-
const filterByRegistrantId = a.registrantId
132-
? a.registrantId === person.registrantId
133-
: null;
134-
const filterByActivityId = a.activityId
135-
? a.activityId === personAssignment.activityId
136-
: null;
137-
const filterByAssignmentCode = a.assignmentCode
138-
? a.assignmentCode === personAssignment.assignmentCode
139-
: null;
140-
141-
// return true if any filter is applicable
142-
// We are looking for at least 1 false. If so, return no applicable filters
143-
return !(
144-
filterByRegistrantId === false ||
145-
filterByActivityId === false ||
146-
filterByAssignmentCode === false
147-
); // note do actually want these values to be "false" and not "null"
148-
});
149-
150-
// At least 1 filter is filtering them out
151-
return filtersApplicable.length === 0;
152-
})
153-
);
154-
}),
253+
wcif: updatedWcif,
155254
});
255+
};
156256

157257
export const bulkUpsertPersonAssignments = (
158258
state: AppState,
159259
action: BulkUpsertPersonAssignmentsPayload
160-
): AppState =>
161-
determineErrors({
260+
): AppState => {
261+
if (!state.wcif) return determineErrors(state);
262+
263+
// Track registrant IDs that had assignments updated
264+
const affectedRegistrantIds = new Set<number>();
265+
266+
let updatedWcif: Competition = mapIn(state.wcif, 'persons', (person: Person) => {
267+
const personAssignments = action.assignments
268+
.filter((a) => a.registrantId === person.registrantId)
269+
.map((a) => ({
270+
...a.assignment,
271+
activityId: a.assignment.activityId,
272+
}));
273+
274+
if (personAssignments.length > 0) {
275+
affectedRegistrantIds.add(person.registrantId);
276+
return upsertAssignmentsOnPerson(person, personAssignments);
277+
}
278+
279+
return person;
280+
});
281+
282+
// Clean up featuredCompetitors for all affected persons
283+
for (const registrantId of affectedRegistrantIds) {
284+
updatedWcif = fixFeaturedCompetitors(updatedWcif, registrantId);
285+
}
286+
287+
return determineErrors({
162288
...state,
163289
needToSave: true,
164290
changedKeys: new Set([...state.changedKeys, 'persons']),
165-
wcif:
166-
state.wcif &&
167-
mapIn(state.wcif, 'persons', (person: Person) => {
168-
const personAssignments = action.assignments
169-
.filter((a) => a.registrantId === person.registrantId)
170-
.map((a) => ({
171-
...a.assignment,
172-
activityId: a.assignment.activityId,
173-
}));
174-
175-
if (personAssignments.length > 0) {
176-
return upsertAssignmentsOnPerson(person, personAssignments);
177-
}
178-
179-
return person;
180-
}),
291+
wcif: updatedWcif,
181292
});
293+
};

0 commit comments

Comments
 (0)