diff --git a/web-frontend/src/app/shift-counts/page.tsx b/web-frontend/src/app/shift-counts/page.tsx
index 8b2ecd05..fbd72987 100644
--- a/web-frontend/src/app/shift-counts/page.tsx
+++ b/web-frontend/src/app/shift-counts/page.tsx
@@ -520,7 +520,7 @@ export default function ShiftCountsPage() {
People:{' '}
- {shiftCount.person.join(', ')}
+ {(Array.isArray(shiftCount.person) ? shiftCount.person : [shiftCount.person]).join(', ')}
Expression: {shiftCount.expression.replace('T', shiftCount.target.toString())}
@@ -530,11 +530,11 @@ export default function ShiftCountsPage() {
Count Dates:{' '}
- {shiftCount.countDates.join(', ')}
+ {(Array.isArray(shiftCount.countDates) ? shiftCount.countDates : [shiftCount.countDates]).join(', ')}
Count Shift Types:{' '}
- {shiftCount.countShiftTypes.join(', ')}
+ {(Array.isArray(shiftCount.countShiftTypes) ? shiftCount.countShiftTypes : [shiftCount.countShiftTypes]).join(', ')}
>
diff --git a/web-frontend/src/hooks/useSchedulingData.ts b/web-frontend/src/hooks/useSchedulingData.ts
index b3f2d494..41c63eed 100644
--- a/web-frontend/src/hooks/useSchedulingData.ts
+++ b/web-frontend/src/hooks/useSchedulingData.ts
@@ -1171,17 +1171,29 @@ export function useSchedulingData() {
convertIdsToString(newState.people.groups);
convertIdsToString(newState.shiftTypes.items);
convertIdsToString(newState.shiftTypes.groups);
- const convertArrayIdsToString = (arr: (number | string)[], isDate: boolean = false) => {
- if (!Array.isArray(arr)) return;
+ // Coerce a preference field into an array of strings. Handles the case
+ // where persisted/loaded data has a single scalar value (string/number)
+ // instead of the array shape declared by the TypeScript types, which
+ // would otherwise cause runtime errors like `.join is not a function`
+ // in renderers that trust the declared array type.
+ const normalizePrefArray =