update actions to use redux toolkit action creators
This commit is contained in:
@@ -12,8 +12,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faDownload } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import { configuration } from '../../config';
|
||||
import { submitFileUploadFormData } from '../../data/actions/grades';
|
||||
import { configuration } from 'config';
|
||||
import { submitFileUploadFormData } from 'data/thunkActions/grades';
|
||||
|
||||
export class BulkManagement extends React.Component {
|
||||
constructor(props) {
|
||||
|
||||
@@ -11,10 +11,7 @@ import {
|
||||
} from '@edx/paragon';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import {
|
||||
doneViewingAssignment,
|
||||
updateGrades,
|
||||
} from '../../data/actions/grades';
|
||||
import * as actions from 'data/actions';
|
||||
|
||||
const GRADE_OVERRIDE_HISTORY_COLUMNS = [
|
||||
{ label: 'Date', key: 'date' },
|
||||
@@ -203,8 +200,8 @@ export const mapStateToProps = (state) => {
|
||||
};
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
doneViewingAssignment,
|
||||
updateGrades,
|
||||
doneViewingAssignment: actions.grades.doneViewingAssignment,
|
||||
updateGrades: actions.grades.updateGrades,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditModal);
|
||||
|
||||
@@ -3,9 +3,9 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import * as gradesActions from 'data/actions/grades';
|
||||
import * as filterActions from 'data/actions/filters';
|
||||
import selectors from 'data/selectors';
|
||||
import * as actions from 'data/actions';
|
||||
import { updateGradesIfAssignmentGradeFiltersSet } from 'data/thunkActions/grades';
|
||||
|
||||
import SelectGroup from '../SelectGroup';
|
||||
|
||||
@@ -97,8 +97,8 @@ export const mapStateToProps = (state) => {
|
||||
};
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
updateAssignmentFilter: filterActions.updateAssignmentFilter,
|
||||
updateGradesIfAssignmentGradeFiltersSet: gradesActions.updateGradesIfAssignmentGradeFiltersSet,
|
||||
updateAssignmentFilter: actions.filters.update.assignment,
|
||||
updateGradesIfAssignmentGradeFiltersSet,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AssignmentFilter);
|
||||
|
||||
@@ -5,9 +5,8 @@ import { connect } from 'react-redux';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
import * as gradesActions from 'data/actions/grades';
|
||||
import * as filterActions from 'data/actions/filters';
|
||||
import selectors from 'data/selectors';
|
||||
import * as actions from 'data/actions';
|
||||
|
||||
import PercentGroup from '../PercentGroup';
|
||||
|
||||
@@ -118,8 +117,8 @@ export const mapStateToProps = (state) => {
|
||||
};
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
getUserGrades: gradesActions.fetchGrades,
|
||||
updateAssignmentLimits: filterActions.updateAssignmentLimits,
|
||||
getUserGrades: fetchGrades,
|
||||
updateAssignmentLimits: actions.filters.update.assignmentLimits,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AssignmentGradeFilter);
|
||||
|
||||
@@ -3,8 +3,13 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
<<<<<<< HEAD
|
||||
import * as gradesActions from 'data/actions/grades';
|
||||
import selectors from 'data/selectors';
|
||||
=======
|
||||
import { selectableAssignmentLabels } from 'data/selectors/filters';
|
||||
import * as actions from 'data/actions';
|
||||
>>>>>>> 5694a3b... update actions to use redux toolkit action creators
|
||||
|
||||
import SelectGroup from '../SelectGroup';
|
||||
|
||||
@@ -72,7 +77,7 @@ export const mapStateToProps = (state) => ({
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
filterAssignmentType: gradesActions.filterAssignmentType,
|
||||
filterAssignmentType: actions.filters.update.assignmentType,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AssignmentTypeFilter);
|
||||
|
||||
@@ -6,9 +6,8 @@ import {
|
||||
Button,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { updateCourseGradeFilter } from 'data/actions/filters';
|
||||
import { fetchGrades } from 'data/actions/grades';
|
||||
import selectors from 'data/selectors';
|
||||
import actions from 'data/actions';
|
||||
import PercentGroup from '../PercentGroup';
|
||||
|
||||
export class CourseGradeFilter extends React.Component {
|
||||
@@ -37,11 +36,11 @@ export class CourseGradeFilter extends React.Component {
|
||||
|
||||
updateCourseGradeFilters() {
|
||||
const { courseGradeMin, courseGradeMax } = this.props.filterValues;
|
||||
this.props.updateFilter(
|
||||
this.props.updateFilter({
|
||||
courseGradeMin,
|
||||
courseGradeMax,
|
||||
this.props.courseId,
|
||||
);
|
||||
courseId: this.props.courseId,
|
||||
});
|
||||
this.props.getUserGrades(
|
||||
this.props.courseId,
|
||||
this.props.selectedCohort,
|
||||
@@ -129,7 +128,7 @@ export const mapStateToProps = (state) => {
|
||||
};
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
updateFilter: updateCourseGradeFilter,
|
||||
updateFilter: actions.filter.update.courseGrade,
|
||||
getUserGrades: fetchGrades,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { fetchGrades } from 'data/actions/grades';
|
||||
import selectors from 'data/selectors';
|
||||
import SelectGroup from '../SelectGroup';
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
Table, OverlayTrigger, Tooltip, Icon,
|
||||
} from '@edx/paragon';
|
||||
|
||||
import { formatDateForDisplay } from '../../data/actions/utils';
|
||||
import { fetchGradeOverrideHistory } from '../../data/actions/grades';
|
||||
import { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING } from '../../data/constants/grades';
|
||||
import selectors from '../../data/selectors';
|
||||
import { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING } from 'data/constants/grades';
|
||||
import selectors from 'data/selectors';
|
||||
import { formatDateForDisplay } from 'data/actions/utils';
|
||||
import { fetchGradeOverrideHistory } from 'data/thunkActions/grades';
|
||||
|
||||
const DECIMAL_PRECISION = 2;
|
||||
|
||||
@@ -219,7 +219,7 @@ GradebookTable.propTypes = {
|
||||
|
||||
export const mapStateToProps = (state) => {
|
||||
const { assignmentTypes, grades, root } = selectors;
|
||||
return {
|
||||
returg {
|
||||
areGradesFrozen: assignmentTypes.areGradesFrozen(state),
|
||||
format: grades.gradeFormat(state),
|
||||
grades: grades.allGrades(state),
|
||||
|
||||
@@ -8,7 +8,7 @@ import selectors from 'data/selectors';
|
||||
import {
|
||||
fetchGrades,
|
||||
fetchMatchingUserGrades,
|
||||
} from '../../data/actions/grades';
|
||||
} from 'data/thunkActions/grades';
|
||||
|
||||
/**
|
||||
* Controls for filtering the GradebookTable. Contains the "Edit Filters" button for opening the filter drawer
|
||||
|
||||
@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
|
||||
import { StatusAlert } from '@edx/paragon';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import { closeBanner } from '../../data/actions/grades';
|
||||
import * as actions from 'data/actions';
|
||||
|
||||
export const maxCourseGradeInvalidMessage = 'Maximum course grade value must be between 0 and 100. ';
|
||||
export const minCourseGradeInvalidMessage = 'Minimum course grade value must be between 0 and 100. ';
|
||||
@@ -66,7 +66,7 @@ export const mapStateToProps = (state) => ({
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
handleCloseSuccessBanner: closeBanner,
|
||||
handleCloseSuccessBanner: actions.grades.banner.close,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(StatusAlerts);
|
||||
|
||||
@@ -1,27 +1,19 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import selectors from 'data/selectors';
|
||||
import Gradebook from '../../components/Gradebook';
|
||||
import { fetchAssignmentTypes } from 'data/thunkActions/assignmentTypes';
|
||||
import {
|
||||
fetchGradeOverrideHistory,
|
||||
fetchGrades,
|
||||
fetchPrevNextGrades,
|
||||
filterAssignmentType,
|
||||
submitFileUploadFormData,
|
||||
toggleGradeFormat,
|
||||
downloadBulkGradesReport,
|
||||
downloadInterventionReport,
|
||||
} from '../../data/actions/grades';
|
||||
import { fetchCohorts } from '../../data/actions/cohorts';
|
||||
import { fetchTracks } from '../../data/actions/tracks';
|
||||
import {
|
||||
initializeFilters,
|
||||
resetFilters,
|
||||
updateAssignmentFilter,
|
||||
updateAssignmentLimits,
|
||||
} from '../../data/actions/filters';
|
||||
import { fetchAssignmentTypes } from '../../data/actions/assignmentTypes';
|
||||
import { getRoles } from '../../data/actions/roles';
|
||||
} from 'data/thunkActions/grades';
|
||||
import { fetchCohorts } from 'data/thunkActions/cohorts';
|
||||
import { fetchTracks } from 'data/thunkActions/tracks';
|
||||
import { getRoles } from 'data/thunkActions/roles';
|
||||
import * as actions from 'data/actions';
|
||||
import selectors from 'data/selectors';
|
||||
|
||||
import Gradebook from 'components/Gradebook';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const {
|
||||
@@ -61,22 +53,22 @@ const mapStateToProps = (state, ownProps) => {
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
downloadBulkGradesReport,
|
||||
downloadInterventionReport,
|
||||
downloadBulkGradesReport: actions.grades.downloadReport.bulkGrades,
|
||||
downloadInterventionReport: actions.grades.downloadReport.intervention,
|
||||
fetchGradeOverrideHistory,
|
||||
filterAssignmentType,
|
||||
filterAssignmentType: actions.filter.update.assignmentType,
|
||||
getAssignmentTypes: fetchAssignmentTypes,
|
||||
getCohorts: fetchCohorts,
|
||||
getPrevNextGrades: fetchPrevNextGrades,
|
||||
getRoles,
|
||||
getTracks: fetchTracks,
|
||||
getUserGrades: fetchGrades,
|
||||
initializeFilters,
|
||||
resetFilters,
|
||||
initializeFilters: actions.filters.initialize,
|
||||
resetFilters: actions.filters.reset,
|
||||
submitFileUploadFormData,
|
||||
toggleFormat: toggleGradeFormat,
|
||||
updateAssignmentFilter,
|
||||
updateAssignmentLimits,
|
||||
toggleFormat: actions.grades.toggleGradeFormat,
|
||||
updateAssignmentFilter: actions.filters.update.assignment,
|
||||
updateAssignmentLimits: actions.filters.update.assignmentLimits,
|
||||
};
|
||||
|
||||
const GradebookPage = connect(
|
||||
|
||||
@@ -1,40 +1,14 @@
|
||||
import {
|
||||
STARTED_FETCHING_ASSIGNMENT_TYPES,
|
||||
GOT_ASSIGNMENT_TYPES,
|
||||
ERROR_FETCHING_ASSIGNMENT_TYPES,
|
||||
GOT_ARE_GRADES_FROZEN,
|
||||
} from '../constants/actionTypes/assignmentTypes';
|
||||
import GOT_BULK_MANAGEMENT_CONFIG from '../constants/actionTypes/config';
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const startedFetchingAssignmentTypes = () => ({ type: STARTED_FETCHING_ASSIGNMENT_TYPES });
|
||||
const errorFetchingAssignmentTypes = () => ({ type: ERROR_FETCHING_ASSIGNMENT_TYPES });
|
||||
const gotAssignmentTypes = assignmentTypes => ({ type: GOT_ASSIGNMENT_TYPES, assignmentTypes });
|
||||
const gotGradesFrozen = areGradesFrozen => ({ type: GOT_ARE_GRADES_FROZEN, areGradesFrozen });
|
||||
const gotBulkManagementConfig = bulkManagementEnabled => ({
|
||||
type: GOT_BULK_MANAGEMENT_CONFIG,
|
||||
data: bulkManagementEnabled,
|
||||
});
|
||||
const errorFetching = createAction('assignmentTypes/errorFetching');
|
||||
const startedFetching = createAction('assignmentTypes/startedFetching');
|
||||
|
||||
const fetchAssignmentTypes = courseId => (
|
||||
(dispatch) => {
|
||||
dispatch(startedFetchingAssignmentTypes());
|
||||
return LmsApiService.fetchAssignmentTypes(courseId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(gotAssignmentTypes(Object.keys(data.assignment_types)));
|
||||
dispatch(gotGradesFrozen(data.grades_frozen));
|
||||
dispatch(gotBulkManagementConfig(data.can_see_bulk_management));
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingAssignmentTypes());
|
||||
});
|
||||
}
|
||||
);
|
||||
const received = createAction('assignmentTypes/results'); // payload
|
||||
const gotGradesFrozen = createAction('assignmentTypes/gotGradesFrozen'); // payload
|
||||
|
||||
export {
|
||||
fetchAssignmentTypes,
|
||||
startedFetchingAssignmentTypes,
|
||||
gotAssignmentTypes,
|
||||
errorFetchingAssignmentTypes,
|
||||
errorFetching,
|
||||
startedFetching,
|
||||
received,
|
||||
gotGradesFrozen,
|
||||
};
|
||||
|
||||
@@ -1,31 +1,12 @@
|
||||
import {
|
||||
STARTED_FETCHING_COHORTS,
|
||||
GOT_COHORTS,
|
||||
ERROR_FETCHING_COHORTS,
|
||||
} from '../constants/actionTypes/cohorts';
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const startedFetchingCohorts = () => ({ type: STARTED_FETCHING_COHORTS });
|
||||
const errorFetchingCohorts = () => ({ type: ERROR_FETCHING_COHORTS });
|
||||
const gotCohorts = cohorts => ({ type: GOT_COHORTS, cohorts });
|
||||
|
||||
const fetchCohorts = courseId => (
|
||||
(dispatch) => {
|
||||
dispatch(startedFetchingCohorts());
|
||||
return LmsApiService.fetchCohorts(courseId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(gotCohorts(data.cohorts));
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingCohorts());
|
||||
});
|
||||
}
|
||||
);
|
||||
const startedFetching = createAction('cohorts/startedFetching');
|
||||
const errorFetching = createAction('cohorts/errorFetching');
|
||||
const received = createAction('cohorts/received');
|
||||
|
||||
export {
|
||||
fetchCohorts,
|
||||
startedFetchingCohorts,
|
||||
gotCohorts,
|
||||
errorFetchingCohorts,
|
||||
errorFetching,
|
||||
received,
|
||||
startedFetching,
|
||||
};
|
||||
|
||||
8
src/data/actions/config.js
Normal file
8
src/data/actions/config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const gotBulkManagementConfig = createAction('config/gotBulkManagement'); // payload
|
||||
|
||||
export {
|
||||
gotBulkManagementConfig,
|
||||
};
|
||||
@@ -1,18 +1,7 @@
|
||||
import filterSelectors from 'data/selectors/filters';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import initialFilters from '../constants/filters';
|
||||
import {
|
||||
INITIALIZE_FILTERS,
|
||||
RESET_FILTERS,
|
||||
UPDATE_ASSIGNMENT_FILTER,
|
||||
UPDATE_ASSIGNMENT_LIMITS,
|
||||
UPDATE_COURSE_GRADE_LIMITS,
|
||||
UPDATE_INCLUDE_COURSE_ROLE_MEMBERS,
|
||||
} from '../constants/actionTypes/filters';
|
||||
import { fetchGrades } from './grades';
|
||||
|
||||
const { allFilters } = filterSelectors;
|
||||
|
||||
const initializeFilters = ({
|
||||
const initialize = createAction('filters/initialize', ({
|
||||
assignment = initialFilters.assignment,
|
||||
assignmentType = initialFilters.assignmentType,
|
||||
track = initialFilters.track,
|
||||
@@ -23,8 +12,7 @@ const initializeFilters = ({
|
||||
courseGradeMax = initialFilters.assignmentGradeMax,
|
||||
includeCourseRoleMembers = initialFilters.includeCourseRoleMembers,
|
||||
}) => ({
|
||||
type: INITIALIZE_FILTERS,
|
||||
data: {
|
||||
payload: {
|
||||
assignment: { id: assignment },
|
||||
assignmentType,
|
||||
track,
|
||||
@@ -35,47 +23,19 @@ const initializeFilters = ({
|
||||
courseGradeMax,
|
||||
includeCourseRoleMembers: Boolean(includeCourseRoleMembers),
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const resetFilters = filterNames => ({
|
||||
type: RESET_FILTERS,
|
||||
filterNames,
|
||||
});
|
||||
|
||||
const updateAssignmentFilter = assignment => ({
|
||||
type: UPDATE_ASSIGNMENT_FILTER,
|
||||
data: assignment,
|
||||
});
|
||||
|
||||
const updateAssignmentLimits = (minGrade, maxGrade) => ({
|
||||
type: UPDATE_ASSIGNMENT_LIMITS,
|
||||
data: { minGrade, maxGrade },
|
||||
});
|
||||
|
||||
const updateCourseGradeFilter = (courseGradeMin, courseGradeMax, courseId) => ({
|
||||
type: UPDATE_COURSE_GRADE_LIMITS,
|
||||
data: {
|
||||
courseGradeMin,
|
||||
courseGradeMax,
|
||||
courseId,
|
||||
},
|
||||
});
|
||||
|
||||
const updateIncludeCourseRoleMembersFilter = (includeCourseRoleMembers) => ({
|
||||
type: UPDATE_INCLUDE_COURSE_ROLE_MEMBERS,
|
||||
data: {
|
||||
includeCourseRoleMembers,
|
||||
},
|
||||
});
|
||||
|
||||
const updateIncludeCourseRoleMembers = includeCourseRoleMembers => (dispatch, getState) => {
|
||||
dispatch(updateIncludeCourseRoleMembersFilter(includeCourseRoleMembers));
|
||||
const state = getState();
|
||||
const { cohort, track, assignmentType } = allFilters(state);
|
||||
dispatch(fetchGrades(state.grades.courseId, cohort, track, assignmentType));
|
||||
const reset = createAction('filters/reset'); // paylaod
|
||||
const update = {
|
||||
assignment: createAction('filters/update/assignment'),
|
||||
assignmentType: createAction('filters/update/assignmentType'),
|
||||
assignmentLimits: createAction('filters/update/assignmentLimits'),
|
||||
courseGrade: createAction('filters/update/courseGrade'),
|
||||
includeCourseRoleMembers: createAction('filters/update/includeCourseRoleMembers'),
|
||||
};
|
||||
|
||||
export {
|
||||
initializeFilters, resetFilters, updateAssignmentFilter,
|
||||
updateAssignmentLimits, updateCourseGradeFilter, updateIncludeCourseRoleMembers,
|
||||
initialize,
|
||||
reset,
|
||||
update,
|
||||
};
|
||||
|
||||
@@ -1,359 +1,97 @@
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import gradesSelectors from 'data/selectors/grades';
|
||||
import filtersSelectors from 'data/selectors/filters';
|
||||
import {
|
||||
STARTED_FETCHING_GRADES,
|
||||
FINISHED_FETCHING_GRADES,
|
||||
ERROR_FETCHING_GRADES,
|
||||
GOT_GRADES,
|
||||
GRADE_UPDATE_REQUEST,
|
||||
GRADE_UPDATE_SUCCESS,
|
||||
GRADE_UPDATE_FAILURE,
|
||||
TOGGLE_GRADE_FORMAT,
|
||||
FILTER_BY_ASSIGNMENT_TYPE,
|
||||
OPEN_BANNER,
|
||||
CLOSE_BANNER,
|
||||
START_UPLOAD,
|
||||
UPLOAD_COMPLETE,
|
||||
UPLOAD_ERR,
|
||||
GOT_BULK_HISTORY,
|
||||
BULK_HISTORY_ERR,
|
||||
GOT_GRADE_OVERRIDE_HISTORY,
|
||||
DONE_VIEWING_ASSIGNMENT,
|
||||
ERROR_FETCHING_GRADE_OVERRIDE_HISTORY,
|
||||
UPLOAD_OVERRIDE,
|
||||
UPLOAD_OVERRIDE_ERROR,
|
||||
BULK_GRADE_REPORT_DOWNLOADED,
|
||||
INTERVENTION_REPORT_DOWNLOADED,
|
||||
} from '../constants/actionTypes/grades';
|
||||
import GRADE_OVERRIDE_HISTORY_ERROR_DEFAULT_MSG from '../constants/errors';
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
import { sortAlphaAsc, formatDateForDisplay } from './utils';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const {
|
||||
formatMaxAssignmentGrade,
|
||||
formatMinAssignmentGrade,
|
||||
formatMaxCourseGrade,
|
||||
formatMinCourseGrade,
|
||||
} = gradesSelectors;
|
||||
const { allFilters } = filtersSelectors;
|
||||
|
||||
const defaultAssignmentFilter = 'All';
|
||||
|
||||
const startedCsvUpload = () => ({ type: START_UPLOAD });
|
||||
const finishedCsvUpload = () => ({ type: UPLOAD_COMPLETE });
|
||||
const csvUploadError = data => ({ type: UPLOAD_ERR, data });
|
||||
const gotBulkHistory = data => ({ type: GOT_BULK_HISTORY, data });
|
||||
const bulkHistoryError = () => ({ type: BULK_HISTORY_ERR });
|
||||
|
||||
const startedFetchingGrades = () => ({ type: STARTED_FETCHING_GRADES });
|
||||
const finishedFetchingGrades = () => ({ type: FINISHED_FETCHING_GRADES });
|
||||
const errorFetchingGrades = () => ({ type: ERROR_FETCHING_GRADES });
|
||||
const errorFetchingGradeOverrideHistory = errorMessage => ({
|
||||
type: ERROR_FETCHING_GRADE_OVERRIDE_HISTORY,
|
||||
errorMessage,
|
||||
});
|
||||
|
||||
const gotGrades = ({
|
||||
grades, cohort, track, assignmentType, headings, prev,
|
||||
next, courseId, totalUsersCount, filteredUsersCount,
|
||||
}) => ({
|
||||
type: GOT_GRADES,
|
||||
grades,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
headings,
|
||||
prev,
|
||||
next,
|
||||
courseId,
|
||||
totalUsersCount,
|
||||
filteredUsersCount,
|
||||
});
|
||||
|
||||
const gotGradeOverrideHistory = ({
|
||||
overrideHistory, currentEarnedAllOverride, currentPossibleAllOverride,
|
||||
currentEarnedGradedOverride, currentPossibleGradedOverride,
|
||||
originalGradeEarnedAll, originalGradePossibleAll, originalGradeEarnedGraded,
|
||||
originalGradePossibleGraded,
|
||||
}) => ({
|
||||
type: GOT_GRADE_OVERRIDE_HISTORY,
|
||||
overrideHistory,
|
||||
currentEarnedAllOverride,
|
||||
currentPossibleAllOverride,
|
||||
currentEarnedGradedOverride,
|
||||
currentPossibleGradedOverride,
|
||||
originalGradeEarnedAll,
|
||||
originalGradePossibleAll,
|
||||
originalGradeEarnedGraded,
|
||||
originalGradePossibleGraded,
|
||||
});
|
||||
|
||||
const gradeUpdateRequest = () => ({ type: GRADE_UPDATE_REQUEST });
|
||||
const gradeUpdateSuccess = (courseId, responseData) => ({
|
||||
type: GRADE_UPDATE_SUCCESS,
|
||||
courseId,
|
||||
payload: { responseData },
|
||||
});
|
||||
const gradeUpdateFailure = (courseId, error) => ({
|
||||
type: GRADE_UPDATE_FAILURE,
|
||||
courseId,
|
||||
payload: { error },
|
||||
});
|
||||
const uploadOverrideSuccess = courseId => ({
|
||||
type: UPLOAD_OVERRIDE,
|
||||
courseId,
|
||||
});
|
||||
// This action for google analytics only. Doesn't change redux state.
|
||||
const downloadBulkGradesReport = courseId => ({
|
||||
type: BULK_GRADE_REPORT_DOWNLOADED,
|
||||
courseId,
|
||||
});
|
||||
// This action for google analytics only. Doesn't change redux state.
|
||||
const downloadInterventionReport = courseId => ({
|
||||
type: INTERVENTION_REPORT_DOWNLOADED,
|
||||
courseId,
|
||||
});
|
||||
const uploadOverrideFailure = (courseId, error) => ({
|
||||
type: UPLOAD_OVERRIDE_ERROR,
|
||||
courseId,
|
||||
payload: { error },
|
||||
});
|
||||
|
||||
const toggleGradeFormat = formatType => ({ type: TOGGLE_GRADE_FORMAT, formatType });
|
||||
|
||||
const filterAssignmentType = filterType => (
|
||||
dispatch => dispatch({
|
||||
type: FILTER_BY_ASSIGNMENT_TYPE,
|
||||
filterType,
|
||||
})
|
||||
);
|
||||
|
||||
const openBanner = () => ({ type: OPEN_BANNER });
|
||||
const closeBanner = () => ({ type: CLOSE_BANNER });
|
||||
|
||||
const fetchGrades = (
|
||||
courseId,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
options = {},
|
||||
) => (
|
||||
(dispatch, getState) => {
|
||||
dispatch(startedFetchingGrades());
|
||||
const {
|
||||
assignment,
|
||||
assignmentGradeMax: assignmentMax,
|
||||
assignmentGradeMin: assignmentMin,
|
||||
courseGradeMin,
|
||||
courseGradeMax,
|
||||
includeCourseRoleMembers,
|
||||
} = allFilters(getState());
|
||||
const { id: assignmentId } = assignment || {};
|
||||
const assignmentGradeMax = formatMaxAssignmentGrade(assignmentMax, { assignmentId });
|
||||
const assignmentGradeMin = formatMinAssignmentGrade(assignmentMin, { assignmentId });
|
||||
const courseGradeMinFormatted = formatMinCourseGrade(courseGradeMin);
|
||||
const courseGradeMaxFormatted = formatMaxCourseGrade(courseGradeMax);
|
||||
return LmsApiService.fetchGradebookData(
|
||||
courseId,
|
||||
options.searchText || null,
|
||||
cohort,
|
||||
track,
|
||||
{
|
||||
assignment: assignmentId,
|
||||
assignmentGradeMax,
|
||||
assignmentGradeMin,
|
||||
courseGradeMin: courseGradeMinFormatted,
|
||||
courseGradeMax: courseGradeMaxFormatted,
|
||||
includeCourseRoleMembers,
|
||||
const csvUpload = {
|
||||
started: createAction('grades/csvUpload/started'),
|
||||
finished: createAction('grades/csvUpload/finished'),
|
||||
error: createAction('grades/csvUpload/error'),
|
||||
};
|
||||
const bulkHistory = {
|
||||
received: createAction('grades/bulkHistory/received'),
|
||||
error: createAction('grades/bulkHistory/error'),
|
||||
};
|
||||
const fetching = {
|
||||
started: createAction('grades/fetching/started'),
|
||||
finished: createAction('grades/fetching/finished'),
|
||||
error: createAction('grades/fetching/error'),
|
||||
};
|
||||
const overrideHistory = {
|
||||
errorFetching: createAction('grades/overrideHistory/errorFetching'),
|
||||
received: createAction(
|
||||
'grades/overrideHistory/received',
|
||||
(data) => ({
|
||||
payload: {
|
||||
overrideHistory: data.overrideHistory,
|
||||
currentEarnedAllOverride: data.currentEarnedAllOverride,
|
||||
currentPossibleAllOverride: data.currentPossibleAllOverride,
|
||||
currentEarnedGradedOverride: data.currentEarnedGradedOverride,
|
||||
currentPossibleGradedOverride: data.currentPossibleGradedOverride,
|
||||
originalGradeEarnedAll: data.originalGradeEarnedAll,
|
||||
originalGradePossibleAll: data.originalGradePossibleAll,
|
||||
originalGradeEarnedGraded: data.originalGradeEarnedGraded,
|
||||
originalGradePossibleGraded: data.originalGradePossibleGraded,
|
||||
},
|
||||
|
||||
)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(gotGrades({
|
||||
grades: data.results.sort(sortAlphaAsc),
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
prev: data.previous,
|
||||
next: data.next,
|
||||
courseId,
|
||||
totalUsersCount: data.total_users_count,
|
||||
filteredUsersCount: data.filtered_users_count,
|
||||
}));
|
||||
dispatch(finishedFetchingGrades());
|
||||
if (options.showSuccess) {
|
||||
dispatch(openBanner());
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingGrades());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const formatGradeOverrideForDisplay = historyArray => historyArray.map(item => ({
|
||||
date: formatDateForDisplay(new Date(item.history_date)),
|
||||
grader: item.history_user,
|
||||
reason: item.override_reason,
|
||||
adjustedGrade: item.earned_graded_override,
|
||||
}));
|
||||
|
||||
const doneViewingAssignment = () => dispatch => dispatch({
|
||||
type: DONE_VIEWING_ASSIGNMENT,
|
||||
});
|
||||
const fetchGradeOverrideHistory = (subsectionId, userId) => (
|
||||
dispatch => LmsApiService.fetchGradeOverrideHistory(subsectionId, userId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
dispatch(gotGradeOverrideHistory({
|
||||
overrideHistory: formatGradeOverrideForDisplay(data.history),
|
||||
currentEarnedAllOverride: data.override ? data.override.earned_all_override : null,
|
||||
currentPossibleAllOverride: data.override ? data.override.possible_all_override : null,
|
||||
currentEarnedGradedOverride: data.override ? data.override.earned_graded_override : null,
|
||||
currentPossibleGradedOverride: data.override
|
||||
? data.override.possible_graded_override : null,
|
||||
originalGradeEarnedAll: data.original_grade ? data.original_grade.earned_all : null,
|
||||
originalGradePossibleAll: data.original_grade ? data.original_grade.possible_all : null,
|
||||
originalGradeEarnedGraded: data.original_grade
|
||||
? data.original_grade.earned_graded : null,
|
||||
originalGradePossibleGraded: data.original_grade
|
||||
? data.original_grade.possible_graded : null,
|
||||
}));
|
||||
} else {
|
||||
dispatch(errorFetchingGradeOverrideHistory(data.error_message));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingGradeOverrideHistory(GRADE_OVERRIDE_HISTORY_ERROR_DEFAULT_MSG));
|
||||
})
|
||||
);
|
||||
|
||||
const fetchMatchingUserGrades = (
|
||||
courseId,
|
||||
searchText,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
showSuccess,
|
||||
options = {},
|
||||
) => {
|
||||
const newOptions = { ...options, searchText, showSuccess };
|
||||
return fetchGrades(courseId, cohort, track, assignmentType, newOptions);
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
const fetchPrevNextGrades = (endpoint, courseId, cohort, track, assignmentType) => (
|
||||
(dispatch) => {
|
||||
dispatch(startedFetchingGrades());
|
||||
return getAuthenticatedHttpClient().get(endpoint)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(gotGrades({
|
||||
grades: data.results.sort(sortAlphaAsc),
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
prev: data.previous,
|
||||
next: data.next,
|
||||
courseId,
|
||||
totalUsersCount: data.total_users_count,
|
||||
filteredUsersCount: data.filtered_users_count,
|
||||
}));
|
||||
dispatch(finishedFetchingGrades());
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingGrades());
|
||||
});
|
||||
}
|
||||
const received = createAction(
|
||||
'grades/received',
|
||||
(data) => ({
|
||||
payload: {
|
||||
grades: data.grades,
|
||||
cohort: data.cohort,
|
||||
track: data.track,
|
||||
assignmentType: data.assignmentType,
|
||||
headings: data.headings,
|
||||
prev: data.prev,
|
||||
next: data.next,
|
||||
courseId: data.courseId,
|
||||
totalUsersCount: data.totalUsersCount,
|
||||
filteredUsersCount: data.filteredUsersCount,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const updateGrades = (courseId, updateData, searchText, cohort, track) => (
|
||||
(dispatch) => {
|
||||
dispatch(gradeUpdateRequest());
|
||||
return LmsApiService.updateGradebookData(courseId, updateData)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(gradeUpdateSuccess(courseId, data));
|
||||
dispatch(fetchMatchingUserGrades(
|
||||
courseId,
|
||||
searchText,
|
||||
cohort,
|
||||
track,
|
||||
defaultAssignmentFilter,
|
||||
true,
|
||||
{ searchText },
|
||||
));
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch(gradeUpdateFailure(courseId, error));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const submitFileUploadFormData = (courseId, formData) => (
|
||||
(dispatch) => {
|
||||
dispatch(startedCsvUpload());
|
||||
return LmsApiService.uploadGradeCsv(courseId, formData).then(() => {
|
||||
dispatch(finishedCsvUpload());
|
||||
dispatch(uploadOverrideSuccess(courseId));
|
||||
}).catch((err) => {
|
||||
dispatch(uploadOverrideFailure(courseId, err));
|
||||
if (err.status === 200 && err.data.error_messages.length) {
|
||||
const { error_messages: errorMessages, saved, total } = err.data;
|
||||
return dispatch(csvUploadError({ errorMessages, saved, total }));
|
||||
}
|
||||
return dispatch(csvUploadError({ errorMessages: ['Unknown error.'] }));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const fetchBulkUpgradeHistory = courseId => (
|
||||
// todo add loading effect
|
||||
dispatch => LmsApiService.fetchGradeBulkOperationHistory(courseId).then(
|
||||
(response) => { dispatch(gotBulkHistory(response)); },
|
||||
).catch(() => dispatch(bulkHistoryError()))
|
||||
);
|
||||
|
||||
const updateGradesIfAssignmentGradeFiltersSet = (
|
||||
courseId,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
) => (dispatch, getState) => {
|
||||
const { filters } = getState();
|
||||
const hasAssignmentGradeFiltersSet = filters.assignmentGradeMax || filters.assignmentGradeMin;
|
||||
if (hasAssignmentGradeFiltersSet) {
|
||||
dispatch(fetchGrades(
|
||||
courseId,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
));
|
||||
}
|
||||
const update = {
|
||||
request: createAction('grades/update/request'),
|
||||
success: createAction('grades/update/success'),
|
||||
failure: createAction('grades/update/failure', (courseId, error) => ({
|
||||
payload: { courseId, error },
|
||||
})),
|
||||
};
|
||||
|
||||
const uploadOverride = {
|
||||
success: createAction('grades/uploadOverride/success'),
|
||||
failure: createAction('grades/uploadOverride/failure', (courseId, error) => ({
|
||||
payload: { courseId, error },
|
||||
})),
|
||||
};
|
||||
|
||||
// These actions for google analytics only. Doesn't change redux state.
|
||||
const downloadReport = {
|
||||
bulkGrades: createAction('grades/downloadReport/bulkGrades'),
|
||||
intervention: createAction('grades/downloadReport/intervention'),
|
||||
};
|
||||
|
||||
const toggleGradeFormat = createAction('grades/toggleGradeFormat');
|
||||
|
||||
const banner = {
|
||||
open: createAction('grades/banner/open'),
|
||||
close: createAction('grades/banner/close'),
|
||||
};
|
||||
|
||||
const doneViewingAssignment = createAction('grades/doneViewingAssignment');
|
||||
|
||||
export {
|
||||
startedFetchingGrades,
|
||||
finishedFetchingGrades,
|
||||
errorFetchingGrades,
|
||||
gotGrades,
|
||||
fetchGrades,
|
||||
fetchMatchingUserGrades,
|
||||
fetchPrevNextGrades,
|
||||
gradeUpdateRequest,
|
||||
gradeUpdateSuccess,
|
||||
gradeUpdateFailure,
|
||||
updateGrades,
|
||||
toggleGradeFormat,
|
||||
filterAssignmentType,
|
||||
closeBanner,
|
||||
submitFileUploadFormData,
|
||||
fetchBulkUpgradeHistory,
|
||||
banner,
|
||||
bulkHistory,
|
||||
csvUpload,
|
||||
doneViewingAssignment,
|
||||
fetchGradeOverrideHistory,
|
||||
updateGradesIfAssignmentGradeFiltersSet,
|
||||
downloadBulkGradesReport,
|
||||
downloadInterventionReport,
|
||||
downloadReport,
|
||||
fetching,
|
||||
overrideHistory,
|
||||
received,
|
||||
toggleGradeFormat,
|
||||
update,
|
||||
uploadOverride,
|
||||
};
|
||||
|
||||
15
src/data/actions/index.js
Normal file
15
src/data/actions/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as assignmentTypes from './assignmentTypes';
|
||||
import * as cohorts from './cohorts';
|
||||
import * as config from './config';
|
||||
import * as grades from './grades';
|
||||
import * as roles from './roles';
|
||||
import * as tracks from './tracks';
|
||||
|
||||
export {
|
||||
assignmentTypes,
|
||||
cohorts,
|
||||
config,
|
||||
grades,
|
||||
roles,
|
||||
tracks,
|
||||
};
|
||||
@@ -1,46 +1,9 @@
|
||||
import filtersSelectors from 'data/selectors/filters';
|
||||
import {
|
||||
GOT_ROLES,
|
||||
ERROR_FETCHING_ROLES,
|
||||
} from '../constants/actionTypes/roles';
|
||||
import { fetchGrades } from './grades';
|
||||
import { fetchTracks } from './tracks';
|
||||
import { fetchCohorts } from './cohorts';
|
||||
import { fetchAssignmentTypes } from './assignmentTypes';
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const { allFilters } = filtersSelectors;
|
||||
|
||||
const allowedRoles = ['staff', 'instructor', 'support'];
|
||||
|
||||
const gotRoles = (canUserViewGradebook, courseId) => ({
|
||||
type: GOT_ROLES,
|
||||
canUserViewGradebook,
|
||||
courseId,
|
||||
});
|
||||
const errorFetchingRoles = () => ({ type: ERROR_FETCHING_ROLES });
|
||||
|
||||
const getRoles = courseId => (
|
||||
(dispatch, getState) => LmsApiService.fetchUserRoles(courseId)
|
||||
.then(response => response.data)
|
||||
.then((response) => {
|
||||
const canUserViewGradebook = response.is_staff
|
||||
|| (response.roles.some(role => (role.course_id === courseId)
|
||||
&& allowedRoles.includes(role.role)));
|
||||
dispatch(gotRoles(canUserViewGradebook, courseId));
|
||||
const { cohort, track, assignmentType } = allFilters(getState());
|
||||
if (canUserViewGradebook) {
|
||||
dispatch(fetchGrades(courseId, cohort, track, assignmentType));
|
||||
dispatch(fetchTracks(courseId));
|
||||
dispatch(fetchCohorts(courseId));
|
||||
dispatch(fetchAssignmentTypes(courseId));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingRoles());
|
||||
}));
|
||||
const errorFetching = createAction('roles/errorFetching');
|
||||
const received = createAction('roles/received');
|
||||
|
||||
export {
|
||||
getRoles,
|
||||
errorFetchingRoles,
|
||||
errorFetching,
|
||||
received,
|
||||
};
|
||||
|
||||
@@ -1,39 +1,12 @@
|
||||
/* eslint-disable camelcase */
|
||||
import tracksSelectors from 'data/selectors/tracks';
|
||||
import {
|
||||
STARTED_FETCHING_TRACKS,
|
||||
GOT_TRACKS,
|
||||
ERROR_FETCHING_TRACKS,
|
||||
} from '../constants/actionTypes/tracks';
|
||||
import { fetchBulkUpgradeHistory } from './grades';
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
|
||||
const { hasMastersTrack } = tracksSelectors;
|
||||
|
||||
const startedFetchingTracks = () => ({ type: STARTED_FETCHING_TRACKS });
|
||||
const errorFetchingTracks = () => ({ type: ERROR_FETCHING_TRACKS });
|
||||
const gotTracks = (tracks) => ({ type: GOT_TRACKS, tracks });
|
||||
|
||||
const fetchTracks = (courseId) => (
|
||||
(dispatch) => {
|
||||
dispatch(startedFetchingTracks());
|
||||
return LmsApiService.fetchTracks(courseId)
|
||||
.then(({ data }) => data)
|
||||
.then(({ course_modes }) => {
|
||||
dispatch(gotTracks(course_modes));
|
||||
if (hasMastersTrack(course_modes)) {
|
||||
dispatch(fetchBulkUpgradeHistory(courseId));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(errorFetchingTracks());
|
||||
});
|
||||
}
|
||||
);
|
||||
const fetching = {
|
||||
started: createAction('tracks/fetching/started'),
|
||||
error: createAction('tracks/fetching/error'),
|
||||
received: createAction('tracks/fetching/received'),
|
||||
};
|
||||
|
||||
export {
|
||||
fetchTracks,
|
||||
startedFetchingTracks,
|
||||
gotTracks,
|
||||
errorFetchingTracks,
|
||||
fetching,
|
||||
};
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const STARTED_FETCHING_ASSIGNMENT_TYPES = 'STARTED_FETCHING_ASSIGNMENT_TYPES';
|
||||
const GOT_ASSIGNMENT_TYPES = 'GOT_ASSIGNMENT_TYPES';
|
||||
const ERROR_FETCHING_ASSIGNMENT_TYPES = 'ERROR_FETCHING_ASSIGNMENT_TYPES';
|
||||
const GOT_ARE_GRADES_FROZEN = 'GOT_ARE_GRADES_FROZEN';
|
||||
|
||||
export {
|
||||
STARTED_FETCHING_ASSIGNMENT_TYPES,
|
||||
GOT_ASSIGNMENT_TYPES,
|
||||
ERROR_FETCHING_ASSIGNMENT_TYPES,
|
||||
GOT_ARE_GRADES_FROZEN,
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
const STARTED_FETCHING_COHORTS = 'STARTED_FETCHING_COHORTS';
|
||||
const GOT_COHORTS = 'GOT_COHORTS';
|
||||
const ERROR_FETCHING_COHORTS = 'ERROR_FETCHING_COHORTS';
|
||||
|
||||
export {
|
||||
STARTED_FETCHING_COHORTS,
|
||||
GOT_COHORTS,
|
||||
ERROR_FETCHING_COHORTS,
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
const GOT_BULK_MANAGEMENT_CONFIG = 'GOT_BULK_MANAGEMENT_CONFIG';
|
||||
|
||||
export default GOT_BULK_MANAGEMENT_CONFIG;
|
||||
@@ -1,10 +0,0 @@
|
||||
const INITIALIZE_FILTERS = 'INITIALIZE_FILTERS';
|
||||
const RESET_FILTERS = 'RESET_FILTERS';
|
||||
const UPDATE_ASSIGNMENT_FILTER = 'UPDATE_ASSIGNMENT_FILTER';
|
||||
const UPDATE_ASSIGNMENT_LIMITS = 'UPDATE_ASSIGNMENT_LIMITS';
|
||||
const UPDATE_COURSE_GRADE_LIMITS = 'UPDATE_COURSE_GRADE_LIMITS';
|
||||
const UPDATE_INCLUDE_COURSE_ROLE_MEMBERS = 'UPDATE_INCLUDE_COURSE_ROLE_MEMBERS';
|
||||
export {
|
||||
INITIALIZE_FILTERS, RESET_FILTERS, UPDATE_ASSIGNMENT_FILTER,
|
||||
UPDATE_ASSIGNMENT_LIMITS, UPDATE_COURSE_GRADE_LIMITS, UPDATE_INCLUDE_COURSE_ROLE_MEMBERS,
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
const STARTED_FETCHING_GRADES = 'STARTED_FETCHING_GRADES';
|
||||
const FINISHED_FETCHING_GRADES = 'FINISHED_FETCHING_GRADES';
|
||||
const ERROR_FETCHING_GRADES = 'ERROR_FETCHING_GRADES';
|
||||
const GOT_GRADES = 'GOT_GRADES';
|
||||
const DONE_VIEWING_ASSIGNMENT = 'DONE_VIEWING_ASSIGNMENT';
|
||||
const GOT_GRADE_OVERRIDE_HISTORY = 'GOT_GRADE_OVERRIDE_HISTORY';
|
||||
const ERROR_FETCHING_GRADE_OVERRIDE_HISTORY = 'ERROR_FETCHING_GRADE_OVERRIDE_HISTORY';
|
||||
|
||||
const FILTER_SELECTED = 'FILTER_SELECTED';
|
||||
const GRADE_OVERRIDE = 'GRADE_OVERRIDE';
|
||||
const REPORT_DOWNLOADED = 'REPORT_DOWNLOADED';
|
||||
const UPLOAD_OVERRIDE = 'UPLOAD_OVERRIDE';
|
||||
const UPLOAD_OVERRIDE_ERROR = 'UPLOAD_OVERRIDE_ERROR';
|
||||
|
||||
const GRADE_UPDATE_REQUEST = 'GRADE_UPDATE_REQUEST';
|
||||
const GRADE_UPDATE_SUCCESS = 'GRADE_UPDATE_SUCCESS';
|
||||
const GRADE_UPDATE_FAILURE = 'GRADE_UPDATE_FAILURE';
|
||||
|
||||
const TOGGLE_GRADE_FORMAT = 'TOGGLE_GRADE_FORMAT';
|
||||
const FILTER_BY_ASSIGNMENT_TYPE = 'FILTER_BY_ASSIGNMENT_TYPE';
|
||||
const CLOSE_BANNER = 'CLOSE_BANNER';
|
||||
const OPEN_BANNER = 'OPEN_BANNER';
|
||||
|
||||
const START_UPLOAD = 'START_UPLOAD';
|
||||
const UPLOAD_COMPLETE = 'UPLOAD_COMPLETE';
|
||||
const UPLOAD_ERR = 'UPLOAD_ERR';
|
||||
const GOT_BULK_HISTORY = 'GOT_BULK_HISTORY';
|
||||
const BULK_HISTORY_ERR = 'BULK_HISTORY_ERR';
|
||||
const BULK_GRADE_REPORT_DOWNLOADED = 'BULK_GRADE_REPORT_DOWNLOADED';
|
||||
const INTERVENTION_REPORT_DOWNLOADED = 'INTERVENTION_REPORT_DOWNLOADED';
|
||||
|
||||
export {
|
||||
STARTED_FETCHING_GRADES,
|
||||
FINISHED_FETCHING_GRADES,
|
||||
ERROR_FETCHING_GRADES,
|
||||
GOT_GRADES,
|
||||
GRADE_UPDATE_REQUEST,
|
||||
GRADE_UPDATE_SUCCESS,
|
||||
GRADE_UPDATE_FAILURE,
|
||||
TOGGLE_GRADE_FORMAT,
|
||||
FILTER_BY_ASSIGNMENT_TYPE,
|
||||
OPEN_BANNER,
|
||||
CLOSE_BANNER,
|
||||
START_UPLOAD,
|
||||
UPLOAD_COMPLETE,
|
||||
UPLOAD_ERR,
|
||||
GOT_BULK_HISTORY,
|
||||
BULK_HISTORY_ERR,
|
||||
DONE_VIEWING_ASSIGNMENT,
|
||||
GOT_GRADE_OVERRIDE_HISTORY,
|
||||
ERROR_FETCHING_GRADE_OVERRIDE_HISTORY,
|
||||
FILTER_SELECTED,
|
||||
GRADE_OVERRIDE,
|
||||
REPORT_DOWNLOADED,
|
||||
UPLOAD_OVERRIDE,
|
||||
UPLOAD_OVERRIDE_ERROR,
|
||||
BULK_GRADE_REPORT_DOWNLOADED,
|
||||
INTERVENTION_REPORT_DOWNLOADED,
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
const GOT_ROLES = 'GOT_ROLES';
|
||||
const ERROR_FETCHING_ROLES = 'ERROR_FETCHING_ROLES';
|
||||
|
||||
export {
|
||||
GOT_ROLES,
|
||||
ERROR_FETCHING_ROLES,
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
const STARTED_FETCHING_TRACKS = 'STARTED_FETCHING_TRACKS';
|
||||
const GOT_TRACKS = 'GOT_TRACKS';
|
||||
const ERROR_FETCHING_TRACKS = 'ERROR_FETCHING_TRACKS';
|
||||
|
||||
export {
|
||||
STARTED_FETCHING_TRACKS,
|
||||
GOT_TRACKS,
|
||||
ERROR_FETCHING_TRACKS,
|
||||
};
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
STARTED_FETCHING_ASSIGNMENT_TYPES,
|
||||
ERROR_FETCHING_ASSIGNMENT_TYPES,
|
||||
GOT_ASSIGNMENT_TYPES,
|
||||
GOT_ARE_GRADES_FROZEN,
|
||||
} from '../constants/actionTypes/assignmentTypes';
|
||||
import * as actions from '../actions/assignmentTypes';
|
||||
|
||||
const initialState = {
|
||||
results: [],
|
||||
@@ -11,30 +6,30 @@ const initialState = {
|
||||
errorFetching: false,
|
||||
};
|
||||
|
||||
const assignmentTypes = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_ASSIGNMENT_TYPES:
|
||||
const assignmentTypes = (state = initialState, { type, payload }) => {
|
||||
switch (type) {
|
||||
case actions.received.toString():
|
||||
return {
|
||||
...state,
|
||||
results: action.assignmentTypes,
|
||||
results: payload,
|
||||
errorFetching: false,
|
||||
finishedFetching: true,
|
||||
};
|
||||
case STARTED_FETCHING_ASSIGNMENT_TYPES:
|
||||
case actions.startedFetching.toString():
|
||||
return {
|
||||
...state,
|
||||
startedFetching: true,
|
||||
};
|
||||
case ERROR_FETCHING_ASSIGNMENT_TYPES:
|
||||
case actions.errorFetching.toString():
|
||||
return {
|
||||
...state,
|
||||
finishedFetching: true,
|
||||
errorFetching: true,
|
||||
};
|
||||
case GOT_ARE_GRADES_FROZEN:
|
||||
case actions.gotGradesFrozen.toString():
|
||||
return {
|
||||
...state,
|
||||
areGradesFrozen: action.areGradesFrozen,
|
||||
areGradesFrozen: payload,
|
||||
errorFetching: false,
|
||||
finishedFetching: true,
|
||||
};
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
STARTED_FETCHING_COHORTS,
|
||||
ERROR_FETCHING_COHORTS,
|
||||
GOT_COHORTS,
|
||||
} from '../constants/actionTypes/cohorts';
|
||||
import * as actions from '../actions/cohorts';
|
||||
|
||||
const initialState = {
|
||||
results: [],
|
||||
@@ -12,19 +8,19 @@ const initialState = {
|
||||
|
||||
const cohorts = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_COHORTS:
|
||||
case actions.fetching.received.toString():
|
||||
return {
|
||||
...state,
|
||||
results: action.cohorts,
|
||||
results: action.payload,
|
||||
finishedFetching: true,
|
||||
errorFetching: false,
|
||||
};
|
||||
case STARTED_FETCHING_COHORTS:
|
||||
case actions.fetching.started.toString():
|
||||
return {
|
||||
...state,
|
||||
startedFetching: true,
|
||||
};
|
||||
case ERROR_FETCHING_COHORTS:
|
||||
case actions.fetching.error.toString():
|
||||
return {
|
||||
...state,
|
||||
finishedFetching: true,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import GOT_BULK_MANAGEMENT_CONFIG from '../constants/actionTypes/config';
|
||||
import { gotBulkManagementConfig } from '../actions/config';
|
||||
|
||||
const reducer = (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_BULK_MANAGEMENT_CONFIG:
|
||||
case gotBulkManagementConfig.toString():
|
||||
return {
|
||||
...state,
|
||||
bulkManagementAvailable: action.data,
|
||||
bulkManagementAvailable: action.payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
|
||||
@@ -1,82 +1,77 @@
|
||||
import filterSelectors from 'data/selectors/filters';
|
||||
import { GOT_GRADES, FILTER_BY_ASSIGNMENT_TYPE } from '../constants/actionTypes/grades';
|
||||
import {
|
||||
INITIALIZE_FILTERS,
|
||||
UPDATE_ASSIGNMENT_FILTER,
|
||||
UPDATE_ASSIGNMENT_LIMITS,
|
||||
UPDATE_COURSE_GRADE_LIMITS,
|
||||
RESET_FILTERS,
|
||||
UPDATE_INCLUDE_COURSE_ROLE_MEMBERS,
|
||||
} from '../constants/actionTypes/filters';
|
||||
import * as actions from '../actions/filters';
|
||||
import * as gradeActions from '../actions/grades';
|
||||
import initialFilters from '../constants/filters';
|
||||
|
||||
const { getAssignmentsFromResultsSubstate, chooseRelevantAssignmentData } = filterSelectors;
|
||||
const initialState = {};
|
||||
|
||||
const reducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case FILTER_BY_ASSIGNMENT_TYPE:
|
||||
const reducer = (state = initialState, { type: actionType, payload }) => {
|
||||
switch (actionType) {
|
||||
case actions.update.assignmentType.toString():
|
||||
return {
|
||||
...state,
|
||||
assignmentType: action.filterType,
|
||||
assignmentType: payload.filterType,
|
||||
assignment: (
|
||||
action.filterType !== ''
|
||||
&& (state.assignment || {}).type !== action.filterType)
|
||||
payload.filterType !== ''
|
||||
&& (state.assignment || {}).type !== payload.filterType)
|
||||
? '' : state.assignment,
|
||||
};
|
||||
case INITIALIZE_FILTERS:
|
||||
case actions.initialize.toString():
|
||||
return {
|
||||
...state,
|
||||
...action.data,
|
||||
...payload,
|
||||
};
|
||||
case GOT_GRADES: {
|
||||
case gradeActions.received.toString(): {
|
||||
const { assignment } = state;
|
||||
const { id, type } = assignment || {};
|
||||
if (!type) {
|
||||
const relevantAssignment = getAssignmentsFromResultsSubstate(action.grades)
|
||||
.map(chooseRelevantAssignmentData)
|
||||
.find(assig => assig.id === id);
|
||||
const relevantAssignment = getAssignmentsFromResultsSubstate(
|
||||
payload.grades,
|
||||
).map(
|
||||
chooseRelevantAssignmentData,
|
||||
).find(assig => assig.id === id);
|
||||
return {
|
||||
...state,
|
||||
track: action.track,
|
||||
cohort: action.cohort,
|
||||
track: payload.track,
|
||||
cohort: payload.cohort,
|
||||
assignment: relevantAssignment,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
track: action.track,
|
||||
cohort: action.cohort,
|
||||
track: payload.track,
|
||||
cohort: payload.cohort,
|
||||
};
|
||||
}
|
||||
case RESET_FILTERS: {
|
||||
case actions.reset.toString(): {
|
||||
const result = { ...state };
|
||||
action.filterNames.forEach((filterName) => {
|
||||
payload.forEach((filterName) => {
|
||||
result[filterName] = initialFilters[filterName];
|
||||
});
|
||||
return result;
|
||||
}
|
||||
case UPDATE_ASSIGNMENT_FILTER:
|
||||
case actions.update.assignment.toString():
|
||||
return {
|
||||
...state,
|
||||
assignment: action.data,
|
||||
assignment: payload,
|
||||
};
|
||||
case UPDATE_ASSIGNMENT_LIMITS:
|
||||
case actions.update.assignmentLimits.toString():
|
||||
return {
|
||||
...state,
|
||||
assignmentGradeMin: action.data.minGrade,
|
||||
assignmentGradeMax: action.data.maxGrade,
|
||||
assignmentGradeMin: payload.minGrade,
|
||||
assignmentGradeMax: payload.maxGrade,
|
||||
};
|
||||
case UPDATE_COURSE_GRADE_LIMITS:
|
||||
case actions.update.courseGradeLimits.toString():
|
||||
return {
|
||||
...state,
|
||||
courseGradeMin: action.data.courseGradeMin,
|
||||
courseGradeMax: action.data.courseGradeMax,
|
||||
courseGradeMin: payload.courseGradeMin,
|
||||
courseGradeMax: payload.courseGradeMax,
|
||||
};
|
||||
case UPDATE_INCLUDE_COURSE_ROLE_MEMBERS:
|
||||
case actions.update.includeCourseRoleMembers.toString():
|
||||
return {
|
||||
...state,
|
||||
includeCourseRoleMembers: action.data.includeCourseRoleMembers,
|
||||
includeCourseRoleMembers: payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
import {
|
||||
STARTED_FETCHING_GRADES,
|
||||
ERROR_FETCHING_GRADES,
|
||||
GOT_GRADES,
|
||||
TOGGLE_GRADE_FORMAT,
|
||||
FILTER_BY_ASSIGNMENT_TYPE,
|
||||
OPEN_BANNER,
|
||||
CLOSE_BANNER,
|
||||
START_UPLOAD,
|
||||
UPLOAD_COMPLETE,
|
||||
UPLOAD_ERR,
|
||||
GOT_BULK_HISTORY,
|
||||
DONE_VIEWING_ASSIGNMENT,
|
||||
GOT_GRADE_OVERRIDE_HISTORY,
|
||||
ERROR_FETCHING_GRADE_OVERRIDE_HISTORY,
|
||||
} from '../constants/actionTypes/grades';
|
||||
import * as actions from '../actions/grades';
|
||||
import * as filterActions from '../actions/filters';
|
||||
|
||||
const initialState = {
|
||||
results: [],
|
||||
@@ -41,23 +27,23 @@ const initialState = {
|
||||
filteredUsersCount: 0,
|
||||
};
|
||||
|
||||
const grades = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_GRADES:
|
||||
const grades = (state = initialState, { type, payload }) => {
|
||||
switch (type) {
|
||||
case actions.received.toString():
|
||||
return {
|
||||
...state,
|
||||
results: action.grades,
|
||||
headings: action.headings,
|
||||
results: payload.grades,
|
||||
headings: payload.headings,
|
||||
finishedFetching: true,
|
||||
errorFetching: false,
|
||||
prevPage: action.prev,
|
||||
nextPage: action.next,
|
||||
prevPage: payload.prev,
|
||||
nextPage: payload.next,
|
||||
showSpinner: false,
|
||||
courseId: action.courseId,
|
||||
totalUsersCount: action.totalUsersCount,
|
||||
filteredUsersCount: action.filteredUsersCount,
|
||||
courseId: payload.courseId,
|
||||
totalUsersCount: payload.totalUsersCount,
|
||||
filteredUsersCount: payload.filteredUsersCount,
|
||||
};
|
||||
case DONE_VIEWING_ASSIGNMENT: {
|
||||
case actions.doneViewingAssignment.toString(): {
|
||||
const {
|
||||
gradeOverrideHistoryResults,
|
||||
gradeOverrideCurrentEarnedAllOverride,
|
||||
@@ -72,63 +58,63 @@ const grades = (state = initialState, action) => {
|
||||
} = state;
|
||||
return rest;
|
||||
}
|
||||
case GOT_GRADE_OVERRIDE_HISTORY:
|
||||
case actions.gradeOverride.received.toString():
|
||||
return {
|
||||
...state,
|
||||
gradeOverrideHistoryResults: action.overrideHistory,
|
||||
gradeOverrideCurrentEarnedAllOverride: action.currentEarnedAllOverride,
|
||||
gradeOverrideCurrentPossibleAllOverride: action.currentPossibleAllOverride,
|
||||
gradeOverrideCurrentEarnedGradedOverride: action.currentEarnedGradedOverride,
|
||||
gradeOverrideCurrentPossibleGradedOverride: action.currentPossibleGradedOverride,
|
||||
gradeOriginalEarnedAll: action.originalGradeEarnedAll,
|
||||
gradeOriginalPossibleAll: action.originalGradePossibleAll,
|
||||
gradeOriginalEarnedGraded: action.originalGradeEarnedGraded,
|
||||
gradeOriginalPossibleGraded: action.originalGradePossibleGraded,
|
||||
gradeOverrideHistoryResults: payload.overrideHistory,
|
||||
gradeOverrideCurrentEarnedAllOverride: payload.currentEarnedAllOverride,
|
||||
gradeOverrideCurrentPossibleAllOverride: payload.currentPossibleAllOverride,
|
||||
gradeOverrideCurrentEarnedGradedOverride: payload.currentEarnedGradedOverride,
|
||||
gradeOverrideCurrentPossibleGradedOverride: payload.currentPossibleGradedOverride,
|
||||
gradeOriginalEarnedAll: payload.originalGradeEarnedAll,
|
||||
gradeOriginalPossibleAll: payload.originalGradePossibleAll,
|
||||
gradeOriginalEarnedGraded: payload.originalGradeEarnedGraded,
|
||||
gradeOriginalPossibleGraded: payload.originalGradePossibleGraded,
|
||||
overrideHistoryError: '',
|
||||
};
|
||||
|
||||
case ERROR_FETCHING_GRADE_OVERRIDE_HISTORY:
|
||||
case actions.overrideHistory.errorFetching.toString():
|
||||
return {
|
||||
...state,
|
||||
finishedFetchingOverrideHistory: true,
|
||||
overrideHistoryError: action.errorMessage,
|
||||
overrideHistoryError: payload,
|
||||
};
|
||||
|
||||
case STARTED_FETCHING_GRADES:
|
||||
case actions.fetching.started.toString():
|
||||
return {
|
||||
...state,
|
||||
startedFetching: true,
|
||||
finishedFetching: false,
|
||||
showSpinner: true,
|
||||
};
|
||||
case ERROR_FETCHING_GRADES:
|
||||
case actions.fetching.error.toString():
|
||||
return {
|
||||
...state,
|
||||
finishedFetching: true,
|
||||
errorFetching: true,
|
||||
};
|
||||
case TOGGLE_GRADE_FORMAT:
|
||||
case actions.toggleGradeFormat.toString():
|
||||
return {
|
||||
...state,
|
||||
gradeFormat: action.formatType,
|
||||
gradeFormat: payload,
|
||||
};
|
||||
case FILTER_BY_ASSIGNMENT_TYPE:
|
||||
case filterActions.filterAssignmentType.toString():
|
||||
return {
|
||||
...state,
|
||||
selectedAssignmentType: action.filterType,
|
||||
headings: action.headings,
|
||||
selectedAssignmentType: payload.filterType,
|
||||
headings: payload.headings,
|
||||
};
|
||||
case OPEN_BANNER:
|
||||
case actions.banner.open.toString():
|
||||
return {
|
||||
...state,
|
||||
showSuccess: true,
|
||||
};
|
||||
case CLOSE_BANNER:
|
||||
case actions.banner.close.toString():
|
||||
return {
|
||||
...state,
|
||||
showSuccess: false,
|
||||
};
|
||||
case START_UPLOAD: {
|
||||
case actions.csvUpload.started.toString(): {
|
||||
const { errorMessages, uploadSuccess, ...rest } = state.bulkManagement;
|
||||
return {
|
||||
...state,
|
||||
@@ -136,7 +122,7 @@ const grades = (state = initialState, action) => {
|
||||
bulkManagement: rest,
|
||||
};
|
||||
}
|
||||
case UPLOAD_COMPLETE: {
|
||||
case actions.csvUpload.finished.toString():
|
||||
return {
|
||||
...state,
|
||||
showSpinner: false,
|
||||
@@ -145,22 +131,21 @@ const grades = (state = initialState, action) => {
|
||||
uploadSuccess: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
case UPLOAD_ERR:
|
||||
case actions.csvUpload.error.toString():
|
||||
return {
|
||||
...state,
|
||||
showSpinner: false,
|
||||
bulkManagement: {
|
||||
...state.bulkManagement,
|
||||
...action.data,
|
||||
...payload,
|
||||
},
|
||||
};
|
||||
case GOT_BULK_HISTORY:
|
||||
case actions.bulkHistory.received.toString():
|
||||
return {
|
||||
...state,
|
||||
bulkManagement: {
|
||||
...state.bulkManagement,
|
||||
history: action.data,
|
||||
history: payload,
|
||||
},
|
||||
};
|
||||
default:
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
GOT_ROLES,
|
||||
ERROR_FETCHING_ROLES,
|
||||
} from '../constants/actionTypes/roles';
|
||||
import * as actions from '../actions/roles';
|
||||
|
||||
const initialState = {
|
||||
canUserViewGradebook: null,
|
||||
@@ -9,12 +6,12 @@ const initialState = {
|
||||
|
||||
const roles = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_ROLES:
|
||||
case actions.received.toString():
|
||||
return {
|
||||
...state,
|
||||
canUserViewGradebook: action.canUserViewGradebook,
|
||||
canUserViewGradebook: action.payload,
|
||||
};
|
||||
case ERROR_FETCHING_ROLES:
|
||||
case actions.errorFetching.toString():
|
||||
return {
|
||||
...state,
|
||||
canUserViewGradebook: false,
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
STARTED_FETCHING_TRACKS,
|
||||
ERROR_FETCHING_TRACKS,
|
||||
GOT_TRACKS,
|
||||
} from '../constants/actionTypes/tracks';
|
||||
import * as actions from '../actions/tracks';
|
||||
|
||||
const initialState = {
|
||||
results: [],
|
||||
@@ -12,19 +8,19 @@ const initialState = {
|
||||
|
||||
const tracks = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_TRACKS:
|
||||
case actions.fetching.received.toString():
|
||||
return {
|
||||
...state,
|
||||
results: action.tracks,
|
||||
results: action.payload,
|
||||
errorFetching: false,
|
||||
finishedFetching: true,
|
||||
};
|
||||
case STARTED_FETCHING_TRACKS:
|
||||
case actions.fetching.started.toString():
|
||||
return {
|
||||
...state,
|
||||
startedFetching: true,
|
||||
};
|
||||
case ERROR_FETCHING_TRACKS:
|
||||
case actions.fetching.error.toString():
|
||||
return {
|
||||
...state,
|
||||
finishedFetching: true,
|
||||
|
||||
@@ -102,6 +102,23 @@ const formatMinAssignmentGrade = composeFilters(
|
||||
assignmentIdIsDefined,
|
||||
);
|
||||
|
||||
const allGrades = ({ grades: { results } }) => results;
|
||||
const uploadSuccess = ({ grades: { bulkManagement } }) => (!!bulkManagement && bulkManagement.uploadSuccess);
|
||||
|
||||
const bulkImportError = ({ grades: { bulkManagement } }) => (
|
||||
(!!bulkManagement && bulkManagement.errorMessages)
|
||||
? `Errors while processing: ${bulkManagement.errorMessages.join(', ')}`
|
||||
: ''
|
||||
);
|
||||
const gradeOverrides = ({ grades }) => grades.gradeOverrideHistoryResults;
|
||||
|
||||
const formatGradeOverrideForDisplay = historyArray => historyArray.map(item => ({
|
||||
date: formatDateForDisplay(new Date(item.history_date)),
|
||||
grader: item.history_user,
|
||||
reason: item.override_reason,
|
||||
adjustedGrade: item.earned_graded_override,
|
||||
}));
|
||||
|
||||
const simpleSelectors = simpleSelectorFactory(
|
||||
({ grades }) => grades,
|
||||
[
|
||||
@@ -117,18 +134,9 @@ const simpleSelectors = simpleSelectorFactory(
|
||||
],
|
||||
);
|
||||
|
||||
const allGrades = ({ grades: { results } }) => results;
|
||||
const uploadSuccess = ({ grades: { bulkManagement } }) => (!!bulkManagement && bulkManagement.uploadSuccess);
|
||||
|
||||
const bulkImportError = ({ grades: { bulkManagement } }) => (
|
||||
(!!bulkManagement && bulkManagement.errorMessages)
|
||||
? `Errors while processing: ${bulkManagement.errorMessages.join(', ')}`
|
||||
: ''
|
||||
);
|
||||
const gradeOverrides = ({ grades }) => grades.gradeOverrideHistoryResults;
|
||||
|
||||
const selectors = {
|
||||
bulkImportError,
|
||||
formatGradeOverrideForDisplay,
|
||||
formatMinAssignmentGrade,
|
||||
formatMaxAssignmentGrade,
|
||||
formatMaxCourseGrade,
|
||||
|
||||
@@ -4,12 +4,8 @@ import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProductio
|
||||
import { createLogger } from 'redux-logger';
|
||||
import { createMiddleware } from 'redux-beacon';
|
||||
import Segment, { trackEvent, trackPageView } from '@redux-beacon/segment';
|
||||
import { GOT_ROLES } from './constants/actionTypes/roles';
|
||||
import {
|
||||
GOT_GRADES, GRADE_UPDATE_SUCCESS, GRADE_UPDATE_FAILURE, UPLOAD_OVERRIDE,
|
||||
UPLOAD_OVERRIDE_ERROR, BULK_GRADE_REPORT_DOWNLOADED, INTERVENTION_REPORT_DOWNLOADED,
|
||||
} from './constants/actionTypes/grades';
|
||||
import { UPDATE_COURSE_GRADE_LIMITS } from './constants/actionTypes/filters';
|
||||
|
||||
import * as actions from './actions';
|
||||
|
||||
import reducers from './reducers';
|
||||
|
||||
@@ -17,75 +13,79 @@ const loggerMiddleware = createLogger();
|
||||
const trackingCategory = 'gradebook';
|
||||
|
||||
const eventsMap = {
|
||||
[GOT_ROLES]: trackPageView(action => ({
|
||||
[actions.roles.received.toString()]: trackPageView(({ payload }) => ({
|
||||
category: trackingCategory,
|
||||
page: action.courseId,
|
||||
page: payload.courseId,
|
||||
})),
|
||||
[GOT_GRADES]: trackEvent(action => ({
|
||||
[actions.grades.received.toString()]: trackEvent(({ payload }) => ({
|
||||
name: 'edx.gradebook.grades.displayed',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
track: action.track,
|
||||
cohort: action.cohort,
|
||||
assignmentType: action.assignmentType,
|
||||
prev: action.prev,
|
||||
next: action.next,
|
||||
label: payload.courseId,
|
||||
track: payload.track,
|
||||
cohort: payload.cohort,
|
||||
assignmentType: payload.assignmentType,
|
||||
prev: payload.prev,
|
||||
next: payload.next,
|
||||
},
|
||||
})),
|
||||
[GRADE_UPDATE_SUCCESS]: trackEvent(action => ({
|
||||
[actions.grades.update.success.toString()]: trackEvent(({ payload }) => ({
|
||||
name: 'edx.gradebook.grades.grade_override.succeeded',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
updatedGrades: action.payload.responseData,
|
||||
label: payload.courseId,
|
||||
updatedGrades: payload.responseData,
|
||||
},
|
||||
})),
|
||||
[GRADE_UPDATE_FAILURE]: trackEvent(action => ({
|
||||
[actions.grades.update.failure.toString()]: trackEvent(({ payload }) => ({
|
||||
name: 'edx.gradebook.grades.grade_override.failed',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
error: action.payload.error,
|
||||
label: payload.courseId,
|
||||
error: payload.error,
|
||||
},
|
||||
})),
|
||||
[UPLOAD_OVERRIDE]: trackEvent(action => ({
|
||||
[actions.grades.uploadOverride.success.toString()]: trackEvent(({ payload }) => ({
|
||||
name: 'edx.gradebook.grades.upload.grades_overrides.succeeded',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
label: payload.courseId,
|
||||
},
|
||||
})),
|
||||
[UPLOAD_OVERRIDE_ERROR]: trackEvent(action => ({
|
||||
[actions.grades.uploadOverride.failure.toString()]: trackEvent(({ payload }) => ({
|
||||
name: 'edx.gradebook.grades.upload.grades_overrides.failed',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
error: action.payload.error,
|
||||
label: payload.courseId,
|
||||
error: payload.error,
|
||||
},
|
||||
})),
|
||||
[UPDATE_COURSE_GRADE_LIMITS]: trackEvent(action => ({
|
||||
[actions.filters.update.courseGradeLimits]: trackEvent(({ payload }) => ({
|
||||
name: 'edx.gradebook.grades.filter_applied',
|
||||
label: action.courseId,
|
||||
label: payload.courseId,
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
},
|
||||
})),
|
||||
[BULK_GRADE_REPORT_DOWNLOADED]: trackEvent(action => ({
|
||||
name: 'edx.gradebook.reports.grade_export.downloaded',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
},
|
||||
})),
|
||||
[INTERVENTION_REPORT_DOWNLOADED]: trackEvent(action => ({
|
||||
name: 'edx.gradebook.reports.intervention.downloaded',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: action.courseId,
|
||||
label: payload.courseId,
|
||||
},
|
||||
})),
|
||||
[actions.grades.downloadReport.bulkGrade.toString()]: trackEvent(
|
||||
({ payload }) => ({
|
||||
name: 'edx.gradebook.reports.grade_export.downloaded',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: payload.courseId,
|
||||
},
|
||||
}),
|
||||
),
|
||||
[actions.grades.downloadReport.invervention.toString()]: trackEvent(
|
||||
({ payload }) => ({
|
||||
name: 'edx.gradebook.reports.intervention.downloaded',
|
||||
properties: {
|
||||
category: trackingCategory,
|
||||
label: payload.courseId,
|
||||
},
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
const segmentMiddleware = createMiddleware(eventsMap, Segment());
|
||||
|
||||
24
src/data/thunkActions/assignmentTypes.js
Normal file
24
src/data/thunkActions/assignmentTypes.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import * as assignmentTypes from '../actions/assignmentTypes';
|
||||
import * as config from '../actions/config';
|
||||
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
|
||||
const fetchAssignmentTypes = courseId => (
|
||||
(dispatch) => {
|
||||
dispatch(assignmentTypes.startedFetching());
|
||||
return LmsApiService.fetchAssignmentTypes(courseId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(assignmentTypes.received(Object.keys(data.assignment_types)));
|
||||
dispatch(assignmentTypes.gotGradesFrozen(data.grades_frozen));
|
||||
dispatch(config.gotBulkManagementConfig(data.can_see_bulk_management));
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(assignmentTypes.errorFetching());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export { fetchAssignmentTypes };
|
||||
21
src/data/thunkActions/cohorts.js
Normal file
21
src/data/thunkActions/cohorts.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import * as cohorts from '../actions/cohorts';
|
||||
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
|
||||
const fetchCohorts = courseId => (
|
||||
(dispatch) => {
|
||||
dispatch(cohorts.startedFetching());
|
||||
return LmsApiService.fetchCohorts(courseId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(cohorts.received(data.cohorts));
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(cohorts.errorFetching());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export { fetchCohorts };
|
||||
19
src/data/thunkActions/filters.js
Normal file
19
src/data/thunkActions/filters.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import * as filters from '../actions/filters';
|
||||
|
||||
import { getFilters } from '../selectors/filters';
|
||||
|
||||
import { fetchGrades } from './grades';
|
||||
|
||||
const updateIncludeCourseRoleMembers = (includeCourseRoleMembers) => (dispatch, getState) => {
|
||||
dispatch(filters.update.includeCourseRoleMembers(includeCourseRoleMembers));
|
||||
const state = getState();
|
||||
const { cohort, track, assignmentType } = getFilters(state);
|
||||
dispatch(fetchGrades(state.grades.courseId, cohort, track, assignmentType));
|
||||
};
|
||||
|
||||
export {
|
||||
updateIncludeCourseRoleMembers,
|
||||
|
||||
};
|
||||
221
src/data/thunkActions/grades.js
Normal file
221
src/data/thunkActions/grades.js
Normal file
@@ -0,0 +1,221 @@
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import * as grades from '../actions/grades';
|
||||
import { sortAlphaAsc } from '../actions/utils';
|
||||
|
||||
import { getFilters } from '../selectors/filters';
|
||||
import {
|
||||
formatMaxAssignmentGrade,
|
||||
formatMinAssignmentGrade,
|
||||
formatMaxCourseGrade,
|
||||
formatMinCourseGrade,
|
||||
formatGradeOverrideForDisplay,
|
||||
} from '../selectors/grades';
|
||||
|
||||
import GRADE_OVERRIDE_HISTORY_ERROR_DEFAULT_MSG from '../constants/errors';
|
||||
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
|
||||
const defaultAssignmentFilter = 'All';
|
||||
|
||||
const fetchBulkUpgradeHistory = courseId => (
|
||||
// todo add loading effect
|
||||
dispatch => LmsApiService.fetchGradeBulkOperationHistory(courseId).then(
|
||||
(response) => { dispatch(grades.bulkHistory.received(response)); },
|
||||
).catch(() => dispatch(grades.bulkHistory.error()))
|
||||
);
|
||||
|
||||
const fetchGrades = (
|
||||
courseId,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
options = {},
|
||||
) => (
|
||||
(dispatch, getState) => {
|
||||
dispatch(grades.fetching.started());
|
||||
const {
|
||||
assignment,
|
||||
assignmentGradeMax: assignmentMax,
|
||||
assignmentGradeMin: assignmentMin,
|
||||
courseGradeMin,
|
||||
courseGradeMax,
|
||||
includeCourseRoleMembers,
|
||||
} = getFilters(getState());
|
||||
const { id: assignmentId } = assignment || {};
|
||||
const assignmentGradeMax = formatMaxAssignmentGrade(assignmentMax, { assignmentId });
|
||||
const assignmentGradeMin = formatMinAssignmentGrade(assignmentMin, { assignmentId });
|
||||
const courseGradeMinFormatted = formatMinCourseGrade(courseGradeMin);
|
||||
const courseGradeMaxFormatted = formatMaxCourseGrade(courseGradeMax);
|
||||
return LmsApiService.fetchGradebookData(
|
||||
courseId,
|
||||
options.searchText || null,
|
||||
cohort,
|
||||
track,
|
||||
{
|
||||
assignment: assignmentId,
|
||||
assignmentGradeMax,
|
||||
assignmentGradeMin,
|
||||
courseGradeMin: courseGradeMinFormatted,
|
||||
courseGradeMax: courseGradeMaxFormatted,
|
||||
includeCourseRoleMembers,
|
||||
},
|
||||
)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(grades.received({
|
||||
grades: data.results.sort(sortAlphaAsc),
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
prev: data.previous,
|
||||
next: data.next,
|
||||
courseId,
|
||||
totalUsersCount: data.total_users_count,
|
||||
filteredUsersCount: data.filtered_users_count,
|
||||
}));
|
||||
dispatch(grades.fetching.finished());
|
||||
if (options.showSuccess) {
|
||||
dispatch(grades.banner.open());
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(grades.fetching.error());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const fetchGradeOverrideHistory = (subsectionId, userId) => (
|
||||
dispatch => LmsApiService.fetchGradeOverrideHistory(subsectionId, userId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
if (data.success) {
|
||||
dispatch(grades.overrideHistory.received({
|
||||
overrideHistory: formatGradeOverrideForDisplay(data.history),
|
||||
currentEarnedAllOverride: data.override ? data.override.earned_all_override : null,
|
||||
currentPossibleAllOverride: data.override ? data.override.possible_all_override : null,
|
||||
currentEarnedGradedOverride: data.override ? data.override.earned_graded_override : null,
|
||||
currentPossibleGradedOverride: data.override
|
||||
? data.override.possible_graded_override : null,
|
||||
originalGradeEarnedAll: data.original_grade ? data.original_grade.earned_all : null,
|
||||
originalGradePossibleAll: data.original_grade ? data.original_grade.possible_all : null,
|
||||
originalGradeEarnedGraded: data.original_grade
|
||||
? data.original_grade.earned_graded : null,
|
||||
originalGradePossibleGraded: data.original_grade
|
||||
? data.original_grade.possible_graded : null,
|
||||
}));
|
||||
} else {
|
||||
dispatch(grades.overrideHistory.errorFetching(data.error_message));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(grades.overrideHistory.errorFetching(GRADE_OVERRIDE_HISTORY_ERROR_DEFAULT_MSG));
|
||||
})
|
||||
);
|
||||
|
||||
const fetchMatchingUserGrades = (
|
||||
courseId,
|
||||
searchText,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
showSuccess,
|
||||
options = {},
|
||||
) => {
|
||||
const newOptions = { ...options, searchText, showSuccess };
|
||||
return fetchGrades(courseId, cohort, track, assignmentType, newOptions);
|
||||
};
|
||||
|
||||
const fetchPrevNextGrades = (endpoint, courseId, cohort, track, assignmentType) => (
|
||||
(dispatch) => {
|
||||
dispatch(grades.fetching.started());
|
||||
return getAuthenticatedHttpClient().get(endpoint)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(grades.fetching.results({
|
||||
grades: data.results.sort(sortAlphaAsc),
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
prev: data.previous,
|
||||
next: data.next,
|
||||
courseId,
|
||||
totalUsersCount: data.total_users_count,
|
||||
filteredUsersCount: data.filtered_users_count,
|
||||
}));
|
||||
dispatch(grades.fetching.finished());
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(grades.fetching.error());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const submitFileUploadFormData = (courseId, formData) => (
|
||||
(dispatch) => {
|
||||
dispatch(grades.csvUpload.started());
|
||||
return LmsApiService.uploadGradeCsv(courseId, formData).then(() => {
|
||||
dispatch(grades.csvUpload.finished());
|
||||
dispatch(grades.uploadOverride.success(courseId));
|
||||
}).catch((err) => {
|
||||
dispatch(grades.uploadOverride.failure(courseId, err));
|
||||
if (err.status === 200 && err.data.error_messages.length) {
|
||||
const { error_messages: errorMessages, saved, total } = err.data;
|
||||
return dispatch(grades.csvUpload.error({ errorMessages, saved, total }));
|
||||
}
|
||||
return dispatch(grades.csvUpload.error({ errorMessages: ['Unknown error.'] }));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const updateGrades = (courseId, updateData, searchText, cohort, track) => (
|
||||
(dispatch) => {
|
||||
dispatch(grades.update.request());
|
||||
return LmsApiService.updateGradebookData(courseId, updateData)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(grades.update.success({ courseId, data }));
|
||||
dispatch(fetchMatchingUserGrades(
|
||||
courseId,
|
||||
searchText,
|
||||
cohort,
|
||||
track,
|
||||
defaultAssignmentFilter,
|
||||
true,
|
||||
{ searchText },
|
||||
));
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch(grades.update.failure({ courseId, error }));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const updateGradesIfAssignmentGradeFiltersSet = (
|
||||
courseId,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
) => (dispatch, getState) => {
|
||||
const { filters: { assignmentGradeMin, assignmentGradeMax } } = getState();
|
||||
const hasAssignmentGradeFiltersSet = assignmentGradeMax || assignmentGradeMin;
|
||||
if (hasAssignmentGradeFiltersSet) {
|
||||
dispatch(fetchGrades(
|
||||
courseId,
|
||||
cohort,
|
||||
track,
|
||||
assignmentType,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
fetchBulkUpgradeHistory,
|
||||
fetchGrades,
|
||||
fetchGradeOverrideHistory,
|
||||
fetchMatchingUserGrades,
|
||||
fetchPrevNextGrades,
|
||||
submitFileUploadFormData,
|
||||
updateGrades,
|
||||
updateGradesIfAssignmentGradeFiltersSet,
|
||||
};
|
||||
41
src/data/thunkActions/roles.js
Normal file
41
src/data/thunkActions/roles.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import * as roles from '../actions/roles';
|
||||
|
||||
import { getFilters } from '../selectors/filters';
|
||||
|
||||
import { fetchCohorts } from './cohorts';
|
||||
import {
|
||||
fetchGrades,
|
||||
} from './grades';
|
||||
import { fetchTracks } from './tracks';
|
||||
import { fetchAssignmentTypes } from './assignmentTypes';
|
||||
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
|
||||
const allowedRoles = ['staff', 'instructor', 'support'];
|
||||
|
||||
const getRoles = courseId => (
|
||||
(dispatch, getState) => LmsApiService.fetchUserRoles(courseId)
|
||||
.then(response => response.data)
|
||||
.then((response) => {
|
||||
const isAllowedRole = (role) => (
|
||||
(role.course_id === courseId) && allowedRoles.includes(role.role)
|
||||
);
|
||||
|
||||
const canUserViewGradebook = (response.is_staff || (response.roles.some(isAllowedRole)));
|
||||
dispatch(roles.received({ canUserViewGradebook, courseId }));
|
||||
const { cohort, track, assignmentType } = getFilters(getState());
|
||||
if (canUserViewGradebook) {
|
||||
dispatch(fetchGrades(courseId, cohort, track, assignmentType));
|
||||
dispatch(fetchTracks(courseId));
|
||||
dispatch(fetchCohorts(courseId));
|
||||
dispatch(fetchAssignmentTypes(courseId));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(roles.errorFetching());
|
||||
}));
|
||||
|
||||
export {
|
||||
getRoles,
|
||||
};
|
||||
31
src/data/thunkActions/tracks.js
Normal file
31
src/data/thunkActions/tracks.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import * as tracks from '../actions/tracks';
|
||||
|
||||
import { hasMastersTrack } from '../selectors/tracks';
|
||||
|
||||
import {
|
||||
fetchBulkUpgradeHistory,
|
||||
} from './grades';
|
||||
|
||||
import LmsApiService from '../services/LmsApiService';
|
||||
|
||||
const fetchTracks = courseId => (
|
||||
(dispatch) => {
|
||||
dispatch(tracks.fetching.started());
|
||||
return LmsApiService.fetchTracks(courseId)
|
||||
.then(response => response.data)
|
||||
.then((data) => {
|
||||
dispatch(tracks.fetching.received(data.course_modes));
|
||||
if (hasMastersTrack(data.course_modes)) {
|
||||
dispatch(fetchBulkUpgradeHistory(courseId));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch(tracks.fetching.error());
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export {
|
||||
fetchTracks,
|
||||
};
|
||||
Reference in New Issue
Block a user