diff --git a/src/pages/ExamsPage/components/ExamSelection.jsx b/src/pages/ExamsPage/components/ExamSelection.jsx
index 5c2ae7f..fd7ba0c 100644
--- a/src/pages/ExamsPage/components/ExamSelection.jsx
+++ b/src/pages/ExamsPage/components/ExamSelection.jsx
@@ -1,32 +1,53 @@
-import React from 'react';
+import React, { useState } from 'react';
+import { useIntl } from '@edx/frontend-platform/i18n';
import {
MenuItem, SearchField,
SelectMenu,
} from '@edx/paragon';
import PropTypes from 'prop-types';
-import { useUpdateCurrentExamIndex } from '../hooks';
-// todo: implement substring search
+const ExamSelection = ({ exams, handleSelectExam }) => {
+ const { formatMessage, formatDate } = useIntl();
+ const [searchText, setSearchText] = useState('');
-const ExamSelection = ({ exams }) => {
- const { updateSelectedExam } = useUpdateCurrentExamIndex();
+ const placeholderMessage = formatMessage({
+ id: 'ExamSelection.select_exam_placeholder',
+ defaultMessage: 'Search for an exam...',
+ description: 'Placeholder message for the exam selection dropdown',
+ });
+
+ const getMenuItems = () => {
+ const menuItems = [
+ ,
+ ]
+ return menuItems.concat(exams.filter(exam => (
+ exam.name.toLowerCase().includes(searchText.toLowerCase()))
+ ).map(exam => {
+ return
+ }));
+ }
return (
-
-
- {exams.map(exam => (
- // todo: update redux state
- //
-
- ))}
+
+ { getMenuItems() }
);
};
ExamSelection.propTypes = {
- exams: PropTypes.arrayOf(PropTypes.object).isRequired, // eslint-disable-line react/forbid-prop-types
+ exams: PropTypes.arrayOf(PropTypes.shape({
+ id: PropTypes.number,
+ name: PropTypes.string,
+ })).isRequired,
+ handleSelectExam: PropTypes.func.isRequired,
};
export default ExamSelection;
diff --git a/src/pages/ExamsPage/data/reducer.js b/src/pages/ExamsPage/data/reducer.js
index 3b83cbe..89e368c 100644
--- a/src/pages/ExamsPage/data/reducer.js
+++ b/src/pages/ExamsPage/data/reducer.js
@@ -36,7 +36,7 @@ const slice = createSlice({
...state,
attemptsList: state.attemptsList.filter(attempt => attempt.attempt_id !== attemptId.payload),
}),
- setCurrentExamIndex: (state, examId) => ({
+ setCurrentExam: (state, examId) => ({
...state,
currentExamIndex: state.examsList.findIndex(exam => exam.id === examId.payload),
}),
@@ -47,7 +47,7 @@ export const {
loadExams,
loadExamAttempts,
deleteExamAttempt,
- setCurrentExamIndex,
+ setCurrentExam,
} = slice.actions;
export const {
diff --git a/src/pages/ExamsPage/hooks.js b/src/pages/ExamsPage/hooks.js
index f9bad45..8fbd2a1 100644
--- a/src/pages/ExamsPage/hooks.js
+++ b/src/pages/ExamsPage/hooks.js
@@ -57,15 +57,20 @@ export const useInitializeExamsPage = (courseId) => {
React.useEffect(() => { fetchCourseExams(courseId); }, []); // eslint-disable-line react-hooks/exhaustive-deps
};
-export const useUpdateCurrentExamIndex = () => {
+export const useSetCurrentExam = () => {
const dispatch = useDispatch();
- return (examId) => () => dispatch(reducer.setCurrentExamIndex(examId));
+ const fetchExamAttempts = module.useFetchExamAttempts();
+ return (examId) => {
+ dispatch(reducer.setCurrentExam(examId));
+ fetchExamAttempts(examId);
+ };
};
export const useExamsData = () => {
const [exampleValue, setExampleValue] = state.exampleValue(0);
const examsList = useSelector(selectors.courseExamsList);
const currentExam = useSelector(selectors.currentExam);
+ const setCurrentExam = module.useSetCurrentExam();
const isLoading = reduxHooks.useRequestIsPending(RequestKeys.fetchCourseExams);
return {
@@ -73,6 +78,7 @@ export const useExamsData = () => {
examsList,
isLoading,
exampleValue,
+ setCurrentExam,
setExampleValue,
};
};
diff --git a/src/pages/ExamsPage/index.jsx b/src/pages/ExamsPage/index.jsx
index e11bb35..1d830df 100644
--- a/src/pages/ExamsPage/index.jsx
+++ b/src/pages/ExamsPage/index.jsx
@@ -9,39 +9,30 @@ import {
useExamsData, useInitializeExamsPage, useFetchExamAttempts, useExamAttemptsData,
} from './hooks';
import AttemptList from './components/AttemptList';
-import ExamList from './components/ExamList';
import ExternalReviewDashboard from './components/ExternalReviewDashboard';
import ExamSelection from './components/ExamSelection';
+import './index.scss'
+
const ExamsPage = ({ courseId }) => {
useInitializeExamsPage(courseId);
const { formatMessage } = useIntl();
const {
currentExam,
examsList,
- isLoading,
+ setCurrentExam,
} = useExamsData();
const {
attemptsList,
} = useExamAttemptsData();
- /* eslint-disable react-hooks/exhaustive-deps */
- const fetchExamAttempts = useFetchExamAttempts();
- // NOTE: This useEffect hook is temporary until the currentExam is
- // Passed in via the exam selection component
- useEffect(() => {
- if (currentExam) {
- fetchExamAttempts(currentExam.id);
- }
- }, [currentExam]);
- /* eslint-disable react-hooks/exhaustive-deps */
return (
- {isLoading && Loading...
}
-
+
+
+
-
diff --git a/src/pages/ExamsPage/index.scss b/src/pages/ExamsPage/index.scss
new file mode 100644
index 0000000..e1a9e9b
--- /dev/null
+++ b/src/pages/ExamsPage/index.scss
@@ -0,0 +1,14 @@
+@import "~@edx/paragon/scss/core/core";
+
+#exam-selector {
+ margin: 0.5em auto;
+}
+
+.pgn__searchfield .form-control {
+ border: 1px solid $search-border-color !important;
+}
+
+.pgn__searchfield.has-focus:not(.pgn__searchfield--external)::after {
+ border: none;
+ width: 0px;
+}
\ No newline at end of file