From c660bd8d15294112ff86129c0b9c060901bb7aee Mon Sep 17 00:00:00 2001 From: Rick Reilly Date: Wed, 14 Nov 2018 14:55:17 -0500 Subject: [PATCH] Fix the category filter --- src/components/Gradebook/index.jsx | 141 +---------------------- src/containers/GradebookPage/index.jsx | 5 + src/data/actions/grades.js | 17 ++- src/data/actions/utils.js | 131 +++++++++++++++++++++ src/data/constants/actionTypes/grades.js | 4 + src/data/reducers/grades.js | 8 ++ 6 files changed, 166 insertions(+), 140 deletions(-) create mode 100644 src/data/actions/utils.js diff --git a/src/components/Gradebook/index.jsx b/src/components/Gradebook/index.jsx index 607df3e..1c48b0f 100644 --- a/src/components/Gradebook/index.jsx +++ b/src/components/Gradebook/index.jsx @@ -52,134 +52,6 @@ export default class Gradebook extends React.Component { }); } - sortAlphaDesc = (gradeRowA, gradeRowB) => { - const a = gradeRowA.username.toUpperCase(); - const b = gradeRowB.username.toUpperCase(); - if (a < b) { - return -1; - } - if (a > b) { - return 1; - } - return 0; - }; - - sortAlphaAsc = (gradeRowA, gradeRowB) => { - const a = gradeRowA.username.toUpperCase(); - const b = gradeRowB.username.toUpperCase(); - if (a < b) { - return 1; - } - if (a > b) { - return -1; - } - return 0; - }; - - sortNumerically = (colKey, direction) => { - function sortNumAsc(gradeRowA, gradeRowB) { - if (gradeRowA[colKey] < gradeRowB[colKey]) { - return -1; - } - if (gradeRowA[colKey] > gradeRowB[colKey]) { - return 1; - } - return 0; - } - - function sortNumDesc(gradeRowA, gradeRowB) { - if (gradeRowA[colKey] < gradeRowB[colKey]) { - return 1; - } - if (gradeRowA[colKey] > gradeRowB[colKey]) { - return -1; - } - return 0; - } - - this.setState({ grades: [...this.state.grades].sort(direction === 'desc' ? sortNumDesc : sortNumAsc) }); - } - - mapHeadings = (entry) => { - if (entry) { - const results = [{ - label: 'Username', - key: 'username', - columnSortable: true, - onSort: (direction) => { - this.setState({ - grades: [...this.state.grades].sort(direction === 'desc' ? this.sortAlphaDesc : this.sortAlphaAsc), - }); - }, - }]; - - const assignmentHeadings = entry.section_breakdown - .filter(section => section.is_graded && section.label) - .map(s => ({ - label: s.label, - key: s.label, - columnSortable: true, - onSort: (direction) => { this.sortNumerically(s.label, direction); }, - })); - - const totals = [{ - label: 'Total', - key: 'total', - columnSortable: true, - onSort: (direction) => { this.sortNumerically('total', direction); }, - }]; - - return results.concat(assignmentHeadings).concat(totals); - } - return []; - }; - - mapHeadingsHw = (entry) => { - const results = [{ - label: 'Username', - key: 'username', - columnSortable: true, - onSort: (direction) => { - this.setState({ - grades: [...this.state.grades].sort(direction === 'desc' ? this.sortAlphaDesc : this.sortAlphaAsc), - }); - }, - }]; - const assignmentHeadings = entry.section_breakdown - .filter(section => section.is_graded && section.label && section.category == 'Homework') - .map(s => ({ - label: s.label, - key: s.label, - columnSortable: true, - onSort: (direction) => { this.sortNumerically(s.label, direction); }, - })); - - return results.concat(assignmentHeadings); - }; - - mapHeadingsExam = (entry) => { - const results = [{ - label: 'Username', - key: 'username', - columnSortable: true, - onSort: (direction) => { - this.setState({ - grades: [...this.state.grades].sort(direction === 'desc' ? this.sortAlphaDesc : this.sortAlphaAsc), - }); - }, - }]; - const assignmentHeadings = entry.section_breakdown - .filter(section => section.is_graded && section.label && section.category == 'Exam') - .map(s => ({ - label: s.label, - key: s.label, - columnSortable: true, - onSort: (direction) => { this.sortNumerically(s.label, direction); }, - })); - - return results.concat(assignmentHeadings); - }; - handleAdjustedGradeClick = () => { this.props.updateGrades(this.props.match.params.courseId, [ { @@ -345,8 +217,7 @@ export default class Gradebook extends React.Component { type="radio" name="category" value="all" - onClick={() => - this.setState({ headings: this.mapHeadings(this.props.results[0]) })} + onClick={() => this.props.filterColumns('all', this.props.grades[0])} /> All @@ -358,10 +229,7 @@ export default class Gradebook extends React.Component { type="radio" name="category" value="homework" - onClick={() => - this.setState({ - headings: this.mapHeadingsHw(this.props.results[0]), - })} + onClick={() => this.props.filterColumns('hw', this.props.grades[0])} /> @@ -372,7 +240,7 @@ export default class Gradebook extends React.Component { type="radio" name="category" value="exam" - onClick={() => this.setState({ headings: this.mapHeadingsExam(this.props.results[0]) })} + onClick={() => this.props.filterColumns('exam', this.props.grades[0])} /> Exam @@ -417,9 +285,8 @@ export default class Gradebook extends React.Component {
diff --git a/src/containers/GradebookPage/index.jsx b/src/containers/GradebookPage/index.jsx index 2fbf9f2..24848b9 100644 --- a/src/containers/GradebookPage/index.jsx +++ b/src/containers/GradebookPage/index.jsx @@ -6,6 +6,7 @@ import { fetchMatchingUserGrades, updateGrades, toggleGradeFormat, + filterColumns, } from '../../data/actions/grades'; import { fetchCohorts } from '../../data/actions/cohorts'; import { fetchTracks } from '../../data/actions/tracks'; @@ -13,6 +14,7 @@ import { fetchTracks } from '../../data/actions/tracks'; const mapStateToProps = state => ( { grades: state.grades.results, + headings: state.grades.headings, tracks: state.tracks.results, cohorts: state.cohorts.results, selectedTrack: state.grades.selectedTrack, @@ -41,6 +43,9 @@ const mapDispatchToProps = dispatch => ( toggleFormat: (formatType) => { dispatch(toggleGradeFormat(formatType)); }, + filterColumns: (filterType, exampleUser) => { + dispatch(filterColumns(filterType, exampleUser)); + }, } ); diff --git a/src/data/actions/grades.js b/src/data/actions/grades.js index 95f2db8..745aac1 100644 --- a/src/data/actions/grades.js +++ b/src/data/actions/grades.js @@ -7,17 +7,21 @@ import { GRADE_UPDATE_SUCCESS, GRADE_UPDATE_FAILURE, TOGGLE_GRADE_FORMAT, + SORT_GRADES, + FILTER_COLUMNS, } from '../constants/actionTypes/grades'; import LmsApiService from '../services/LmsApiService'; +import { headingMapper } from './utils'; const startedFetchingGrades = () => ({ type: STARTED_FETCHING_GRADES }); const finishedFetchingGrades = () => ({ type: FINISHED_FETCHING_GRADES }); const errorFetchingGrades = () => ({ type: ERROR_FETCHING_GRADES }); -const gotGrades = (grades, cohort, track) => ({ +const gotGrades = (grades, cohort, track, headings) => ({ type: GOT_GRADES, grades, cohort, track, + headings, }); const gradeUpdateRequest = () => ({ type: GRADE_UPDATE_REQUEST }); @@ -32,7 +36,12 @@ const gradeUpdateFailure = error => ({ const toggleGradeFormat = formatType => ({ type: TOGGLE_GRADE_FORMAT, formatType }); +const sortGrades = (columnName, direction) => ({ type: SORT_GRADES, columnName, direction }); +const filterColumns = (filterType, exampleUser) => ({ + type: FILTER_COLUMNS, + headings: headingMapper[filterType](exampleUser) +}); const fetchGrades = (courseId, cohort, track) => ( (dispatch) => { @@ -40,7 +49,7 @@ const fetchGrades = (courseId, cohort, track) => ( return LmsApiService.fetchGradebookData(courseId, null, cohort, track) .then(response => response.data) .then((data) => { - dispatch(gotGrades(data.results, cohort, track)); + dispatch(gotGrades(data.results, cohort, track, headingMapper.all(data.results[0]))); dispatch(finishedFetchingGrades()); }) .catch(() => { @@ -70,7 +79,7 @@ const updateGrades = (courseId, updateData) => ( return LmsApiService.updateGradebookData(courseId, updateData) .then(response => response.data) .then((data) => { - dispatch(gradeUpdateSuccess(data)) + dispatch(gradeUpdateSuccess(data)); }) .catch((error) => { dispatch(gradeUpdateFailure(error)); @@ -90,4 +99,6 @@ export { gradeUpdateFailure, updateGrades, toggleGradeFormat, + sortGrades, + filterColumns, }; diff --git a/src/data/actions/utils.js b/src/data/actions/utils.js new file mode 100644 index 0000000..23088a7 --- /dev/null +++ b/src/data/actions/utils.js @@ -0,0 +1,131 @@ + +const sortAlphaDesc = (gradeRowA, gradeRowB) => { + const a = gradeRowA.username.toUpperCase(); + const b = gradeRowB.username.toUpperCase(); + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; +}; + +const sortAlphaAsc = (gradeRowA, gradeRowB) => { + const a = gradeRowA.username.toUpperCase(); + const b = gradeRowB.username.toUpperCase(); + if (a < b) { + return 1; + } + if (a > b) { + return -1; + } + return 0; +}; + +const sortNumerically = (colKey, direction) => { + function sortNumAsc(gradeRowA, gradeRowB) { + if (gradeRowA[colKey] < gradeRowB[colKey]) { + return -1; + } + if (gradeRowA[colKey] > gradeRowB[colKey]) { + return 1; + } + return 0; + } + + function sortNumDesc(gradeRowA, gradeRowB) { + if (gradeRowA[colKey] < gradeRowB[colKey]) { + return 1; + } + if (gradeRowA[colKey] > gradeRowB[colKey]) { + return -1; + } + return 0; + } + + this.setState({ grades: [...this.state.grades].sort(direction === 'desc' ? sortNumDesc : sortNumAsc) }); +}; +const headingMapper = { + all: (entry) => { + if (entry) { + const results = [{ + label: 'Username', + key: 'username', + columnSortable: true, + onSort: (direction) => { + this.setState({ + grades: [...this.state.grades].sort(direction === 'desc' ? this.sortAlphaDesc : this.sortAlphaAsc), + }); + }, + }]; + + const assignmentHeadings = entry.section_breakdown + .filter(section => section.is_graded && section.label) + .map(s => ({ + label: s.label, + key: s.label, + columnSortable: true, + onSort: (direction) => { this.sortNumerically(s.label, direction); }, + })); + + const totals = [{ + label: 'Total', + key: 'total', + columnSortable: true, + onSort: (direction) => { this.sortNumerically('total', direction); }, + }]; + + return results.concat(assignmentHeadings).concat(totals); + } + return []; + }, + hw: (entry) => { + const results = [{ + label: 'Username', + key: 'username', + columnSortable: true, + onSort: (direction) => { + this.setState({ + grades: [...this.state.grades].sort(direction === 'desc' ? this.sortAlphaDesc : this.sortAlphaAsc), + }); + }, + }]; + + const assignmentHeadings = entry.section_breakdown + .filter(section => section.is_graded && section.label && section.category == 'Homework') + .map(s => ({ + label: s.label, + key: s.label, + columnSortable: false, + onSort: (direction) => { this.sortNumerically(s.label, direction); }, + })); + + return results.concat(assignmentHeadings); + }, + exam: (entry) => { + const results = [{ + label: 'Username', + key: 'username', + columnSortable: false, + onSort: (direction) => { + this.setState({ + grades: [...this.state.grades].sort(direction === 'desc' ? this.sortAlphaDesc : this.sortAlphaAsc), + }); + }, + }]; + + const assignmentHeadings = entry.section_breakdown + .filter(section => section.is_graded && section.label && section.category == 'Exam') + .map(s => ({ + label: s.label, + key: s.label, + columnSortable: false, + onSort: (direction) => { this.sortNumerically(s.label, direction); }, + })); + + return results.concat(assignmentHeadings); + }, +}; + +export { headingMapper }; diff --git a/src/data/constants/actionTypes/grades.js b/src/data/constants/actionTypes/grades.js index 6aa4d17..31a65d6 100644 --- a/src/data/constants/actionTypes/grades.js +++ b/src/data/constants/actionTypes/grades.js @@ -8,6 +8,8 @@ const GRADE_UPDATE_SUCCESS = 'GRADE_UPDATE_SUCCESS'; const GRADE_UPDATE_FAILURE = 'GRADE_UPDATE_FAILURE'; const TOGGLE_GRADE_FORMAT = 'TOGGLE_GRADE_FORMAT'; +const SORT_GRADES = 'SORT_GRADES'; +const FILTER_COLUMNS = 'FILTER_COLUMNS'; export { STARTED_FETCHING_GRADES, @@ -18,4 +20,6 @@ export { GRADE_UPDATE_SUCCESS, GRADE_UPDATE_FAILURE, TOGGLE_GRADE_FORMAT, + SORT_GRADES, + FILTER_COLUMNS, }; diff --git a/src/data/reducers/grades.js b/src/data/reducers/grades.js index cbbcc36..a11f46e 100644 --- a/src/data/reducers/grades.js +++ b/src/data/reducers/grades.js @@ -3,10 +3,12 @@ import { ERROR_FETCHING_GRADES, GOT_GRADES, TOGGLE_GRADE_FORMAT, + FILTER_COLUMNS, } from '../constants/actionTypes/grades'; const initialState = { results: [], + headings: [], startedFetching: false, finishedFetching: false, errorFetching: false, @@ -19,6 +21,7 @@ const grades = (state = initialState, action) => { return { ...state, results: action.grades, + headings: action.headings, finishedFetching: true, errorFetching: false, selectedTrack: action.track, @@ -41,6 +44,11 @@ const grades = (state = initialState, action) => { ...state, gradeFormat: action.formatType, }; + case FILTER_COLUMNS: + return { + ...state, + headings: action.headings, + }; default: return state; }