diff --git a/src/features/Classes/Class/ClassPage/Actions.jsx b/src/features/Classes/Class/ClassPage/Actions.jsx index d7c9b5b..7bfa5d0 100644 --- a/src/features/Classes/Class/ClassPage/Actions.jsx +++ b/src/features/Classes/Class/ClassPage/Actions.jsx @@ -51,13 +51,6 @@ const Actions = ({ previousPage }) => { const [isOpenEditModal, openEditModal, closeEditModal] = useToggle(false); const [isEnrollModalOpen, setIsEnrollModalOpen] = useState(false); - const handleEnrollStudentModal = () => setIsEnrollModalOpen(!isEnrollModalOpen); - const addQueryParam = useInstitutionIdQueryParam(); - - const handleManageButton = () => { - history.push(addQueryParam(`/manage-instructors/${courseId}/${classId}?previous=${previousPage}`)); - }; - let instructorText = 'Assign instructor'; if (classInfo?.instructors?.length > 1) { @@ -66,6 +59,14 @@ const Actions = ({ previousPage }) => { instructorText = 'Manage instructor'; } + const addQueryParam = useInstitutionIdQueryParam(); + + const handleEnrollStudentModal = () => setIsEnrollModalOpen(!isEnrollModalOpen); + + const handleManageButton = () => { + history.push(addQueryParam(`/manage-instructors/${courseId}/${classId}?previous=${previousPage}`)); + }; + const handleResetDeletion = () => { setDeletionState(initialDeletionClassState); dispatch(resetClassState()); diff --git a/src/features/Classes/InstructorCard/__test__/index.test.jsx b/src/features/Classes/InstructorCard/__test__/index.test.jsx index 19bc36b..e0b24d5 100644 --- a/src/features/Classes/InstructorCard/__test__/index.test.jsx +++ b/src/features/Classes/InstructorCard/__test__/index.test.jsx @@ -1,14 +1,10 @@ import React from 'react'; -import { renderWithProviders } from 'test-utils'; import '@testing-library/jest-dom/extend-expect'; +import { MemoryRouter, Route } from 'react-router-dom'; -import InstructorCard from 'features/Classes/InstructorCard'; +import { renderWithProviders } from 'test-utils'; -jest.mock('react-router-dom', () => ({ - useParams: jest.fn(() => ({ - classId: 'ccx-v1', - })), -})); +import InstructorCard from 'features/Classes/InstructorCard'; jest.mock('@edx/frontend-platform/logging', () => ({ logError: jest.fn(), @@ -45,7 +41,11 @@ const stateMock = { describe('InstructorCard', () => { test('Should render with correct elements', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: stateMock }, ); @@ -57,7 +57,11 @@ describe('InstructorCard', () => { test('Should render multiple instructors', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: { instructors: { @@ -101,11 +105,44 @@ describe('InstructorCard', () => { ); expect(getByText(/more\.\.\./)).toBeInTheDocument(); + expect(getByText(/Manage instructors/)).toBeInTheDocument(); + }); + + test('Should render assign instructor button if the instructor is not present', () => { + const { getByText } = renderWithProviders( + + + { }} /> + + , + { + preloadedState: { + classes: { + allClasses: { + data: [ + { + ...stateMock.classes.allClasses.data[0], + startDate: '2024-02-13T17:42:22Z', + endDate: '2025-02-13T17:42:22Z', + instructors: [], + }, + ], + }, + }, + }, + }, + ); + + expect(getByText('Assign instructor')).toBeInTheDocument(); }); test('Should render both dates when the duration is to long', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: { classes: { @@ -128,7 +165,11 @@ describe('InstructorCard', () => { test('Should render the date when the course take couple months', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: { classes: { @@ -151,7 +192,11 @@ describe('InstructorCard', () => { test('Should render the date when the course take one single month', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: { classes: { @@ -174,7 +219,11 @@ describe('InstructorCard', () => { test('Should render enrollment info with 1 seat remaining', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: { classes: { @@ -196,7 +245,11 @@ describe('InstructorCard', () => { test('Should render enrollment info with more than 1 seat remaining', () => { const { getByText } = renderWithProviders( - { }} />, + + + { }} /> + + , { preloadedState: { classes: { diff --git a/src/features/Classes/InstructorCard/index.jsx b/src/features/Classes/InstructorCard/index.jsx index dcf9a9a..aadb579 100644 --- a/src/features/Classes/InstructorCard/index.jsx +++ b/src/features/Classes/InstructorCard/index.jsx @@ -1,27 +1,37 @@ import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { Spinner } from '@edx/paragon'; +import { Button } from 'react-paragon-topaz'; import { useSelector, useDispatch } from 'react-redux'; -import { useParams } from 'react-router-dom'; +import { useParams, useHistory } from 'react-router-dom'; import { formatDateRange } from 'helpers'; +import { useInstitutionIdQueryParam } from 'hooks'; import { initialPage, RequestStatus } from 'features/constants'; import { resetInstructorOptions } from 'features/Instructors/data/slice'; import { fetchInstructorsOptionsData } from 'features/Instructors/data/thunks'; import InstructorAvatar from 'features/Classes/InstructorAvatar'; -import { Spinner } from '@edx/paragon'; import 'features/Classes/InstructorCard/index.scss'; const INSTRUCTORS_NUMBER = 3; -const InstructorCard = () => { +const InstructorCard = ({ previousPage }) => { const dispatch = useDispatch(); - const { classId } = useParams(); + const { classId, courseId } = useParams(); + const history = useHistory(); const institution = useSelector((state) => state.main.selectedInstitution); const instructors = useSelector((state) => state.instructors.selectOptions.data); const classes = useSelector((state) => state.classes.allClasses); const classIdDecoded = decodeURIComponent(classId); + const addQueryParam = useInstitutionIdQueryParam(); + + const handleManageInstructorButton = () => { + history.push(addQueryParam(`/manage-instructors/${courseId}/${classId}?previous=${previousPage}`)); + }; + const isLoadingClasses = classes.status === RequestStatus.LOADING; const [classInfo] = classes.data.filter( @@ -77,7 +87,7 @@ const InstructorCard = () => {
-

Instructor{instructors.length > 1 && 's'}

+

Instructor{instructors?.length > 1 && 's'}

{isLoadingClasses && (
{ )} {!isLoadingClasses && (
- {classInfo?.instructors.length === 0 && No instructor assigned} + {classInfo?.instructors?.length === 0 && ( + + )} + { classInfo?.instructors?.slice(0, INSTRUCTORS_NUMBER)?.map((instructor) => { const instructorInfo = instructors.find((user) => user.instructorUsername === instructor); @@ -107,6 +126,7 @@ const InstructorCard = () => { }
)} + {classInfo?.instructors?.length > INSTRUCTORS_NUMBER && (
+ @@ -114,9 +134,27 @@ const InstructorCard = () => { more...
)} + + {classInfo?.instructors?.length > 0 && ( + + )}
); }; +InstructorCard.propTypes = { + previousPage: PropTypes.string, +}; + +InstructorCard.defaultProps = { + previousPage: 'courses', +}; + export default InstructorCard; diff --git a/src/features/Main/index.scss b/src/features/Main/index.scss index af51aac..64a1680 100644 --- a/src/features/Main/index.scss +++ b/src/features/Main/index.scss @@ -71,6 +71,7 @@ header.vertical-nav { } } +.text-decoration-underline, a { color: $hyperlink-color; text-decoration: underline;