From 1b97295445221ebfd14e577be3a57d601af90640 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Thu, 17 Jun 2021 01:26:43 +0300 Subject: [PATCH 1/5] Renamed workingDays property. --- src/constants/workPeriods.js | 1 + .../components/PeriodItem/index.jsx | 20 ++++++++-------- .../components/PeriodItem/styles.module.scss | 6 ++--- .../components/PeriodsHistoryItem/index.jsx | 24 +++++++++---------- .../PeriodsHistoryItem/styles.module.scss | 4 ++-- src/store/actions/workPeriods.js | 15 ++++++------ src/store/reducers/workPeriods.js | 12 +++++----- src/store/thunks/workPeriods.js | 6 ++--- src/utils/workPeriods.js | 5 ++-- 9 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/constants/workPeriods.js b/src/constants/workPeriods.js index 3caa7e6..34b3924 100644 --- a/src/constants/workPeriods.js +++ b/src/constants/workPeriods.js @@ -35,6 +35,7 @@ export const REQUIRED_FIELDS = [ "workPeriods.endDate", "workPeriods.paymentStatus", "workPeriods.daysWorked", + "workPeriods.daysPaid", ]; // Valid parameter names for requests. diff --git a/src/routes/WorkPeriods/components/PeriodItem/index.jsx b/src/routes/WorkPeriods/components/PeriodItem/index.jsx index ae5cf84..b5b9e53 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodItem/index.jsx @@ -53,16 +53,16 @@ const PeriodItem = ({ }, [dispatch, item]); const onWorkingDaysChange = useCallback( - (workingDays) => { - dispatch(setWorkPeriodWorkingDays({ periodId: item.id, workingDays })); + (daysWorked) => { + dispatch(setWorkPeriodWorkingDays(item.id, daysWorked)); }, [dispatch, item.id] ); const updateWorkingDays = useCallback( debounce( - (workingDays) => { - dispatch(updateWorkPeriodWorkingDays(item.id, workingDays)); + (daysWorked) => { + dispatch(updateWorkPeriodWorkingDays(item.id, daysWorked)); }, 300, { leading: false } @@ -72,8 +72,8 @@ const PeriodItem = ({ // Update working days on server if working days change. useUpdateEffect(() => { - updateWorkingDays(item.workingDays); - }, [item.workingDays]); + updateWorkingDays(item.daysWorked); + }, [item.daysWorked]); return ( <> @@ -118,15 +118,15 @@ const PeriodItem = ({ - + @@ -156,7 +156,7 @@ PeriodItem.propTypes = { endDate: PT.string.isRequired, weeklyRate: PT.number, paymentStatus: PT.string.isRequired, - workingDays: PT.number.isRequired, + daysWorked: PT.number.isRequired, }), details: PT.shape({ periodId: PT.string.isRequired, diff --git a/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss b/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss index bd8766b..7cb0181 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss @@ -25,7 +25,7 @@ padding-left: 14px; } - &.workingDays { + &.daysWorked { border-right: 1px solid #d6d6d6; padding-top: 4px; padding-right: 9px; @@ -77,10 +77,10 @@ td.weeklyRate { } } -td.workingDays { +td.daysWorked { padding: 5px 10px; } -.workingDaysControl { +.daysWorkedControl { width: 100px; } diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx b/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx index 5bbfabc..1dda757 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx @@ -32,19 +32,19 @@ const PeriodsHistoryItem = ({ const dispatch = useDispatch(); const dateLabel = formatDateLabel(item.startDate, currentStartDate); - const workingDays = item.workingDays; + const daysWorked = item.daysWorked; const onWorkingDaysChange = useCallback( - (workingDays) => { - dispatch(setDetailsWorkingDays(periodId, item.id, workingDays)); + (daysWorked) => { + dispatch(setDetailsWorkingDays(periodId, item.id, daysWorked)); }, [dispatch, periodId, item.id] ); const updateWorkingDays = useCallback( debounce( - (workingDays) => { - dispatch(updateWorkPeriodWorkingDays(item.id, workingDays)); + (daysWorked) => { + dispatch(updateWorkPeriodWorkingDays(item.id, daysWorked)); }, 300, { leading: false } @@ -54,8 +54,8 @@ const PeriodsHistoryItem = ({ // Update working days on server if working days change. useUpdateEffect(() => { - updateWorkingDays(item.workingDays); - }, [item.workingDays]); + updateWorkingDays(item.daysWorked); + }, [item.daysWorked]); return ( - + {item.paymentStatus === PAYMENT_STATUS.PAID ? ( - `${workingDays} ${workingDays === 1 ? "Day" : "Days"}` + `${daysWorked} ${daysWorked === 1 ? "Day" : "Days"}` ) : ( @@ -106,7 +106,7 @@ PeriodsHistoryItem.propTypes = { paymentStatus: PT.string.isRequired, payments: PT.array, weeklyRate: PT.number, - workingDays: PT.number.isRequired, + daysWorked: PT.number.isRequired, }).isRequired, currentStartDate: PT.oneOfType([PT.string, PT.number, PT.object]).isRequired, }; diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss b/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss index 27d50dc..fb3d65c 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss @@ -36,11 +36,11 @@ position: relative; } -.workingDays { +.daysWorked { padding: 4px 10px; } -.workingDaysControl { +.daysWorkedControl { display: block; width: 100px; } diff --git a/src/store/actions/workPeriods.js b/src/store/actions/workPeriods.js index d93bff5..a386133 100644 --- a/src/store/actions/workPeriods.js +++ b/src/store/actions/workPeriods.js @@ -161,16 +161,16 @@ export const setBillingAccount = (periodId, accountId) => ({ * * @param {string} parentPeriodId parent working period id * @param {string} periodId working period id - * @param {number} workingDays number of working days + * @param {number} daysWorked number of working days * @returns {Object} */ export const setDetailsWorkingDays = ( parentPeriodId, periodId, - workingDays + daysWorked ) => ({ type: ACTION_TYPE.WP_SET_DETAILS_WORKING_DAYS, - payload: { parentPeriodId, periodId, workingDays }, + payload: { parentPeriodId, periodId, daysWorked }, }); /** @@ -314,14 +314,13 @@ export const setWorkPeriodsUserHandle = (handle) => ({ /** * Creates an action to change working days for specific working period. * - * @param {Object} payload object containing period id and days number - * @param {string|number} payload.periodId period id - * @param {number} payload.workingDays number of working days + * @param {string|number} periodId period id + * @param {number} daysWorked number of working days * @returns {Object} */ -export const setWorkPeriodWorkingDays = (payload) => ({ +export const setWorkPeriodWorkingDays = (periodId, daysWorked) => ({ type: ACTION_TYPE.WP_SET_WORKING_DAYS, - payload, + payload: { periodId, daysWorked }, }); /** diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js index 110d2d8..bd5e670 100644 --- a/src/store/reducers/workPeriods.js +++ b/src/store/reducers/workPeriods.js @@ -376,25 +376,25 @@ const actionHandlers = { }, [ACTION_TYPE.WP_SET_DETAILS_WORKING_DAYS]: ( state, - { parentPeriodId, periodId, workingDays } + { parentPeriodId, periodId, daysWorked } ) => { const periodsDetails = { ...state.periodsDetails }; let periodDetails = periodsDetails[parentPeriodId]; if (!periodDetails) { return state; } - workingDays = Math.min(Math.max(workingDays, 0), 5); + daysWorked = Math.min(Math.max(daysWorked, 0), 5); const periods = []; for (let period of periodDetails.periods) { if (period.id === periodId) { - period = { ...period, workingDays }; + period = { ...period, daysWorked }; } periods.push(period); } const periodsVisible = []; for (let period of periodDetails.periodsVisible) { if (period.id === periodId) { - period = { ...period, workingDays }; + period = { ...period, daysWorked }; } periodsVisible.push(period); } @@ -516,7 +516,7 @@ const actionHandlers = { }, }; }, - [ACTION_TYPE.WP_SET_WORKING_DAYS]: (state, { periodId, workingDays }) => { + [ACTION_TYPE.WP_SET_WORKING_DAYS]: (state, { periodId, daysWorked }) => { const oldPeriods = state.periods; const periods = []; for (let i = 0, len = oldPeriods.length; i < len; i++) { @@ -524,7 +524,7 @@ const actionHandlers = { if (period.id === periodId) { period = { ...period, - workingDays: Math.min(Math.max(workingDays, 0), 5), + daysWorked: Math.min(Math.max(daysWorked, 0), 5), }; } periods.push(period); diff --git a/src/store/thunks/workPeriods.js b/src/store/thunks/workPeriods.js index e04818a..7cff821 100644 --- a/src/store/thunks/workPeriods.js +++ b/src/store/thunks/workPeriods.js @@ -219,13 +219,13 @@ export const updateWorkPeriodBillingAccount = /** * * @param {string} periodId - * @param {number} workingDays + * @param {number} daysWorked * @returns {function} */ export const updateWorkPeriodWorkingDays = - (periodId, workingDays) => async () => { + (periodId, daysWorked) => async () => { try { - await services.patchWorkPeriodWorkingDays(periodId, workingDays); + await services.patchWorkPeriodWorkingDays(periodId, daysWorked); } catch (error) { makeToast( `Failed to update working days for working period ${periodId}.\n` + diff --git a/src/utils/workPeriods.js b/src/utils/workPeriods.js index 8ed10a2..3a8351e 100644 --- a/src/utils/workPeriods.js +++ b/src/utils/workPeriods.js @@ -26,7 +26,8 @@ export function normalizePeriodItems(items) { endDate: item.endDate ? moment(item.endDate).format(DATE_FORMAT_UI) : "", weeklyRate: item.memberRate, paymentStatus: normalizePaymentStatus(workPeriod.paymentStatus), - workingDays: daysWorked === null ? 5 : +daysWorked || 0, + daysWorked: daysWorked === null ? 5 : +daysWorked || 0, + daysPaid: +workPeriod.daysPaid || 0, }); } return periods; @@ -75,7 +76,7 @@ export function normalizeDetailsPeriodItems(items) { paymentStatus: normalizePaymentStatus(item.paymentStatus), payments: item.payments || [], weeklyRate: item.memberRate, - workingDays: daysWorked === null ? 5 : +daysWorked || 0, + daysWorked: daysWorked === null ? 5 : +daysWorked || 0, }); } periods.sort(sortByStartDate); From d4906a0667e3d4b1cf73ff378ed855cf1ba2bba1 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Thu, 17 Jun 2021 05:23:02 +0300 Subject: [PATCH 2/5] Fixed: dropdowns inside periods' details overlaid week picker calendar. --- src/routes/WorkPeriods/components/PeriodWeekPicker/index.jsx | 4 +++- .../components/PeriodWeekPicker/styles.module.scss | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/WorkPeriods/components/PeriodWeekPicker/index.jsx b/src/routes/WorkPeriods/components/PeriodWeekPicker/index.jsx index 09dbec4..212bea8 100644 --- a/src/routes/WorkPeriods/components/PeriodWeekPicker/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodWeekPicker/index.jsx @@ -1,10 +1,12 @@ import React, { useCallback } from "react"; import { useSelector, useDispatch } from "react-redux"; import PT from "prop-types"; +import cn from "classnames"; import moment from "moment"; import WeekPicker from "components/WeekPicker"; import { getWorkPeriodsDateRange } from "store/selectors/workPeriods"; import { setWorkPeriodsDateRange } from "store/actions/workPeriods"; +import styles from "./styles.module.scss"; /** * Displays working periods' week picker. @@ -34,7 +36,7 @@ const PeriodWeekPicker = ({ className }) => { return ( Date: Thu, 17 Jun 2021 05:35:46 +0300 Subject: [PATCH 3/5] Refactored handling of working days. --- .../components/PeriodDetails/index.jsx | 1 - .../components/PeriodItem/index.jsx | 15 ++-- .../components/PeriodList/index.jsx | 3 + .../components/PeriodsHistory/index.jsx | 11 ++- .../components/PeriodsHistoryItem/index.jsx | 27 +++--- src/store/actions/workPeriods.js | 9 +- src/store/reducers/workPeriods.js | 83 ++++++++++--------- src/store/selectors/workPeriods.js | 2 + src/utils/workPeriods.js | 1 + 9 files changed, 84 insertions(+), 68 deletions(-) diff --git a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx index a5a86b8..18bc861 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx @@ -146,7 +146,6 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { diff --git a/src/routes/WorkPeriods/components/PeriodItem/index.jsx b/src/routes/WorkPeriods/components/PeriodItem/index.jsx index b5b9e53..0d615c8 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodItem/index.jsx @@ -29,6 +29,7 @@ import styles from "./styles.module.scss"; * @param {boolean} [props.isFailed] whether the item should be highlighted as failed * @param {boolean} props.isSelected whether the item is selected * @param {Object} props.item object describing a working period + * @param {Object} props.data changeable working period data such as working days * @param {Object} [props.details] object with working period details * @returns {JSX.Element} */ @@ -37,6 +38,7 @@ const PeriodItem = ({ isFailed = false, isSelected, item, + data, details, }) => { const dispatch = useDispatch(); @@ -72,8 +74,8 @@ const PeriodItem = ({ // Update working days on server if working days change. useUpdateEffect(() => { - updateWorkingDays(item.daysWorked); - }, [item.daysWorked]); + updateWorkingDays(data.daysWorked); + }, [data.daysWorked]); return ( <> @@ -125,8 +127,8 @@ const PeriodItem = ({ name={`wp_wrk_days_${item.id}`} onChange={onWorkingDaysChange} maxValue={5} - minValue={0} - value={item.daysWorked} + minValue={data.daysPaid} + value={data.daysWorked} /> @@ -156,8 +158,11 @@ PeriodItem.propTypes = { endDate: PT.string.isRequired, weeklyRate: PT.number, paymentStatus: PT.string.isRequired, + }).isRequired, + data: PT.shape({ daysWorked: PT.number.isRequired, - }), + daysPaid: PT.number.isRequired, + }).isRequired, details: PT.shape({ periodId: PT.string.isRequired, rbId: PT.string.isRequired, diff --git a/src/routes/WorkPeriods/components/PeriodList/index.jsx b/src/routes/WorkPeriods/components/PeriodList/index.jsx index 06ed6b5..5ffedf0 100644 --- a/src/routes/WorkPeriods/components/PeriodList/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodList/index.jsx @@ -7,6 +7,7 @@ import PeriodItem from "../PeriodItem"; import PeriodListHead from "../PeriodListHead"; import { getWorkPeriods, + getWorkPeriodsData, getWorkPeriodsDetails, getWorkPeriodsFailed, getWorkPeriodsIsProcessingPayments, @@ -23,6 +24,7 @@ import styles from "./styles.module.scss"; */ const PeriodList = ({ className }) => { const periods = useSelector(getWorkPeriods); + const [periodsData] = useSelector(getWorkPeriodsData); const periodsDetails = useSelector(getWorkPeriodsDetails); const periodsFailed = useSelector(getWorkPeriodsFailed); const periodsSelected = useSelector(getWorkPeriodsSelected); @@ -46,6 +48,7 @@ const PeriodList = ({ className }) => { isFailed={period.id in periodsFailed} isSelected={period.id in periodsSelected} item={period} + data={periodsData[period.id]} details={periodsDetails[period.id]} /> ))} diff --git a/src/routes/WorkPeriods/components/PeriodsHistory/index.jsx b/src/routes/WorkPeriods/components/PeriodsHistory/index.jsx index 73b8e0c..c1cf309 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistory/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodsHistory/index.jsx @@ -3,7 +3,10 @@ import { useSelector } from "react-redux"; import PT from "prop-types"; import cn from "classnames"; import PeriodHistoryItem from "../PeriodsHistoryItem"; -import { getWorkPeriodsDateRange } from "store/selectors/workPeriods"; +import { + getWorkPeriodsData, + getWorkPeriodsDateRange, +} from "store/selectors/workPeriods"; import styles from "./styles.module.scss"; /** @@ -12,7 +15,8 @@ import styles from "./styles.module.scss"; * @param {Object} props component properties * @returns {JSX.Element} */ -const PeriodsHistory = ({ className, isDisabled, periodId, periods }) => { +const PeriodsHistory = ({ className, isDisabled, periods }) => { + const [periodsData] = useSelector(getWorkPeriodsData); const [startDate] = useSelector(getWorkPeriodsDateRange); return (
@@ -21,9 +25,9 @@ const PeriodsHistory = ({ className, isDisabled, periodId, periods }) => { {periods.map((period) => ( ))} @@ -36,7 +40,6 @@ const PeriodsHistory = ({ className, isDisabled, periodId, periods }) => { PeriodsHistory.propTypes = { className: PT.string, isDisabled: PT.bool.isRequired, - periodId: PT.string.isRequired, periods: PT.arrayOf(PT.object), }; diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx b/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx index 1dda757..e652046 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx @@ -16,6 +16,7 @@ import { } from "utils/formatters"; import styles from "./styles.module.scss"; import PeriodsHistoryWeeklyRate from "../PeriodsHistoryWeeklyRate"; +import moment from "moment"; /** * Displays working period row in history table in details view. @@ -23,22 +24,18 @@ import PeriodsHistoryWeeklyRate from "../PeriodsHistoryWeeklyRate"; * @param {Object} props component properties * @returns {JSX.Element} */ -const PeriodsHistoryItem = ({ - periodId, - isDisabled, - item, - currentStartDate, -}) => { +const PeriodsHistoryItem = ({ isDisabled, item, data, currentStartDate }) => { const dispatch = useDispatch(); const dateLabel = formatDateLabel(item.startDate, currentStartDate); - const daysWorked = item.daysWorked; + const daysWorked = data.daysWorked; + const isCurrent = moment(item.startDate).isSame(currentStartDate, "date"); const onWorkingDaysChange = useCallback( (daysWorked) => { - dispatch(setDetailsWorkingDays(periodId, item.id, daysWorked)); + dispatch(setDetailsWorkingDays(item.id, daysWorked)); }, - [dispatch, periodId, item.id] + [dispatch, item.id] ); const updateWorkingDays = useCallback( @@ -54,8 +51,10 @@ const PeriodsHistoryItem = ({ // Update working days on server if working days change. useUpdateEffect(() => { - updateWorkingDays(item.daysWorked); - }, [item.daysWorked]); + if (!isCurrent) { + updateWorkingDays(data.daysWorked); + } + }, [data.daysWorked, isCurrent]); return ( )} @@ -97,7 +96,6 @@ const PeriodsHistoryItem = ({ }; PeriodsHistoryItem.propTypes = { - periodId: PT.string.isRequired, isDisabled: PT.bool.isRequired, item: PT.shape({ id: PT.string.isRequired, @@ -106,7 +104,10 @@ PeriodsHistoryItem.propTypes = { paymentStatus: PT.string.isRequired, payments: PT.array, weeklyRate: PT.number, + }).isRequired, + data: PT.shape({ daysWorked: PT.number.isRequired, + daysPaid: PT.number.isRequired, }).isRequired, currentStartDate: PT.oneOfType([PT.string, PT.number, PT.object]).isRequired, }; diff --git a/src/store/actions/workPeriods.js b/src/store/actions/workPeriods.js index a386133..198e380 100644 --- a/src/store/actions/workPeriods.js +++ b/src/store/actions/workPeriods.js @@ -159,18 +159,13 @@ export const setBillingAccount = (periodId, accountId) => ({ * Creates an action denoting the change of working period's working days in * details view. * - * @param {string} parentPeriodId parent working period id * @param {string} periodId working period id * @param {number} daysWorked number of working days * @returns {Object} */ -export const setDetailsWorkingDays = ( - parentPeriodId, - periodId, - daysWorked -) => ({ +export const setDetailsWorkingDays = (periodId, daysWorked) => ({ type: ACTION_TYPE.WP_SET_DETAILS_WORKING_DAYS, - payload: { parentPeriodId, periodId, daysWorked }, + payload: { periodId, daysWorked }, }); /** diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js index bd5e670..4a0fbcb 100644 --- a/src/store/reducers/workPeriods.js +++ b/src/store/reducers/workPeriods.js @@ -17,6 +17,8 @@ import { } from "utils/misc"; import { createAssignedBillingAccountOption } from "utils/workPeriods"; +const cancelSourceDummy = { cancel: () => {} }; + const initPagination = () => ({ totalCount: 0, pageCount: 0, @@ -34,7 +36,11 @@ const initFilters = () => ({ userHandle: "", }); -const cancelSourceDummy = { cancel: () => {} }; +const initPeriodData = (daysWorked, daysPaid) => ({ + cancelSource: null, + daysWorked, + daysPaid, +}); const initPeriodDetails = ( periodId, @@ -65,6 +71,7 @@ const initialState = { error: null, cancelSource: cancelSourceDummy, periods: [], + periodsData: [{}], periodsDetails: {}, periodsFailed: {}, periodsSelected: {}, @@ -95,6 +102,7 @@ const actionHandlers = { cancelSource, error: null, periods: [], + periodsData: [{}], periodsDetails: {}, periodsFailed: {}, periodsSelected: {}, @@ -115,11 +123,22 @@ const actionHandlers = { oldPagination.pageCount !== pageCount ? { ...oldPagination, totalCount, pageCount } : oldPagination; + const periodsData = {}; + for (let period of periods) { + periodsData[period.id] = initPeriodData( + period.daysWorked, + period.daysPaid + ); + // These two lines can be removed but they're kept for now for debugging. + delete period.daysWorked; + delete period.daysPaid; + } return { ...state, cancelSource: null, error: null, periods, + periodsData: [periodsData], pagination, }; }, @@ -194,6 +213,16 @@ const actionHandlers = { // This branch should not be reachable but just in case. return state; } + const periodsData = state.periodsData[0]; + for (let period of details.periods) { + periodsData[period.id] = initPeriodData( + period.daysWorked, + period.daysPaid + ); + // These two lines can be removed but they're kept for now for debugging. + delete period.daysWorked; + delete period.daysPaid; + } periodDetails = { ...periodDetails, periods: details.periods, @@ -210,6 +239,7 @@ const actionHandlers = { periodsDetails[periodId] = periodDetails; return { ...state, + periodsData: [periodsData], periodsDetails, }; }, @@ -376,36 +406,18 @@ const actionHandlers = { }, [ACTION_TYPE.WP_SET_DETAILS_WORKING_DAYS]: ( state, - { parentPeriodId, periodId, daysWorked } + { periodId, daysWorked } ) => { - const periodsDetails = { ...state.periodsDetails }; - let periodDetails = periodsDetails[parentPeriodId]; - if (!periodDetails) { + const periodsData = state.periodsData[0]; + let periodData = periodsData[periodId]; + daysWorked = Math.min(Math.max(daysWorked, periodData.daysPaid), 5); + if (daysWorked === periodData.daysWorked) { return state; } - daysWorked = Math.min(Math.max(daysWorked, 0), 5); - const periods = []; - for (let period of periodDetails.periods) { - if (period.id === periodId) { - period = { ...period, daysWorked }; - } - periods.push(period); - } - const periodsVisible = []; - for (let period of periodDetails.periodsVisible) { - if (period.id === periodId) { - period = { ...period, daysWorked }; - } - periodsVisible.push(period); - } - periodsDetails[parentPeriodId] = { - ...periodDetails, - periods, - periodsVisible, - }; + periodsData[periodId] = { ...periodData, daysWorked }; return { ...state, - periodsDetails, + periodsData: [periodsData], }; }, [ACTION_TYPE.WP_RESET_FILTERS]: (state) => ({ @@ -517,21 +529,16 @@ const actionHandlers = { }; }, [ACTION_TYPE.WP_SET_WORKING_DAYS]: (state, { periodId, daysWorked }) => { - const oldPeriods = state.periods; - const periods = []; - for (let i = 0, len = oldPeriods.length; i < len; i++) { - let period = oldPeriods[i]; - if (period.id === periodId) { - period = { - ...period, - daysWorked: Math.min(Math.max(daysWorked, 0), 5), - }; - } - periods.push(period); + const periodsData = state.periodsData[0]; + const periodData = periodsData[periodId]; + daysWorked = Math.min(Math.max(daysWorked, periodData.daysPaid), 5); + if (daysWorked === periodData.daysWorked) { + return state; } + periodsData[periodId] = { ...periodData, daysWorked }; return { ...state, - periods, + periodsData: [periodsData], }; }, [ACTION_TYPE.WP_TOGGLE_PERIOD]: (state, periodId) => { diff --git a/src/store/selectors/workPeriods.js b/src/store/selectors/workPeriods.js index d0ad0ab..060d93f 100644 --- a/src/store/selectors/workPeriods.js +++ b/src/store/selectors/workPeriods.js @@ -64,6 +64,8 @@ export const getWorkPeriodsPageSize = (state) => export const getWorkPeriodsCount = (state) => state.workPeriods.periods.length; +export const getWorkPeriodsData = (state) => state.workPeriods.periodsData; + export const getWorkPeriodsTotalCount = (state) => state.workPeriods.pagination.totalCount; diff --git a/src/utils/workPeriods.js b/src/utils/workPeriods.js index 3a8351e..38d18f4 100644 --- a/src/utils/workPeriods.js +++ b/src/utils/workPeriods.js @@ -77,6 +77,7 @@ export function normalizeDetailsPeriodItems(items) { payments: item.payments || [], weeklyRate: item.memberRate, daysWorked: daysWorked === null ? 5 : +daysWorked || 0, + daysPaid: +item.daysPaid || 0, }); } periods.sort(sortByStartDate); From 4b8dbf279c9a1a4c53a4fe49f9886e530463d0af Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Thu, 17 Jun 2021 06:43:59 +0300 Subject: [PATCH 4/5] Added 'Total Paid' column. --- src/constants/workPeriods.js | 2 ++ src/constants/workPeriods/apiSortBy.js | 1 + src/constants/workPeriods/sortBy.js | 1 + .../components/PeriodDetails/index.jsx | 2 +- .../components/PeriodItem/index.jsx | 13 +++++++- .../components/PeriodItem/styles.module.scss | 14 ++++++++ .../components/PeriodList/index.jsx | 2 +- .../components/PeriodListHead/index.jsx | 1 + .../components/PeriodsHistoryItem/index.jsx | 20 ++++++------ .../PeriodsHistoryItem/styles.module.scss | 4 +-- .../index.jsx | 32 ++++++++++++------- .../styles.module.scss | 10 +++++- src/utils/workPeriods.js | 2 ++ 13 files changed, 76 insertions(+), 28 deletions(-) rename src/routes/WorkPeriods/components/{PeriodsHistoryWeeklyRate => PeriodsHistoryPaymentTotal}/index.jsx (74%) rename src/routes/WorkPeriods/components/{PeriodsHistoryWeeklyRate => PeriodsHistoryPaymentTotal}/styles.module.scss (69%) diff --git a/src/constants/workPeriods.js b/src/constants/workPeriods.js index 34b3924..0a41526 100644 --- a/src/constants/workPeriods.js +++ b/src/constants/workPeriods.js @@ -34,6 +34,7 @@ export const REQUIRED_FIELDS = [ "workPeriods.startDate", "workPeriods.endDate", "workPeriods.paymentStatus", + "workPeriods.paymentTotal", "workPeriods.daysWorked", "workPeriods.daysPaid", ]; @@ -59,6 +60,7 @@ export const SORT_BY_MAP = { [SORT_BY.END_DATE]: API_SORT_BY.END_DATE, [SORT_BY.WEEKLY_RATE]: API_SORT_BY.WEEKLY_RATE, [SORT_BY.PAYMENT_STATUS]: API_SORT_BY.PAYMENT_STATUS, + [SORT_BY.PAYMENT_TOTAL]: API_SORT_BY.PAYMENT_TOTAL, [SORT_BY.WORKING_DAYS]: API_SORT_BY.WORKING_DAYS, }; diff --git a/src/constants/workPeriods/apiSortBy.js b/src/constants/workPeriods/apiSortBy.js index c1bfc14..4f5de41 100644 --- a/src/constants/workPeriods/apiSortBy.js +++ b/src/constants/workPeriods/apiSortBy.js @@ -3,4 +3,5 @@ export const START_DATE = "startDate"; export const END_DATE = "endDate"; export const WEEKLY_RATE = "memberRate"; export const PAYMENT_STATUS = "workPeriods.paymentStatus"; +export const PAYMENT_TOTAL = "workPeriods.paymentTotal"; export const WORKING_DAYS = "workPeriods.daysWorked"; diff --git a/src/constants/workPeriods/sortBy.js b/src/constants/workPeriods/sortBy.js index 4c20856..cafb587 100644 --- a/src/constants/workPeriods/sortBy.js +++ b/src/constants/workPeriods/sortBy.js @@ -5,4 +5,5 @@ export const END_DATE = "END_DATE"; export const ALERT = "ALERT"; export const WEEKLY_RATE = "WEEKLY_RATE"; export const PAYMENT_STATUS = "STATUS"; +export const PAYMENT_TOTAL = "TOTAL_PAYMENT"; export const WORKING_DAYS = "WORKING_DAYS"; diff --git a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx index 18bc861..687e5d5 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx @@ -124,7 +124,7 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => {
- +
History diff --git a/src/routes/WorkPeriods/components/PeriodItem/index.jsx b/src/routes/WorkPeriods/components/PeriodItem/index.jsx index 0d615c8..14b9c82 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodItem/index.jsx @@ -17,7 +17,11 @@ import { updateWorkPeriodWorkingDays, } from "store/thunks/workPeriods"; import { useUpdateEffect } from "utils/hooks"; -import { formatUserHandleLink, formatWeeklyRate } from "utils/formatters"; +import { + currencyFormatter, + formatUserHandleLink, + formatWeeklyRate, +} from "utils/formatters"; import { stopPropagation } from "utils/misc"; import styles from "./styles.module.scss"; @@ -117,6 +121,12 @@ const PeriodItem = ({ {formatWeeklyRate(item.weeklyRate)} + + + {currencyFormatter.format(item.paymentTotal)} + + ({data.daysPaid}) + @@ -158,6 +168,7 @@ PeriodItem.propTypes = { endDate: PT.string.isRequired, weeklyRate: PT.number, paymentStatus: PT.string.isRequired, + paymentTotal: PT.number.isRequired, }).isRequired, data: PT.shape({ daysWorked: PT.number.isRequired, diff --git a/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss b/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss index 7cb0181..6c24821 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss @@ -77,6 +77,20 @@ td.weeklyRate { } } +td.paymentTotal { + white-space: nowrap; +} + +.paymentTotalSum { + display: inline-block; + width: 70px; + text-align: right; +} + +.daysPaid { + color: #aaa; +} + td.daysWorked { padding: 5px 10px; } diff --git a/src/routes/WorkPeriods/components/PeriodList/index.jsx b/src/routes/WorkPeriods/components/PeriodList/index.jsx index 5ffedf0..6394127 100644 --- a/src/routes/WorkPeriods/components/PeriodList/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodList/index.jsx @@ -39,7 +39,7 @@ const PeriodList = ({ className }) => { - + {periods.map((period) => ( { {formatDateRange(item.startDate, item.endDate)} {dateLabel} - - + @@ -103,6 +100,7 @@ PeriodsHistoryItem.propTypes = { endDate: PT.oneOfType([PT.string, PT.number]).isRequired, paymentStatus: PT.string.isRequired, payments: PT.array, + paymentTotal: PT.number.isRequired, weeklyRate: PT.number, }).isRequired, data: PT.shape({ diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss b/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss index fb3d65c..c91363d 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodsHistoryItem/styles.module.scss @@ -27,12 +27,12 @@ } } -.weeklyRate { +.paymentTotal { padding: 6px 12px; line-height: 26px; } -.weeklyRateContainer { +.paymentTotalContainer { position: relative; } diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryWeeklyRate/index.jsx b/src/routes/WorkPeriods/components/PeriodsHistoryPaymentTotal/index.jsx similarity index 74% rename from src/routes/WorkPeriods/components/PeriodsHistoryWeeklyRate/index.jsx rename to src/routes/WorkPeriods/components/PeriodsHistoryPaymentTotal/index.jsx index 8383ecc..fdc8cea 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryWeeklyRate/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodsHistoryPaymentTotal/index.jsx @@ -3,11 +3,17 @@ import React, { useCallback, useRef, useState } from "react"; import { usePopper } from "react-popper"; import PT from "prop-types"; import cn from "classnames"; -import ChallengePopup from "../PaymentsPopup"; -import compStyles from "./styles.module.scss"; +import PaymentsPopup from "../PaymentsPopup"; import { useClickOutside } from "utils/hooks"; +import { currencyFormatter } from "utils/formatters"; +import compStyles from "./styles.module.scss"; -const PeriodsHistoryWeeklyRate = ({ className, payments, weeklyRate }) => { +const PeriodsHistoryPaymentTotal = ({ + className, + payments, + paymentTotal, + daysPaid, +}) => { const [isShowPopup, setIsShowPopup] = useState(false); const containerRef = useRef(); @@ -37,15 +43,18 @@ const PeriodsHistoryWeeklyRate = ({ className, payments, weeklyRate }) => { return (
- - {weeklyRate} - + + {currencyFormatter.format(paymentTotal)} + + ({daysPaid}) +
{hasPayments && isShowPopup && (
{ style={styles.popper} {...attributes.popper} > - +
{ ); }; -PeriodsHistoryWeeklyRate.propTypes = { +PeriodsHistoryPaymentTotal.propTypes = { className: PT.string, payments: PT.array, - weeklyRate: PT.string.isRequired, + paymentTotal: PT.number.isRequired, + daysPaid: PT.number.isRequired, }; function negate(value) { return !value; } -export default PeriodsHistoryWeeklyRate; +export default PeriodsHistoryPaymentTotal; diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryWeeklyRate/styles.module.scss b/src/routes/WorkPeriods/components/PeriodsHistoryPaymentTotal/styles.module.scss similarity index 69% rename from src/routes/WorkPeriods/components/PeriodsHistoryWeeklyRate/styles.module.scss rename to src/routes/WorkPeriods/components/PeriodsHistoryPaymentTotal/styles.module.scss index 8ab6350..60b6009 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryWeeklyRate/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodsHistoryPaymentTotal/styles.module.scss @@ -6,12 +6,20 @@ } } -.weeklyRateValue { +.paymentTotal { + white-space: nowrap; +} + +.paymentTotalSum { display: inline-block; width: 70px; text-align: right; } +.daysPaid { + color: #aaa; +} + .hasPayments { cursor: pointer; } diff --git a/src/utils/workPeriods.js b/src/utils/workPeriods.js index 38d18f4..a61c999 100644 --- a/src/utils/workPeriods.js +++ b/src/utils/workPeriods.js @@ -26,6 +26,7 @@ export function normalizePeriodItems(items) { endDate: item.endDate ? moment(item.endDate).format(DATE_FORMAT_UI) : "", weeklyRate: item.memberRate, paymentStatus: normalizePaymentStatus(workPeriod.paymentStatus), + paymentTotal: +workPeriod.paymentTotal || 0, daysWorked: daysWorked === null ? 5 : +daysWorked || 0, daysPaid: +workPeriod.daysPaid || 0, }); @@ -75,6 +76,7 @@ export function normalizeDetailsPeriodItems(items) { endDate: item.endDate ? moment(item.endDate).valueOf() : 0, paymentStatus: normalizePaymentStatus(item.paymentStatus), payments: item.payments || [], + paymentTotal: +item.paymentTotal || 0, weeklyRate: item.memberRate, daysWorked: daysWorked === null ? 5 : +daysWorked || 0, daysPaid: +item.daysPaid || 0, From c5c670f55988d0c6b1ab350ec595f2dbfafdb8e0 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Thu, 17 Jun 2021 12:35:58 +0300 Subject: [PATCH 5/5] Implemented period data updating from server. --- .../PaymentStatus/styles.module.scss | 7 +- .../components/PeriodItem/index.jsx | 8 +- .../components/PeriodsHistoryItem/index.jsx | 10 +-- src/services/workPeriods.js | 14 +++- src/store/actionTypes/workPeriods.js | 3 + src/store/actions/workPeriods.js | 22 ++++++ src/store/reducers/workPeriods.js | 75 ++++++++++++++----- src/store/thunks/workPeriods.js | 46 ++++++++++-- src/utils/workPeriods.js | 32 +++++--- 9 files changed, 167 insertions(+), 50 deletions(-) diff --git a/src/routes/WorkPeriods/components/PaymentStatus/styles.module.scss b/src/routes/WorkPeriods/components/PaymentStatus/styles.module.scss index 162480c..0fcef2e 100644 --- a/src/routes/WorkPeriods/components/PaymentStatus/styles.module.scss +++ b/src/routes/WorkPeriods/components/PaymentStatus/styles.module.scss @@ -1,4 +1,5 @@ @import "styles/mixins"; +@import "styles/variables"; .container { display: inline-block; @@ -25,7 +26,10 @@ background: #9d41c9; } -.cancelled, +.cancelled { + background: #999; +} + .failed { background: #da0000; } @@ -37,4 +41,5 @@ line-height: 20px; letter-spacing: normal; background: transparent; + color: $text-color; } diff --git a/src/routes/WorkPeriods/components/PeriodItem/index.jsx b/src/routes/WorkPeriods/components/PeriodItem/index.jsx index 14b9c82..134798f 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodItem/index.jsx @@ -123,12 +123,12 @@ const PeriodItem = ({ - {currencyFormatter.format(item.paymentTotal)} + {currencyFormatter.format(data.paymentTotal)} ({data.daysPaid}) - + { - + - {item.paymentStatus === PAYMENT_STATUS.PAID ? ( + {data.paymentStatus === PAYMENT_STATUS.PAID ? ( `${daysWorked} ${daysWorked === 1 ? "Day" : "Days"}` ) : ( { * * @param {string} periodId working period id * @param {number} daysWorked new number of working days - * @returns {Promise} + * @returns {[Promise, Object]} */ export const patchWorkPeriodWorkingDays = (periodId, daysWorked) => { - return axios.patch(`${WORK_PERIODS_API_URL}/${periodId}`, { daysWorked }); + const source = CancelToken.source(); + return [ + axios + .patch( + `${WORK_PERIODS_API_URL}/${periodId}`, + { daysWorked }, + { cancelToken: source.token } + ) + .then(extractResponseData), + source, + ]; }; /** diff --git a/src/store/actionTypes/workPeriods.js b/src/store/actionTypes/workPeriods.js index 23196b9..85eb490 100644 --- a/src/store/actionTypes/workPeriods.js +++ b/src/store/actionTypes/workPeriods.js @@ -19,6 +19,9 @@ export const WP_SET_DETAILS_HIDE_PAST_PERIODS = "WP_SET_DETAILS_HIDE_PAST_PERIODS"; export const WP_SET_PAGE_NUMBER = "WP_SET_PAGE_NUMBER"; export const WP_SET_PAGE_SIZE = "WP_SET_PAGE_SIZE"; +export const WP_SET_DATA_PENDING = "WP_SET_DATA_PENDING"; +export const WP_SET_DATA_SUCCESS = "WP_SET_DATA_SUCCESS"; +export const WP_SET_DATA_ERROR = "WP_SET_DATA_ERROR"; export const WP_SET_DATE_RANGE = "WP_SET_DATE_RANGE"; export const WP_SET_SORT_BY = "WP_SET_SORT_BY"; export const WP_SET_SORT_ORDER = "WP_SET_SORT_ORDER"; diff --git a/src/store/actions/workPeriods.js b/src/store/actions/workPeriods.js index 198e380..592cd1c 100644 --- a/src/store/actions/workPeriods.js +++ b/src/store/actions/workPeriods.js @@ -318,6 +318,28 @@ export const setWorkPeriodWorkingDays = (periodId, daysWorked) => ({ payload: { periodId, daysWorked }, }); +/** + * Creates an action denoting the update of working period's changeable data. + * + * @param {Object} periodId working period id + * @param {Object} cancelSource axios cancel token source + * @returns {Object} + */ +export const setWorkPeriodDataPending = (periodId, cancelSource) => ({ + type: ACTION_TYPE.WP_SET_DATA_PENDING, + payload: { periodId, cancelSource }, +}); + +export const setWorkPeriodDataSuccess = (periodId, data) => ({ + type: ACTION_TYPE.WP_SET_DATA_SUCCESS, + payload: { periodId, data }, +}); + +export const setWorkPeriodDataError = (periodId, message) => ({ + type: ACTION_TYPE.WP_SET_DATA_ERROR, + payload: { periodId, message }, +}); + /** * Creates an action to toggle certain working period by its id. * diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js index 4a0fbcb..0ea2522 100644 --- a/src/store/reducers/workPeriods.js +++ b/src/store/reducers/workPeriods.js @@ -36,12 +36,6 @@ const initFilters = () => ({ userHandle: "", }); -const initPeriodData = (daysWorked, daysPaid) => ({ - cancelSource: null, - daysWorked, - daysPaid, -}); - const initPeriodDetails = ( periodId, rbId, @@ -125,13 +119,9 @@ const actionHandlers = { : oldPagination; const periodsData = {}; for (let period of periods) { - periodsData[period.id] = initPeriodData( - period.daysWorked, - period.daysPaid - ); - // These two lines can be removed but they're kept for now for debugging. - delete period.daysWorked; - delete period.daysPaid; + period.data.cancelSource = null; + periodsData[period.id] = period.data; + delete period.data; } return { ...state, @@ -215,13 +205,9 @@ const actionHandlers = { } const periodsData = state.periodsData[0]; for (let period of details.periods) { - periodsData[period.id] = initPeriodData( - period.daysWorked, - period.daysPaid - ); - // These two lines can be removed but they're kept for now for debugging. - delete period.daysWorked; - delete period.daysPaid; + period.data.cancelSource = null; + periodsData[period.id] = period.data; + delete period.data; } periodDetails = { ...periodDetails, @@ -528,9 +514,58 @@ const actionHandlers = { }, }; }, + [ACTION_TYPE.WP_SET_DATA_PENDING]: (state, { periodId, cancelSource }) => { + const periodsData = state.periodsData[0]; + const periodData = periodsData[periodId]; + if (!periodData) { + return state; + } + periodsData[periodId] = { + ...periodData, + cancelSource, + }; + return { + ...state, + periodsData: [periodsData], + }; + }, + [ACTION_TYPE.WP_SET_DATA_SUCCESS]: (state, { periodId, data }) => { + const periodsData = state.periodsData[0]; + const periodData = periodsData[periodId]; + if (!periodData) { + return state; + } + periodsData[periodId] = { + ...periodData, + ...data, + cancelSource: null, + }; + return { + ...state, + periodsData: [periodsData], + }; + }, + [ACTION_TYPE.WP_SET_DATA_ERROR]: (state, { periodId }) => { + const periodsData = state.periodsData[0]; + const periodData = periodsData[periodId]; + if (!periodData) { + return state; + } + periodsData[periodId] = { + ...periodData, + cancelSource: null, + }; + return { + ...state, + periodsData: [periodsData], + }; + }, [ACTION_TYPE.WP_SET_WORKING_DAYS]: (state, { periodId, daysWorked }) => { const periodsData = state.periodsData[0]; const periodData = periodsData[periodId]; + if (!periodData) { + return state; + } daysWorked = Math.min(Math.max(daysWorked, periodData.daysPaid), 5); if (daysWorked === periodData.daysWorked) { return state; diff --git a/src/store/thunks/workPeriods.js b/src/store/thunks/workPeriods.js index 7cff821..785f807 100644 --- a/src/store/thunks/workPeriods.js +++ b/src/store/thunks/workPeriods.js @@ -19,6 +19,7 @@ import { import { normalizeBillingAccounts, normalizeDetailsPeriodItems, + normalizePeriodData, normalizePeriodItems, } from "utils/workPeriods"; import { makeToast } from "components/ToastrMessage"; @@ -217,20 +218,49 @@ export const updateWorkPeriodBillingAccount = }; /** + * Sends an update request to the server to update the number of working + * period's working days. The working period is also updated with the data + * from response. * - * @param {string} periodId - * @param {number} daysWorked + * @param {string} periodId working period id + * @param {number} daysWorked working period's working days * @returns {function} */ export const updateWorkPeriodWorkingDays = - (periodId, daysWorked) => async () => { + (periodId, daysWorked) => async (dispatch, getState) => { + let [periodsData] = selectors.getWorkPeriodsData(getState()); + periodsData[periodId]?.cancelSource?.cancel(); + const [promise, source] = services.patchWorkPeriodWorkingDays( + periodId, + daysWorked + ); + dispatch(actions.setWorkPeriodDataPending(periodId, source)); + let periodData = null; + let errorMessage = null; try { - await services.patchWorkPeriodWorkingDays(periodId, daysWorked); + const data = await promise; + periodData = normalizePeriodData(data); } catch (error) { - makeToast( - `Failed to update working days for working period ${periodId}.\n` + - error.toString() - ); + if (!axios.isCancel(error)) { + errorMessage = error.toString(); + makeToast( + `Failed to update working days for working period ${periodId}.\n` + + errorMessage + ); + } + } + [periodsData] = selectors.getWorkPeriodsData(getState()); + const currentDaysWorked = periodsData[periodId]?.daysWorked; + // If periodData is null it means the request was cancelled right before + // another request was sent and so we don't need to update the state. + // If periodData's daysWorked is not equal to the current daysWorked + // it means that the state was changed while the data was in transit + // and there will be a new request at the end of which the period's data + // will be updated so again we don't need to update the state. + if (periodData && periodData.daysWorked === currentDaysWorked) { + dispatch(actions.setWorkPeriodDataSuccess(periodId, periodData)); + } else if (errorMessage) { + dispatch(actions.setWorkPeriodDataError(periodId, errorMessage)); } }; diff --git a/src/utils/workPeriods.js b/src/utils/workPeriods.js index a61c999..6e05f70 100644 --- a/src/utils/workPeriods.js +++ b/src/utils/workPeriods.js @@ -11,7 +11,6 @@ export function normalizePeriodItems(items) { for (let item of items) { const workPeriod = item.workPeriods?.[0] || empty; const billingAccountId = item.billingAccountId; - const daysWorked = workPeriod.daysWorked; periods.push({ id: workPeriod.id || item.id, rbId: item.id, @@ -25,15 +24,32 @@ export function normalizePeriodItems(items) { : "", endDate: item.endDate ? moment(item.endDate).format(DATE_FORMAT_UI) : "", weeklyRate: item.memberRate, - paymentStatus: normalizePaymentStatus(workPeriod.paymentStatus), - paymentTotal: +workPeriod.paymentTotal || 0, - daysWorked: daysWorked === null ? 5 : +daysWorked || 0, - daysPaid: +workPeriod.daysPaid || 0, + data: normalizePeriodData(workPeriod), }); } return periods; } +/** + * Normalizes specific working period data (daysWorked, daysPaid, + * paymentStatus, paymentTotal). + * + * @param {Object} period + * @param {number} period.daysWorked + * @param {number} period.daysPaid + * @param {string} period.paymentStatus + * @param {number} period.paymentTotal + * @returns {Object} + */ +export function normalizePeriodData(period) { + return { + daysWorked: period.daysWorked === null ? 5 : +period.daysWorked || 0, + daysPaid: +period.daysPaid || 0, + paymentStatus: normalizePaymentStatus(period.paymentStatus), + paymentTotal: +period.paymentTotal || 0, + }; +} + /** * Creates options to be used in dropdown selecting working period's * billing account. @@ -69,17 +85,13 @@ export function createAssignedBillingAccountOption(accountId) { export function normalizeDetailsPeriodItems(items) { const periods = []; for (let item of items) { - const daysWorked = item.daysWorked; periods.push({ id: item.id, startDate: item.startDate ? moment(item.startDate).valueOf() : 0, endDate: item.endDate ? moment(item.endDate).valueOf() : 0, - paymentStatus: normalizePaymentStatus(item.paymentStatus), payments: item.payments || [], - paymentTotal: +item.paymentTotal || 0, weeklyRate: item.memberRate, - daysWorked: daysWorked === null ? 5 : +daysWorked || 0, - daysPaid: +item.daysPaid || 0, + data: normalizePeriodData(item), }); } periods.sort(sortByStartDate);