Skip to content

Commit

Permalink
feat: finish component logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Zacharis278 committed Jul 17, 2023
1 parent 8a3dc5f commit 0501387
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 32 deletions.
47 changes: 34 additions & 13 deletions src/pages/ExamsPage/components/ExamSelection.jsx
Original file line number Diff line number Diff line change
@@ -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();

Check failure on line 10 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

'formatDate' is assigned a value but never used
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 = [
<MenuItem as={SearchField} onChange={setSearchText} placeholder={placeholderMessage} />,
]

Check failure on line 22 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

Missing semicolon
return menuItems.concat(exams.filter(exam => (
exam.name.toLowerCase().includes(searchText.toLowerCase()))

Check failure on line 24 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

Missing trailing comma
).map(exam => {

Check failure on line 25 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

Unexpected newline before ')'

Check failure on line 25 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`
return <MenuItem onClick={() => handleSelectExam(exam.id)}>{exam.name}</MenuItem>

Check failure on line 26 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

Missing semicolon
}));
}

Check failure on line 28 in src/pages/ExamsPage/components/ExamSelection.jsx

View workflow job for this annotation

GitHub Actions / test (16)

Missing semicolon

return (
<div data-testid="exam_selection">
<SelectMenu defaultMessage="Select an exam...">
<MenuItem as={SearchField} />
{exams.map(exam => (
// todo: update redux state
// <MenuItem onClick={() => console.log(exam.id)}>{exam.name}</MenuItem>
<MenuItem onClick={() => updateSelectedExam(exam.id)}>{exam.name}</MenuItem>
))}
<SelectMenu
defaultMessage={formatMessage({
id: 'ExamSelection.select_exam',
defaultMessage: 'Select an exam',
description: 'Default message for the exam selection dropdown',
})}
>
{ getMenuItems() }
</SelectMenu>
</div>
);
};

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;
4 changes: 2 additions & 2 deletions src/pages/ExamsPage/data/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}),
Expand All @@ -47,7 +47,7 @@ export const {
loadExams,
loadExamAttempts,
deleteExamAttempt,
setCurrentExamIndex,
setCurrentExam,
} = slice.actions;

export const {
Expand Down
10 changes: 8 additions & 2 deletions src/pages/ExamsPage/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,28 @@ 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 {
currentExam,
examsList,
isLoading,
exampleValue,
setCurrentExam,
setExampleValue,
};
};
Expand Down
21 changes: 6 additions & 15 deletions src/pages/ExamsPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,30 @@ import {
useExamsData, useInitializeExamsPage, useFetchExamAttempts, useExamAttemptsData,

Check failure on line 9 in src/pages/ExamsPage/index.jsx

View workflow job for this annotation

GitHub Actions / test (16)

'useFetchExamAttempts' is defined but never used
} 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 (
<Container>
{isLoading && <div>Loading...</div>}
<ExamList exams={examsList} />
<Container id="exam-selector">
<ExamSelection exams={examsList} handleSelectExam={setCurrentExam} />
</Container>
<Tabs variant="tabs" mountOnEnter defaultActiveKey="attempts">
<Tab eventKey="attempts" title={formatMessage(messages.attemptsViewTabTitle)}>
<ExamSelection exams={examsList} />
<AttemptList attempts={attemptsList} />
</Tab>
<Tab eventKey="review" title={formatMessage(messages.reviewDashboardTabTitle)}>
Expand Down
14 changes: 14 additions & 0 deletions src/pages/ExamsPage/index.scss
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 0501387

Please sign in to comment.