diff --git a/src/features/Classes/Class/ClassPage/Actions.jsx b/src/features/Classes/Class/ClassPage/Actions.jsx index ac2d62c3..8e19a96d 100644 --- a/src/features/Classes/Class/ClassPage/Actions.jsx +++ b/src/features/Classes/Class/ClassPage/Actions.jsx @@ -18,7 +18,7 @@ import EnrollStudent from 'features/Classes/EnrollStudent'; const Actions = ({ previousPage }) => { const location = useLocation(); const history = useHistory(); - const { courseId, classId } = useParams(); + const { courseName, className } = useParams(); const classes = useSelector((state) => state.classes.allClasses.data); const queryParams = new URLSearchParams(location.search); @@ -35,7 +35,7 @@ const Actions = ({ previousPage }) => { const handleEnrollStudentModal = () => setIsEnrollModalOpen(!isEnrollModalOpen); const handleManageButton = () => { - history.push(`/manage-instructors/${courseId}/${classId}?classId=${queryClassId}&previous=${previousPage}`); + history.push(`/manage-instructors/${courseName}/${className}?classId=${queryClassId}&previous=${previousPage}`); }; return ( @@ -49,7 +49,7 @@ const Actions = ({ previousPage }) => { -

Class details: {classId}

+

Class details: {classNameDecoded}

diff --git a/src/features/Classes/ClassesTable/columns.jsx b/src/features/Classes/ClassesTable/columns.jsx index 2062c6c8..34ce2193 100644 --- a/src/features/Classes/ClassesTable/columns.jsx +++ b/src/features/Classes/ClassesTable/columns.jsx @@ -22,7 +22,7 @@ const columns = [ accessor: 'className', Cell: ({ row }) => ( {row.values.className} @@ -125,7 +125,7 @@ const columns = [ diff --git a/src/features/Classes/EnrollStudent/__test__/index.test.jsx b/src/features/Classes/EnrollStudent/__test__/index.test.jsx index 039f4de4..bca7cfc7 100644 --- a/src/features/Classes/EnrollStudent/__test__/index.test.jsx +++ b/src/features/Classes/EnrollStudent/__test__/index.test.jsx @@ -6,7 +6,7 @@ import '@testing-library/jest-dom/extend-expect'; import EnrollStudent from 'features/Classes/EnrollStudent'; jest.mock('react-router-dom', () => ({ - useParams: jest.fn(() => ({ courseId: 'Demo course', classId: 'demo class' })), + useParams: jest.fn(() => ({ courseName: 'Demo course', className: 'demo class' })), useLocation: jest.fn().mockReturnValue({ search: '?classId=demo class' }), })); diff --git a/src/features/Classes/EnrollStudent/index.jsx b/src/features/Classes/EnrollStudent/index.jsx index 3fe5cfc5..36bd99c7 100644 --- a/src/features/Classes/EnrollStudent/index.jsx +++ b/src/features/Classes/EnrollStudent/index.jsx @@ -26,10 +26,12 @@ const successToastMessage = 'Email invite has been sent successfully'; const EnrollStudent = ({ isOpen, onClose, queryClassId }) => { const dispatch = useDispatch(); - const { courseId, classId } = useParams(); + const { courseName, className } = useParams(); const [showToast, setShowToast] = useState(false); const [isLoading, setLoading] = useState(false); const institution = useSelector((state) => state.main.selectedInstitution); + const courseNameDecoded = decodeURIComponent(courseName); + const classNameDecoded = decodeURIComponent(className); const handleEnrollStudent = async (e) => { e.preventDefault(); @@ -48,15 +50,15 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => { await handleEnrollments(formData, queryClassId); const params = { - course_name: courseId, - class_name: classId, + course_name: courseNameDecoded, + class_name: classNameDecoded, limit: true, }; dispatch(fetchStudentsData(institution.id, initialPage, params)); // Get the classes info updated with the new number of students enrolled. - dispatch(fetchAllClassesData(institution.id, courseId)); + dispatch(fetchAllClassesData(institution.id, courseNameDecoded)); setShowToast(true); onClose(); } catch (error) { @@ -82,7 +84,7 @@ const EnrollStudent = ({ isOpen, onClose, queryClassId }) => {

- Class: {classId} + Class: {classNameDecoded}

{isLoading && (
diff --git a/src/features/Classes/InstructorCard/__test__/index.test.jsx b/src/features/Classes/InstructorCard/__test__/index.test.jsx index ac9956ef..65987da1 100644 --- a/src/features/Classes/InstructorCard/__test__/index.test.jsx +++ b/src/features/Classes/InstructorCard/__test__/index.test.jsx @@ -6,8 +6,8 @@ import InstructorCard from 'features/Classes/InstructorCard'; jest.mock('react-router-dom', () => ({ useParams: jest.fn(() => ({ - courseId: 'Demo course', - classId: 'demo class', + courseName: 'Demo course', + className: 'demo class', })), useLocation: jest.fn().mockReturnValue({ search: '?classId=demo+class' }), })); diff --git a/src/features/Classes/InstructorCard/index.jsx b/src/features/Classes/InstructorCard/index.jsx index ed808ba6..be216652 100644 --- a/src/features/Classes/InstructorCard/index.jsx +++ b/src/features/Classes/InstructorCard/index.jsx @@ -17,10 +17,12 @@ const INSTRUCTORS_NUMBER = 3; const InstructorCard = () => { const location = useLocation(); const dispatch = useDispatch(); - const { courseId, classId } = useParams(); + const { courseName, className } = useParams(); const institution = useSelector((state) => state.main.selectedInstitution); const instructors = useSelector((state) => state.instructors.selectOptions.data); const classes = useSelector((state) => state.classes.allClasses); + const courseNameDecoded = decodeURIComponent(courseName); + const classNameDecoded = decodeURIComponent(className); const queryParams = new URLSearchParams(location.search); const classIdQuery = queryParams.get('classId')?.replaceAll(' ', '+'); @@ -44,8 +46,8 @@ const InstructorCard = () => { return (
-

- {classId} +

+ {classNameDecoded}

{isLoadingClasses && (
@@ -58,8 +60,8 @@ const InstructorCard = () => { )} {!isLoadingClasses && ( <> -

- {courseId} +

+ {courseNameDecoded}

diff --git a/src/features/Courses/AddClass/_test_/index.test.jsx b/src/features/Courses/AddClass/_test_/index.test.jsx index d65687b2..5c391ee5 100644 --- a/src/features/Courses/AddClass/_test_/index.test.jsx +++ b/src/features/Courses/AddClass/_test_/index.test.jsx @@ -34,7 +34,7 @@ describe('Add class modal', () => { test('render add class modal', () => { const { getByText, getByPlaceholderText } = renderWithProviders( - + { }} courseInfo={courseInfoMocked} /> , @@ -68,7 +68,7 @@ describe('Add class modal', () => { test('cancel button in add classmodal', () => { const { getByText, getByPlaceholderText } = renderWithProviders( - + { }} courseInfo={courseInfoMocked} /> , diff --git a/src/features/Courses/AddClass/index.jsx b/src/features/Courses/AddClass/index.jsx index 26a61cbf..6d5b3544 100644 --- a/src/features/Courses/AddClass/index.jsx +++ b/src/features/Courses/AddClass/index.jsx @@ -23,7 +23,7 @@ import 'features/Courses/AddClass/index.scss'; const AddClass = ({ isOpen, onClose, courseInfo, isCoursePage, isEditing, isDetailClassPage, }) => { - const { courseId } = useParams(); + const { courseName } = useParams(); const dispatch = useDispatch(); const selectedInstitution = useSelector((state) => state.main.selectedInstitution); const instructorsList = useSelector((state) => state.instructors.selectOptions.data); @@ -37,6 +37,8 @@ const AddClass = ({ const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); + const courseNameDecoded = courseName ? decodeURIComponent(courseName) : ''; + const handleAddClass = async (e) => { e.preventDefault(); const form = e.target; @@ -59,9 +61,9 @@ const AddClass = ({ logError(error); } finally { if (isDetailClassPage) { - dispatch(fetchAllClassesData(selectedInstitution.id, courseId)); + dispatch(fetchAllClassesData(selectedInstitution.id, courseNameDecoded)); } else { - dispatch(fetchClassesData(selectedInstitution.id, initialPage, courseId)); + dispatch(fetchClassesData(selectedInstitution.id, initialPage, courseNameDecoded)); dispatch(updateClassesCurrentPage(initialPage)); } } @@ -85,7 +87,7 @@ const AddClass = ({ dispatch(fetchCoursesData(selectedInstitution.id, initialPage)); dispatch(updateCoursesCurrentPage(initialPage)); } else { - dispatch(fetchClassesData(selectedInstitution.id, initialPage, courseId)); + dispatch(fetchClassesData(selectedInstitution.id, initialPage, courseNameDecoded)); dispatch(updateClassesCurrentPage(initialPage)); } } diff --git a/src/features/Courses/CourseDetailTable/__test__/columns.test.jsx b/src/features/Courses/CourseDetailTable/__test__/columns.test.jsx index 2d1cbc0a..f8e980f6 100644 --- a/src/features/Courses/CourseDetailTable/__test__/columns.test.jsx +++ b/src/features/Courses/CourseDetailTable/__test__/columns.test.jsx @@ -63,7 +63,7 @@ describe('columns', () => { renderWithProviders( - + , @@ -157,7 +157,7 @@ describe('columns', () => { const component = renderWithProviders( - + , @@ -211,7 +211,7 @@ describe('columns', () => { const component = renderWithProviders( - + , @@ -256,7 +256,7 @@ describe('columns', () => { const component = renderWithProviders( - + , diff --git a/src/features/Courses/CourseDetailTable/columns.jsx b/src/features/Courses/CourseDetailTable/columns.jsx index 7abc52ce..4bb6224c 100644 --- a/src/features/Courses/CourseDetailTable/columns.jsx +++ b/src/features/Courses/CourseDetailTable/columns.jsx @@ -19,10 +19,10 @@ const columns = [ Header: 'Class', accessor: 'className', Cell: ({ row }) => { - const { courseId } = useParams(); + const { courseName } = useParams(); return ( {row.values.className} @@ -131,7 +131,7 @@ const columns = [ diff --git a/src/features/Courses/CoursesDetailPage/__test__/index.test.jsx b/src/features/Courses/CoursesDetailPage/__test__/index.test.jsx index 60745ab6..c52f78b9 100644 --- a/src/features/Courses/CoursesDetailPage/__test__/index.test.jsx +++ b/src/features/Courses/CoursesDetailPage/__test__/index.test.jsx @@ -80,7 +80,7 @@ describe('CoursesDetailPage', () => { test('Should render the table and the course info', async () => { const component = renderWithProviders( - + , diff --git a/src/features/Courses/CoursesDetailPage/index.jsx b/src/features/Courses/CoursesDetailPage/index.jsx index c330a340..eb1950a0 100644 --- a/src/features/Courses/CoursesDetailPage/index.jsx +++ b/src/features/Courses/CoursesDetailPage/index.jsx @@ -21,7 +21,8 @@ import 'features/Courses/CoursesDetailPage/index.scss'; const CoursesDetailPage = () => { const history = useHistory(); const dispatch = useDispatch(); - const { courseId } = useParams(); + const { courseName } = useParams(); + const courseNameDecoded = decodeURIComponent(courseName); const institutionRef = useRef(undefined); const [currentPage, setCurrentPage] = useState(initialPage); @@ -34,7 +35,7 @@ const CoursesDetailPage = () => { }), []); const courseInfo = useSelector((state) => state.courses.table.data) - .find((course) => course?.masterCourseName === courseId) || defaultCourseInfo; + .find((course) => course?.masterCourseName === courseNameDecoded) || defaultCourseInfo; const lastCourseInfoRef = useRef(courseInfo); useEffect(() => { @@ -62,7 +63,7 @@ const CoursesDetailPage = () => { }; if (institution.id) { - dispatch(fetchClassesData(institution.id, initialPage, courseId)); + dispatch(fetchClassesData(institution.id, initialPage, courseNameDecoded)); dispatch(fetchCoursesData(institution.id, initialPage, null)); } @@ -70,10 +71,10 @@ const CoursesDetailPage = () => { dispatch(fetchCoursesDataSuccess(initialState)); dispatch(fetchClassesDataSuccess(initialState)); }; - }, [dispatch, institution.id, courseId]); + }, [dispatch, institution.id, courseNameDecoded]); useEffect(() => { - dispatch(fetchClassesData(institution.id, currentPage, courseId)); + dispatch(fetchClassesData(institution.id, currentPage, courseNameDecoded)); }, [currentPage]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { @@ -93,7 +94,7 @@ const CoursesDetailPage = () => { -

{courseId}

+

{courseNameDecoded}

diff --git a/src/features/Courses/CoursesPage/_test_/index.test.jsx b/src/features/Courses/CoursesPage/_test_/index.test.jsx index 57ef600c..56f7b863 100644 --- a/src/features/Courses/CoursesPage/_test_/index.test.jsx +++ b/src/features/Courses/CoursesPage/_test_/index.test.jsx @@ -56,7 +56,7 @@ describe('CoursesPage', () => { it('renders courses data and pagination', async () => { const component = renderWithProviders( - + , diff --git a/src/features/Courses/CoursesTable/columns.jsx b/src/features/Courses/CoursesTable/columns.jsx index 5841271b..0a18fbb2 100644 --- a/src/features/Courses/CoursesTable/columns.jsx +++ b/src/features/Courses/CoursesTable/columns.jsx @@ -14,7 +14,7 @@ const columns = [ { Header: 'Courses', accessor: 'masterCourseName', - Cell: ({ row }) => ({row.values.masterCourseName}), + Cell: ({ row }) => ({row.values.masterCourseName}), }, { Header: 'Classes', diff --git a/src/features/Dashboard/InstructorAssignSection/ClassCard.jsx b/src/features/Dashboard/InstructorAssignSection/ClassCard.jsx index 3901d21b..5ae1abbd 100644 --- a/src/features/Dashboard/InstructorAssignSection/ClassCard.jsx +++ b/src/features/Dashboard/InstructorAssignSection/ClassCard.jsx @@ -12,7 +12,7 @@ const ClassCard = ({ data }) => { const history = useHistory(); const handleManageButton = () => { - history.push(`/manage-instructors/${data?.masterCourseName}/${data?.className}?classId=${data?.classId}&previous=dashboard`); + history.push(`/manage-instructors/${encodeURIComponent(data?.masterCourseName)}/${encodeURIComponent(data?.className)}?classId=${data?.classId}&previous=dashboard`); }; return ( diff --git a/src/features/Instructors/InstructorDetailTable/columns.jsx b/src/features/Instructors/InstructorDetailTable/columns.jsx index 48e87a3c..a02d6264 100644 --- a/src/features/Instructors/InstructorDetailTable/columns.jsx +++ b/src/features/Instructors/InstructorDetailTable/columns.jsx @@ -12,7 +12,7 @@ const columns = [ accessor: 'className', Cell: ({ row }) => ( {row.values.className} diff --git a/src/features/Instructors/ManageInstructors/columns.jsx b/src/features/Instructors/ManageInstructors/columns.jsx index 969a0fe6..133e84d1 100644 --- a/src/features/Instructors/ManageInstructors/columns.jsx +++ b/src/features/Instructors/ManageInstructors/columns.jsx @@ -24,7 +24,7 @@ const columns = [ return ( {diffHours < hoursDay && 'Today'} - {diffDays < daysWeek && `${diffDays} days ago`} + {diffDays < daysWeek && diffDays > 0 && `${diffDays} days ago`} {diffDays > daysWeek && `${diffWeeks} wks ago`} ); diff --git a/src/features/Instructors/ManageInstructors/index.jsx b/src/features/Instructors/ManageInstructors/index.jsx index edb83a0d..03a5dd4e 100644 --- a/src/features/Instructors/ManageInstructors/index.jsx +++ b/src/features/Instructors/ManageInstructors/index.jsx @@ -34,6 +34,8 @@ const ManageInstructors = () => { const previousPage = queryParams.get('previous') || 'courses'; const isLoadingInstructors = instructorsByClass?.status === RequestStatus.LOADING; const isButtonDisabled = rowsSelected.length === 0; + const courseNameDecoded = decodeURIComponent(courseName); + const classNameDecoded = decodeURIComponent(className); const resetValues = () => { cancelButtonRef?.current?.clearSelectionFunc(); @@ -82,7 +84,7 @@ const ManageInstructors = () => { dispatch(resetClassesTable()); dispatch(resetClasses()); }; - }, [dispatch, selectedInstitution.id, courseName, previousPage, classId]); + }, [dispatch, selectedInstitution.id, previousPage, classId]); return ( <> @@ -102,8 +104,8 @@ const ManageInstructors = () => {
-

{className}

-

{courseName}

+

{classNameDecoded}

+

{courseNameDecoded}

diff --git a/src/features/Licenses/LicenseDetailTable/columns.jsx b/src/features/Licenses/LicenseDetailTable/columns.jsx index 2465ff9a..d29e7a14 100644 --- a/src/features/Licenses/LicenseDetailTable/columns.jsx +++ b/src/features/Licenses/LicenseDetailTable/columns.jsx @@ -6,7 +6,7 @@ const columns = [ Header: 'Course', accessor: 'masterCourseName', Cell: ({ row }) => ( - {row.values.masterCourseName} + {row.values.masterCourseName} ), }, { diff --git a/src/features/Main/index.jsx b/src/features/Main/index.jsx index e378cac1..6ece9781 100644 --- a/src/features/Main/index.jsx +++ b/src/features/Main/index.jsx @@ -59,8 +59,8 @@ const Main = () => { { path: '/instructors', component: InstructorsPage, exact: true }, { path: '/instructors/:instructorUsername', component: InstructorsDetailPage, exact: true }, { path: '/courses', component: CoursesPage, exact: true }, - { path: '/courses/:courseId', component: CoursesDetailPage, exact: true }, - { path: '/courses/:courseId/:classId', component: ClassPage, exact: true }, + { path: '/courses/:courseName', component: CoursesDetailPage, exact: true }, + { path: '/courses/:courseName/:className', component: ClassPage, exact: true }, { path: '/licenses', component: LicensesPage, exact: true }, { path: '/licenses/:licenseId', component: LicensesDetailPage, exact: true }, { path: '/classes', component: ClassesPage, exact: true }, diff --git a/src/features/Students/StudentsTable/columns.jsx b/src/features/Students/StudentsTable/columns.jsx index ec479eac..555d0581 100644 --- a/src/features/Students/StudentsTable/columns.jsx +++ b/src/features/Students/StudentsTable/columns.jsx @@ -26,7 +26,7 @@ const columns = [ accessor: 'className', Cell: ({ row }) => ( {row.values.className}