diff --git a/src/components/Checkbox/styles.module.scss b/src/components/Checkbox/styles.module.scss index e07c408..c07881a 100644 --- a/src/components/Checkbox/styles.module.scss +++ b/src/components/Checkbox/styles.module.scss @@ -56,6 +56,7 @@ input.checkbox { border-radius: 3px; line-height: 18px; user-select: none; + background-color: #fff; color: transparent; &::before { diff --git a/src/components/ProjectName/index.jsx b/src/components/ProjectName/index.jsx index 463c531..33be6fd 100644 --- a/src/components/ProjectName/index.jsx +++ b/src/components/ProjectName/index.jsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect } from "react"; +import React, { memo, useContext, useEffect } from "react"; import PT from "prop-types"; import cn from "classnames"; import { ProjectNameContext } from "components/ProjectNameContextProvider"; @@ -6,13 +6,16 @@ import styles from "./styles.module.scss"; const ProjectName = ({ className, projectId }) => { const [getName, fetchName] = useContext(ProjectNameContext); + useEffect(() => { fetchName(projectId); }, [fetchName, projectId]); + const projectName = getName(projectId) || projectId; + return ( - <span className={cn(styles.container, className)}> - {getName(projectId) || projectId} + <span className={cn(styles.container, className)} title={projectName}> + {projectName} </span> ); }; @@ -22,4 +25,4 @@ ProjectName.propTypes = { projectId: PT.number.isRequired, }; -export default ProjectName; +export default memo(ProjectName); diff --git a/src/components/ProjectName/styles.module.scss b/src/components/ProjectName/styles.module.scss index f098c8d..5900b9c 100644 --- a/src/components/ProjectName/styles.module.scss +++ b/src/components/ProjectName/styles.module.scss @@ -1,5 +1,10 @@ @import "styles/mixins"; .container { + display: block; + max-width: 20em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; @include roboto-medium; } diff --git a/src/components/SearchHandleField/styles.module.scss b/src/components/SearchHandleField/styles.module.scss index 266d7d4..1cc06f8 100644 --- a/src/components/SearchHandleField/styles.module.scss +++ b/src/components/SearchHandleField/styles.module.scss @@ -2,6 +2,7 @@ @import "styles/mixins"; .container { + z-index: 3; position: relative; display: flex; align-items: center; diff --git a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx index 146d645..a5a86b8 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx @@ -12,7 +12,6 @@ import { hideWorkPeriodDetails, setBillingAccount, setDetailsHidePastPeriods, - // setDetailsLockWorkingDays, } from "store/actions/workPeriods"; import styles from "./styles.module.scss"; import { updateWorkPeriodBillingAccount } from "store/thunks/workPeriods"; @@ -42,7 +41,6 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { periodsVisible, periodsIsLoading, hidePastPeriods, - // lockWorkingDays, } = details; const onHideDetailsBtnClick = useCallback(() => { @@ -56,13 +54,6 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { [dispatch, periodId] ); - // const onChangeLockWorkingDays = useCallback( - // (lock) => { - // dispatch(setDetailsLockWorkingDays(periodId, lock)); - // }, - // [dispatch, periodId] - // ); - const onChangeBillingAccount = useCallback( (value) => { dispatch(setBillingAccount(periodId, value)); @@ -113,16 +104,6 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { </div> </div> </div> - {/* <div className={styles.lockWorkingDaysSection}> - <div className={styles.sectionLabel}>Lock Working Days</div> - <Toggle - size="small" - className={styles.lockWorkingDaysToggle} - name={`rb_lck_wd_${periodId}`} - onChange={onChangeLockWorkingDays} - isOn={lockWorkingDays} - /> - </div> */} <div className={styles.billingAccountSection}> <div className={styles.sectionLabel}>Billing Account</div> <SelectField @@ -188,7 +169,7 @@ PeriodDetails.propTypes = { billingAccounts: PT.arrayOf( PT.shape({ label: PT.string.isRequired, - value: PT.string.isRequired, + value: PT.number.isRequired, }) ), billingAccountsError: PT.string, @@ -197,7 +178,6 @@ PeriodDetails.propTypes = { periodsVisible: PT.array.isRequired, periodsIsLoading: PT.bool.isRequired, hidePastPeriods: PT.bool.isRequired, - lockWorkingDays: PT.bool.isRequired, }).isRequired, isDisabled: PT.bool.isRequired, isFailed: PT.bool.isRequired, diff --git a/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss b/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss index 3410973..1553b9a 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss @@ -69,14 +69,6 @@ color: #e90c5a; } -.lockWorkingDaysSection { - margin-top: 19px; -} - -.lockWorkingDaysToggle { - margin-top: 6px; -} - .billingAccountSection { margin-top: 13px; } diff --git a/src/routes/WorkPeriods/components/PeriodItem/index.jsx b/src/routes/WorkPeriods/components/PeriodItem/index.jsx index 7b790ab..ae5cf84 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodItem/index.jsx @@ -166,16 +166,12 @@ PeriodItem.propTypes = { billingAccountId: PT.number.isRequired, billingAccounts: PT.arrayOf( PT.shape({ - value: PT.string.isRequired, label: PT.string.isRequired, + value: PT.number.isRequired, }) - ), + ).isRequired, billingAccountsIsLoading: PT.bool.isRequired, - periods: PT.arrayOf( - PT.shape({ - id: PT.string.isRequired, - }) - ), + periods: PT.array.isRequired, periodsIsLoading: PT.bool.isRequired, }), }; diff --git a/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx b/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx index 8934dff..5bbfabc 100644 --- a/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodsHistoryItem/index.jsx @@ -105,7 +105,7 @@ PeriodsHistoryItem.propTypes = { endDate: PT.oneOfType([PT.string, PT.number]).isRequired, paymentStatus: PT.string.isRequired, payments: PT.array, - weeklyRate: PT.number.isRequired, + weeklyRate: PT.number, workingDays: PT.number.isRequired, }).isRequired, currentStartDate: PT.oneOfType([PT.string, PT.number, PT.object]).isRequired, diff --git a/src/routes/WorkPeriods/components/PeriodsSelectionMessage/index.jsx b/src/routes/WorkPeriods/components/PeriodsSelectionMessage/index.jsx index 1202bfd..f937827 100644 --- a/src/routes/WorkPeriods/components/PeriodsSelectionMessage/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodsSelectionMessage/index.jsx @@ -29,25 +29,20 @@ const PeriodsSelectionMessage = ({ className }) => { dispatch(toggleWorkingPeriodsAll()); }, [dispatch]); - const infoText = isSelectedAll - ? `All ${totalCount} Records are selected. ` - : `All ${pageSize} Records on this page are selected. `; - const btnText = isSelectedAll - ? "Deselect" - : `Select all ${totalCount} Records`; - return ( <div className={cn(styles.container, className)}> - {isSelectedVisible && ( + {isSelectedVisible && totalCount > pageSize && ( <span className={styles.message}> - {infoText} + {isSelectedAll + ? `All ${totalCount} Records are selected. ` + : `All ${pageSize} Records on this page are selected. `} <span className={styles.button} onClick={onBtnClick} role="button" tabIndex={0} > - {btnText} + {isSelectedAll ? "Deselect" : `Select all ${totalCount} Records`} </span> </span> )} diff --git a/src/routes/WorkPeriods/components/ToastPaymentsWarning/index.jsx b/src/routes/WorkPeriods/components/ToastPaymentsWarning/index.jsx index 256f86d..7a73bd1 100644 --- a/src/routes/WorkPeriods/components/ToastPaymentsWarning/index.jsx +++ b/src/routes/WorkPeriods/components/ToastPaymentsWarning/index.jsx @@ -8,10 +8,17 @@ import styles from "./styles.module.scss"; * payments have been scheduled or failed to schedule. * * @param {Object} props component properties + * @param {number} props.resourcesSucceededCount the number of resources + * for which payments have been successfully scheduled + * @param {Array} [props.resourcesFailed] array with data for resources + * for which payments were failed to be scheduled + * @param {number} props.resourcesFailedCount the number of resources + * for which payments were failed to be scheduled + * @param {() => void} [props.remove] function that must be called + * on toast message removal intent * @returns {JSX.Element} */ const ToastPaymentsWarning = ({ - resourcesSucceeded, resourcesSucceededCount, resourcesFailed, resourcesFailedCount, @@ -23,15 +30,6 @@ const ToastPaymentsWarning = ({ <div className={styles.sectionTitle}> Payment scheduled for {resourcesSucceededCount} resources </div> - {resourcesSucceeded && resourcesSucceeded.length && ( - <div className={styles.periodsSucceeded}> - {resourcesSucceeded.map((period) => ( - <div key={period.workPeriodId} className={styles.periodSucceeded}> - {period.workPeriodId} - </div> - ))} - </div> - )} </div> <div className={styles.sectionFailed}> <div className={styles.sectionTitle}> @@ -53,12 +51,6 @@ const ToastPaymentsWarning = ({ }; ToastPaymentsWarning.propTypes = { - resourcesSucceeded: PT.arrayOf( - PT.shape({ - workPeriodId: PT.string.isRequired, - amount: PT.number, - }) - ), resourcesSucceededCount: PT.number.isRequired, resourcesFailed: PT.arrayOf( PT.shape({ diff --git a/src/routes/WorkPeriods/components/ToastPaymentsWarning/styles.module.scss b/src/routes/WorkPeriods/components/ToastPaymentsWarning/styles.module.scss index fcc4b34..5b0aebb 100644 --- a/src/routes/WorkPeriods/components/ToastPaymentsWarning/styles.module.scss +++ b/src/routes/WorkPeriods/components/ToastPaymentsWarning/styles.module.scss @@ -3,10 +3,5 @@ } .sectionSucceeded { - margin-bottom: 10px; - background: #1dcfa0; -} - -.sectionFailed { - background: #ff7b7b; + margin-bottom: 5px; } diff --git a/src/routes/WorkPeriods/utils/toasts.jsx b/src/routes/WorkPeriods/utils/toasts.jsx index f653c5f..7a420b4 100644 --- a/src/routes/WorkPeriods/utils/toasts.jsx +++ b/src/routes/WorkPeriods/utils/toasts.jsx @@ -44,8 +44,6 @@ export function makeToastPaymentsSuccess(resourceCount) { * payments were successfully scheduled * @param {number} props.resourcesFailedCount the number of periods for which * payments were failed to be scheduled - * @param {Array} [props.resourcesSucceeded] periods for which payments were - * successfully scheduled * @param {Array} [props.resourcesFailed] periods for which payments were failed * to be scheduled */ diff --git a/src/services/workPeriods.js b/src/services/workPeriods.js index b4a5515..8928618 100644 --- a/src/services/workPeriods.js +++ b/src/services/workPeriods.js @@ -142,6 +142,20 @@ export const postWorkPeriodsPayments = (payments) => { * @returns {Promise} */ export const postWorkPeriodsPaymentsAll = (query) => { + for (let key in query) { + let value = query[key]; + if (typeof value !== "number" && !value) { + delete query[key]; + continue; + } + if (Array.isArray(value)) { + if (value.length) { + query[key] = value.join(","); + } else { + delete query[key]; + } + } + } return axios .post(`${PAYMENTS_API_URL}/query`, { query }) .then(extractResponseData); diff --git a/src/store/actionTypes/workPeriods.js b/src/store/actionTypes/workPeriods.js index 511d5fe..23196b9 100644 --- a/src/store/actionTypes/workPeriods.js +++ b/src/store/actionTypes/workPeriods.js @@ -17,8 +17,6 @@ export const WP_SET_BILLING_ACCOUNT = "WP_SET_BILLING_ACCOUNT"; export const WP_SET_DETAILS_WORKING_DAYS = "WP_SET_DETAILS_WORKING_DAYS"; export const WP_SET_DETAILS_HIDE_PAST_PERIODS = "WP_SET_DETAILS_HIDE_PAST_PERIODS"; -export const WP_SET_DETAILS_LOCK_WORKING_DAYS = - "WP_SET_DETAILS_LOCK_WORKING_DAYS"; export const WP_SET_PAGE_NUMBER = "WP_SET_PAGE_NUMBER"; export const WP_SET_PAGE_SIZE = "WP_SET_PAGE_SIZE"; export const WP_SET_DATE_RANGE = "WP_SET_DATE_RANGE"; diff --git a/src/store/actions/workPeriods.js b/src/store/actions/workPeriods.js index 61920fe..d93bff5 100644 --- a/src/store/actions/workPeriods.js +++ b/src/store/actions/workPeriods.js @@ -185,11 +185,6 @@ export const setDetailsHidePastPeriods = (periodId, hide) => ({ payload: { periodId, hide }, }); -export const setDetailsLockWorkingDays = (periodId, lock) => ({ - type: ACTION_TYPE.WP_SET_DETAILS_LOCK_WORKING_DAYS, - payload: { periodId, lock }, -}); - /** * Creates an action to reset working periods' filters. * diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js index 706ca1a..110d2d8 100644 --- a/src/store/reducers/workPeriods.js +++ b/src/store/reducers/workPeriods.js @@ -59,7 +59,6 @@ const initPeriodDetails = ( periodsVisible: [], periodsIsLoading: true, hidePastPeriods: false, - lockWorkingDays: false, }); const initialState = { @@ -375,21 +374,6 @@ const actionHandlers = { periodsDetails, }; }, - [ACTION_TYPE.WP_SET_DETAILS_LOCK_WORKING_DAYS]: ( - state, - { periodId, lock } - ) => { - const periodsDetails = { ...state.periodsDetails }; - let periodDetails = periodsDetails[periodId]; - if (!periodDetails) { - return state; - } - periodsDetails[periodId] = { ...periodDetails, lockWorkingDays: lock }; - return { - ...state, - periodsDetails, - }; - }, [ACTION_TYPE.WP_SET_DETAILS_WORKING_DAYS]: ( state, { parentPeriodId, periodId, workingDays } @@ -455,7 +439,15 @@ const actionHandlers = { delete periodsSelected[periodId]; } } - if (Object.keys(periodsSelected).length === state.pagination.pageSize) { + const selectedCount = Object.keys(periodsSelected).length; + const pageSize = state.pagination.pageSize; + const totalCount = state.pagination.totalCount; + if (totalCount > pageSize) { + if (selectedCount === pageSize) { + isSelectedPeriodsVisible = true; + } + } else if (selectedCount === totalCount) { + isSelectedPeriodsAll = true; isSelectedPeriodsVisible = true; } return { @@ -549,7 +541,15 @@ const actionHandlers = { const isSelected = !periodsSelected[periodId]; if (isSelected) { periodsSelected[periodId] = true; - if (Object.keys(periodsSelected).length === state.pagination.pageSize) { + const selectedCount = Object.keys(periodsSelected).length; + const pageSize = state.pagination.pageSize; + const totalCount = state.pagination.totalCount; + if (totalCount > pageSize) { + if (selectedCount === pageSize) { + isSelectedPeriodsVisible = true; + } + } else if (selectedCount === totalCount) { + isSelectedPeriodsAll = true; isSelectedPeriodsVisible = true; } } else { @@ -580,18 +580,22 @@ const actionHandlers = { }; }, [ACTION_TYPE.WP_TOGGLE_PERIODS_VISIBLE]: (state, on) => { - const isSelected = on === null ? !state.isSelectedPeriodsVisible : on; + let isSelectedPeriodsAll = false; + const isSelectedPeriodsVisible = + on === null ? !state.isSelectedPeriodsVisible : on; const periodsSelected = {}; - if (isSelected) { + if (isSelectedPeriodsVisible) { for (let period of state.periods) { periodsSelected[period.id] = true; } + isSelectedPeriodsAll = + state.periods.length === state.pagination.totalCount; } return { ...state, periodsSelected, - isSelectedPeriodsAll: false, - isSelectedPeriodsVisible: isSelected, + isSelectedPeriodsAll, + isSelectedPeriodsVisible, }; }, [ACTION_TYPE.WP_TOGGLE_PROCESSING_PAYMENTS]: (state, on) => { diff --git a/src/store/thunks/workPeriods.js b/src/store/thunks/workPeriods.js index 7712130..e04818a 100644 --- a/src/store/thunks/workPeriods.js +++ b/src/store/thunks/workPeriods.js @@ -242,8 +242,10 @@ export const updateWorkPeriodWorkingDays = */ export const processPayments = async (dispatch, getState) => { dispatch(actions.toggleWorkPeriodsProcessingPeyments(true)); - const isSelectedAll = selectors.getWorkPeriodsIsSelectedAll(getState()); - if (isSelectedAll) { + const state = getState(); + const isSelectedAll = selectors.getWorkPeriodsIsSelectedAll(state); + const { pageSize, totalCount } = selectors.getWorkPeriodsPagination(state); + if (isSelectedAll && totalCount > pageSize) { processPaymentsAll(dispatch, getState); } else { processPaymentsSpecific(dispatch, getState); @@ -265,7 +267,7 @@ const processPaymentsAll = async (dispatch, getState) => { status: RESOURCE_BOOKING_STATUS.PLACED, ["workPeriods.userHandle"]: filters.userHandle, ["workPeriods.startDate"]: startDate.format(DATE_FORMAT_API), - ["workPeriods.paymentStatus"]: paymentStatuses.join(","), + ["workPeriods.paymentStatus"]: paymentStatuses, }); let data = null; let errorMessage = null; @@ -332,7 +334,6 @@ const processPaymentsSpecific = async (dispatch, getState) => { if (resourcesSucceeded.length) { if (resourcesFailed.length) { makeToastPaymentsWarning({ - resourcesSucceeded, resourcesSucceededCount: resourcesSucceeded.length, resourcesFailed, resourcesFailedCount: resourcesFailed.length,