Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/teachers-module/pages/SubjectSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ interface CurriculumWithCourses {
courses: TableTypes<'course'>[];
}

const SUBJECT_MODIFICATION_ROLES = [
RoleType.SUPER_ADMIN,
RoleType.OPERATIONAL_DIRECTOR,
RoleType.PROGRAM_MANAGER,
RoleType.FIELD_COORDINATOR,
];

const SubjectSelection: React.FC = () => {
const [curriculumsWithCourses, setCurriculumsWithCourses] = useState<
CurriculumWithCourses[]
Expand Down Expand Up @@ -118,8 +125,14 @@ const SubjectSelection: React.FC = () => {
!currentSchool?.id ||
!selectedSchoolId ||
currentSchool.id === selectedSchoolId;
setCanModify(schoolMatches && normalizedRole === RoleType.PRINCIPAL);
}, [currentSchool?.id, paramSchoolId, roleMap]);
const hasSubjectModificationRole = SUBJECT_MODIFICATION_ROLES.some((role) =>
roles.includes(role),
);
Comment on lines +128 to +130

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using roles.includes(role) directly can throw a TypeError if roles is undefined or null. Since roles is retrieved from the Redux store and might not be immediately available (as indicated by the defensive check const userRoles = roles || [] on line 99), we should use optional chaining roles?.includes(role) to prevent potential runtime crashes.

Suggested change
const hasSubjectModificationRole = SUBJECT_MODIFICATION_ROLES.some((role) =>
roles.includes(role),
);
const hasSubjectModificationRole = SUBJECT_MODIFICATION_ROLES.some((role) =>
roles?.includes(role),
);

setCanModify(
schoolMatches &&
(normalizedRole === RoleType.PRINCIPAL || hasSubjectModificationRole),
Comment on lines +131 to +133

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow ops roles to bypass school matching

When an ops user opens a school's subjects from the school list, DetailList.handleSubjectIconClick navigates with only { schoolId } and does not update Util.getCurrentSchool(). If the user previously had another school selected, currentSchool.id becomes the target school after the fetch while selectedSchoolId remains stale, so this schoolMatches && ... gate still hides the Add button even though hasSubjectModificationRole is true. I inspected the ManageSchools/DetailList flow; this keeps the button missing for ops users browsing a different school than the one currently stored.

Useful? React with 👍 / 👎.

);
}, [currentSchool?.id, paramSchoolId, roleMap, roles]);

const fetchCurriculumsAndCourses = async (
context: 'school' | 'class',
Expand Down
Loading