generated from openedx/frontend-template-application
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
495 additions
and
31 deletions.
There are no files selected for viewing
37 changes: 28 additions & 9 deletions
37
src/features/Dashboard/InstructorAssignSection/ClassCard.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
src/features/Instructors/AssignInstructors/AssignTable.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React, { useMemo, useEffect, useState } from 'react'; | ||
import { useSelector, useDispatch } from 'react-redux'; | ||
|
||
import { IntlProvider } from 'react-intl'; | ||
import { | ||
Row, | ||
Col, | ||
DataTable, | ||
} from '@edx/paragon'; | ||
|
||
import { updateRowsSelected } from 'features/Instructors/data/slice'; | ||
|
||
import { columns } from 'features/Instructors/AssignInstructors/columns'; | ||
|
||
const AssignTable = () => { | ||
const dispatch = useDispatch(); | ||
const stateInstructors = useSelector((state) => state.instructors.table); | ||
const [rowsSelected, setRowsSelected] = useState([]); | ||
const COLUMNS = useMemo(() => columns({ setRowsSelected }), []); | ||
|
||
useEffect(() => { | ||
dispatch(updateRowsSelected(rowsSelected)); | ||
}, [rowsSelected, dispatch]); | ||
|
||
return ( | ||
<IntlProvider locale="en"> | ||
<Row className="justify-content-center my-4 my-3"> | ||
<Col xs={11} className="p-0"> | ||
<DataTable | ||
isSortable | ||
columns={COLUMNS} | ||
itemCount={stateInstructors.count} | ||
data={stateInstructors.data} | ||
> | ||
<DataTable.TableControlBar /> | ||
<DataTable.Table /> | ||
<DataTable.EmptyTable content="No instructors found." /> | ||
</DataTable> | ||
</Col> | ||
</Row> | ||
</IntlProvider> | ||
); | ||
}; | ||
|
||
export default AssignTable; |
64 changes: 64 additions & 0 deletions
64
src/features/Instructors/AssignInstructors/_test_/index.test.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React from 'react'; | ||
import { waitFor, fireEvent } from '@testing-library/react'; | ||
import AssignInstructors from 'features/Instructors/AssignInstructors'; | ||
import '@testing-library/jest-dom/extend-expect'; | ||
import { renderWithProviders } from 'test-utils'; | ||
|
||
jest.mock('@edx/frontend-platform/logging', () => ({ | ||
logError: jest.fn(), | ||
})); | ||
|
||
const mockStore = { | ||
instructors: { | ||
table: { | ||
data: [ | ||
{ | ||
instructorUsername: 'Instructor1', | ||
instructorName: 'Instructor 1', | ||
instructorEmail: '[email protected]', | ||
ccxId: 'CCX1', | ||
ccxName: 'CCX 1', | ||
}, | ||
{ | ||
instructorUsername: 'Instructor2', | ||
instructorName: 'Instructor 2', | ||
instructorEmail: '[email protected]', | ||
ccxId: 'CCX2', | ||
ccxName: 'CCX 2', | ||
}, | ||
], | ||
count: 2, | ||
num_pages: 1, | ||
current_page: 1, | ||
}, | ||
classes: { | ||
data: [], | ||
}, | ||
courses: { | ||
data: [], | ||
}, | ||
}, | ||
}; | ||
|
||
describe('Assign instructors modal', () => { | ||
test('render assing instructors modal', () => { | ||
const {getByText, getAllByRole, getByTestId} = renderWithProviders( | ||
Check failure on line 45 in src/features/Instructors/AssignInstructors/_test_/index.test.jsx GitHub Actions / test
|
||
<AssignInstructors isOpen close={() => {}} />, | ||
{ preloadedState: mockStore }, | ||
); | ||
|
||
waitFor(() => { | ||
expect(getByText('Instructor')).toBeInTheDocument(); | ||
expect(getByText('Instructor1')).toBeInTheDocument() | ||
expect(getByText('Instructor2')).toBeInTheDocument() | ||
expect(getByText('Last seen')).toBeInTheDocument() | ||
expect(getByText('Courses taught')).toBeInTheDocument() | ||
}); | ||
|
||
const checkboxFields = getAllByRole('checkbox'); | ||
fireEvent.click(checkboxFields[0]) | ||
|
||
const assignButton = getByTestId('assignButton') | ||
fireEvent.click(assignButton) | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* eslint-disable react/prop-types, no-nested-ternary */ | ||
import { differenceInHours, differenceInDays, differenceInWeeks } from 'date-fns'; | ||
import { CheckboxControl } from '@edx/paragon'; | ||
|
||
const handleCheckbox = (setRowsSelected, row) => { | ||
setRowsSelected(prevState => { | ||
const rowSelected = row.original.instructorUsername; | ||
if (prevState.includes(rowSelected)) { | ||
const filterData = prevState.filter(rowState => rowState !== rowSelected); | ||
return filterData; | ||
} | ||
return [...prevState, rowSelected]; | ||
}); | ||
}; | ||
|
||
const columns = ({ setRowsSelected }) => [ | ||
{ | ||
Header: '', | ||
id: 'checkbox', | ||
width: 30, | ||
Cell: ({ row }) => ( | ||
<div> | ||
<CheckboxControl | ||
onChange={() => handleCheckbox(setRowsSelected, row)} | ||
/> | ||
</div> | ||
), | ||
}, | ||
{ | ||
Header: 'Instructor', | ||
accessor: 'instructorName', | ||
}, | ||
{ | ||
Header: 'Last seen', | ||
accessor: 'lastAccess', | ||
Cell: ({ row }) => { | ||
const currentDate = Date.now(); | ||
const lastDate = new Date(row.values.lastAccess); | ||
const diffHours = differenceInHours(currentDate, lastDate); | ||
const diffDays = differenceInDays(currentDate, lastDate); | ||
const diffWeeks = differenceInWeeks(currentDate, lastDate); | ||
return ( | ||
<span>{diffHours < 24 | ||
? 'Today' | ||
: diffDays < 7 | ||
? `${diffDays} days ago` | ||
: `${diffWeeks} wks ago`} | ||
</span> | ||
); | ||
}, | ||
}, | ||
{ | ||
Header: 'Courses Taught', | ||
accessor: 'classes', | ||
}, | ||
]; | ||
|
||
export { columns }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { ModalDialog, ModalCloseButton, Pagination } from '@edx/paragon'; | ||
import { Button } from 'react-paragon-topaz'; | ||
import InstructorsFilters from 'features/Instructors/InstructorsFilters'; | ||
import AssignTable from 'features/Instructors/AssignInstructors/AssignTable'; | ||
|
||
import { fetchInstructorsData, assignInstructors } from 'features/Instructors/data'; | ||
import { | ||
updateCurrentPage, updateRowsSelected, updateFilters, updateClassSelected, | ||
} from 'features/Instructors/data/slice'; | ||
|
||
import { initialPage } from 'features/constants'; | ||
import 'features/Instructors/AssignInstructors/index.scss'; | ||
|
||
const AssignInstructors = ({ isOpen, close }) => { | ||
const dispatch = useDispatch(); | ||
const selectedInstitution = useSelector((state) => state.main.selectedInstitution); | ||
const stateInstructors = useSelector((state) => state.instructors); | ||
const rowsSelected = useSelector((state) => state.instructors.rowsSelected); | ||
const classId = useSelector((state) => state.instructors.classSelected); | ||
const [currentPage, setCurrentPage] = useState(initialPage); | ||
|
||
const resetPagination = () => { | ||
setCurrentPage(initialPage); | ||
}; | ||
|
||
const handlePagination = (targetPage) => { | ||
setCurrentPage(targetPage); | ||
dispatch(updateCurrentPage(targetPage)); | ||
}; | ||
|
||
const handleAssignInstructors = async () => { | ||
// eslint-disable-next-line array-callback-return | ||
rowsSelected.map(row => { | ||
const enrollmentData = new FormData(); | ||
enrollmentData.append('unique_student_identifier', row); | ||
enrollmentData.append('rolename', 'staff'); | ||
enrollmentData.append('action', 'allow'); | ||
dispatch(assignInstructors(enrollmentData, classId, selectedInstitution.id)); | ||
}); | ||
close(); | ||
}; | ||
|
||
useEffect(() => { | ||
if (Object.keys(selectedInstitution).length > 0) { | ||
dispatch(fetchInstructorsData(selectedInstitution.id, currentPage, stateInstructors.filters)); | ||
} | ||
}, [currentPage, selectedInstitution, dispatch]); // eslint-disable-line react-hooks/exhaustive-deps | ||
|
||
useEffect(() => { | ||
if (!isOpen) { | ||
dispatch(updateRowsSelected([])); | ||
dispatch(updateFilters({})); | ||
dispatch(updateClassSelected('')); | ||
} | ||
}, [isOpen, dispatch]); | ||
|
||
return ( | ||
<ModalDialog | ||
title="Assign instructor" | ||
isOpen={isOpen} | ||
onClose={close} | ||
hasCloseButton | ||
size="lg" | ||
> | ||
<ModalDialog.Header> | ||
<ModalDialog.Title> | ||
Assign instructor | ||
</ModalDialog.Title> | ||
</ModalDialog.Header> | ||
<ModalDialog.Body> | ||
<InstructorsFilters isAssignModal resetPagination={resetPagination} /> | ||
<AssignTable /> | ||
{stateInstructors.table.numPages > 1 && ( | ||
<Pagination | ||
paginationLabel="paginationNavigation" | ||
pageCount={stateInstructors.table.numPages} | ||
currentPage={currentPage} | ||
onPageSelect={handlePagination} | ||
variant="reduced" | ||
className="mx-auto pagination-table" | ||
size="small" | ||
/> | ||
)} | ||
<div className="d-flex justify-content-end"> | ||
<ModalCloseButton className="btntpz btn-text btn-tertiary">Close</ModalCloseButton> | ||
<Button onClick={handleAssignInstructors} data-testid='assignButton'>Assign instructor</Button> | ||
</div> | ||
</ModalDialog.Body> | ||
</ModalDialog> | ||
); | ||
}; | ||
|
||
AssignInstructors.propTypes = { | ||
isOpen: PropTypes.bool.isRequired, | ||
close: PropTypes.func.isRequired, | ||
}; | ||
|
||
export default AssignInstructors; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@import "assets/colors.scss"; | ||
|
||
.pgn__modal-close-button.btn-icon.btn-icon-primary { | ||
color: $gray-70; | ||
|
||
&:hover, | ||
&:active, | ||
&:focus { | ||
color: $gray-70; | ||
background-color: $gray-20; | ||
box-shadow: none; | ||
} | ||
} |
Oops, something went wrong.