From f3f641cbfe777afbafba8d2d26099f43c52c4322 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Sun, 13 Jun 2021 01:01:12 +0300 Subject: [PATCH 1/8] Fixed: failed periods' rows not highlighted in red --- .../components/PeriodDetails/index.jsx | 12 ++++- .../PeriodDetails/styles.module.scss | 7 +++ .../components/PeriodItem/index.jsx | 38 +++++++------- .../components/PeriodItem/styles.module.scss | 7 +++ .../components/PeriodList/index.jsx | 3 ++ src/store/actionTypes/workPeriods.js | 1 + src/store/actions/workPeriods.js | 13 +++++ src/store/reducers/workPeriods.js | 51 +++++++++++++++++-- src/store/selectors/workPeriods.js | 9 ++++ src/store/thunks/workPeriods.jsx | 10 ++-- src/styles/variables/_colors.scss | 2 + src/utils/misc.js | 13 +++-- 12 files changed, 135 insertions(+), 31 deletions(-) diff --git a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx index bf0ce72..eec7304 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx @@ -25,9 +25,10 @@ import { useUpdateEffect } from "utils/hooks"; * @param {string} [props.className] class name to be added to root element * @param {Object} props.details working period details object * @param {boolean} props.isDisabled whether the details are disabled + * @param {boolean} props.isFailed whether the payments for the period has failed * @returns {JSX.Element} */ -const PeriodDetails = ({ className, details, isDisabled }) => { +const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { const dispatch = useDispatch(); const { periodId, @@ -94,7 +95,13 @@ const PeriodDetails = ({ className, details, isDisabled }) => { billingAccounts[0].value === -1; return ( - + {periodsIsLoading ? (
Loading...
@@ -199,6 +206,7 @@ PeriodDetails.propTypes = { lockWorkingDays: PT.bool.isRequired, }).isRequired, isDisabled: PT.bool.isRequired, + isFailed: PT.bool.isRequired, }; export default memo(PeriodDetails); diff --git a/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss b/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss index 6349a41..1fafa57 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodDetails/styles.module.scss @@ -1,7 +1,14 @@ @import "styles/mixins"; +@import "styles/variables"; .container { position: relative; + + &.isFailed { + td { + // background-color: $period-row-failed-bg-color; + } + } } .loadingIndicator { diff --git a/src/routes/WorkPeriods/components/PeriodItem/index.jsx b/src/routes/WorkPeriods/components/PeriodItem/index.jsx index 92ca032..79a6084 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodItem/index.jsx @@ -17,26 +17,27 @@ import { } from "store/thunks/workPeriods"; import { useUpdateEffect } from "utils/hooks"; import { formatUserHandleLink, formatWeeklyRate } from "utils/formatters"; +import { stopPropagation } from "utils/misc"; import styles from "./styles.module.scss"; -/** - * @param {(v: string) => void} props.onToggle function called when working period checkbox is clicked - * @param {(id: object) => void} props.onToggleDetails function called when item row is clicked - * @param {(v: { periodId: string, workingDays: number }) => void} props.onWorkingDaysChange - * function called when the number of working days is changed - */ - /** * Displays the working period data row to be used in PeriodList component. * * @param {Object} props component properties * @param {boolean} [props.isDisabled] whether the item is disabled + * @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.details] object with working period details * @returns {JSX.Element} */ -const PeriodItem = ({ isDisabled = false, isSelected, item, details }) => { +const PeriodItem = ({ + isDisabled = false, + isFailed = false, + isSelected, + item, + details, +}) => { const dispatch = useDispatch(); const onToggleItem = useCallback( @@ -76,7 +77,10 @@ const PeriodItem = ({ isDisabled = false, isSelected, item, details }) => { return ( <> @@ -123,7 +127,13 @@ const PeriodItem = ({ isDisabled = false, isSelected, item, details }) => { /> - {details && } + {details && ( + + )} ); }; @@ -131,6 +141,7 @@ const PeriodItem = ({ isDisabled = false, isSelected, item, details }) => { PeriodItem.propTypes = { className: PT.string, isDisabled: PT.bool, + isFailed: PT.bool, isSelected: PT.bool.isRequired, item: PT.shape({ id: PT.oneOfType([PT.number, PT.string]).isRequired, @@ -164,13 +175,6 @@ PeriodItem.propTypes = { ), periodsIsLoading: PT.bool.isRequired, }), - // onToggle: PT.func.isRequired, - // onToggleDetails: PT.func.isRequired, - // onWorkingDaysChange: PT.func.isRequired, }; -function stopPropagation(event) { - event.stopPropagation(); -} - export default memo(PeriodItem); diff --git a/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss b/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss index 98a4561..bd8766b 100644 --- a/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss +++ b/src/routes/WorkPeriods/components/PeriodItem/styles.module.scss @@ -1,4 +1,5 @@ @import "styles/mixins"; +@import "styles/variables"; .container { td { @@ -31,6 +32,12 @@ } } } + + &.isFailed { + td { + background-color: $period-row-failed-bg-color; + } + } } td.toggle { diff --git a/src/routes/WorkPeriods/components/PeriodList/index.jsx b/src/routes/WorkPeriods/components/PeriodList/index.jsx index e925a27..8b716df 100644 --- a/src/routes/WorkPeriods/components/PeriodList/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodList/index.jsx @@ -7,6 +7,7 @@ import PeriodListHead from "../PeriodListHead"; import { getWorkPeriods, getWorkPeriodsDetails, + getWorkPeriodsFailed, getWorkPeriodsIsProcessingPayments, getWorkPeriodsSelected, } from "store/selectors/workPeriods"; @@ -22,6 +23,7 @@ import styles from "./styles.module.scss"; const PeriodList = ({ className }) => { const periods = useSelector(getWorkPeriods); const periodsDetails = useSelector(getWorkPeriodsDetails); + const periodsFailed = useSelector(getWorkPeriodsFailed); const periodsSelected = useSelector(getWorkPeriodsSelected); const isProcessingPayments = useSelector(getWorkPeriodsIsProcessingPayments); @@ -39,6 +41,7 @@ const PeriodList = ({ className }) => { ({ payload: periods, }); +/** + * Creates an action that should result in deselecting working periods for which + * the payments were successfully scheduled and in highlighting those working + * periods for which the payments were failed to be scheduled. + * + * @param {Object} periods object with period ids as keys and booleans as values + * @returns {Object} + */ +export const highlightFailedWorkPeriods = (periods) => ({ + type: ACTION_TYPE.WP_HIGHLIGHT_FAILED_PERIODS, + payload: periods, +}); + /** * Creates an action denoting the changing of working periods' page number. * diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js index 891c876..ded3471 100644 --- a/src/store/reducers/workPeriods.js +++ b/src/store/reducers/workPeriods.js @@ -56,6 +56,7 @@ const initialState = { cancelSource: cancelSourceDummy, periods: [], periodsDetails: {}, + periodsFailed: {}, periodsSelected: {}, isSelectedPeriodsAll: false, isSelectedPeriodsVisible: false, @@ -85,6 +86,7 @@ const actionHandlers = { error: null, periods: [], periodsDetails: {}, + periodsFailed: {}, periodsSelected: {}, pagination: pageNumber === state.pagination.pageNumber @@ -126,6 +128,33 @@ const actionHandlers = { periodsDetails, }; }, + [ACTION_TYPE.WP_HIGHLIGHT_FAILED_PERIODS]: (state, periods) => { + const periodIds = Object.keys(periods); + if (!periodIds.length) { + return state; + } + let isSelectedPeriodsAll = state.isSelectedPeriodsAll; + let isSelectedPeriodsVisible = state.isSelectedPeriodsVisible; + const periodsFailed = { ...state.periodsFailed }; + const periodsSelected = { ...state.periodsSelected }; + for (let periodId of periodIds) { + if (periods[periodId]) { + periodsFailed[periodId] = true; + periodsSelected[periodId] = true; + } else { + isSelectedPeriodsAll = false; + isSelectedPeriodsVisible = false; + delete periodsSelected[periodId]; + } + } + return { + ...state, + isSelectedPeriodsAll, + isSelectedPeriodsVisible, + periodsFailed, + periodsSelected, + }; + }, [ACTION_TYPE.WP_LOAD_PERIOD_DETAILS_PENDING]: ( state, { periodId, rbId, billingAccountId, cancelSource } @@ -386,16 +415,22 @@ const actionHandlers = { }; }, [ACTION_TYPE.WP_SELECT_PERIODS]: (state, periods) => { + let isSelectedPeriodsAll = state.isSelectedPeriodsAll; + let isSelectedPeriodsVisible = state.isSelectedPeriodsVisible; let periodsSelected = { ...state.periodsSelected }; for (let periodId in periods) { if (periods[periodId] === true) { periodsSelected[periodId] = true; } else { + isSelectedPeriodsAll = false; + isSelectedPeriodsVisible = false; delete periodsSelected[periodId]; } } return { ...state, + isSelectedPeriodsAll, + isSelectedPeriodsVisible, periodsSelected, }; }, @@ -520,10 +555,18 @@ const actionHandlers = { isSelectedPeriodsVisible: isSelected, }; }, - [ACTION_TYPE.WP_TOGGLE_PROCESSING_PAYMENTS]: (state, on) => ({ - ...state, - isProcessingPayments: on === null ? !state.isProcessingPayments : on, - }), + [ACTION_TYPE.WP_TOGGLE_PROCESSING_PAYMENTS]: (state, on) => { + let periodsFailed = state.periodsFailed; + let isProcessingPayments = on === null ? !state.isProcessingPayments : on; + if (isProcessingPayments) { + periodsFailed = {}; + } + return { + ...state, + periodsFailed, + isProcessingPayments, + }; + }, }; export default reducer; diff --git a/src/store/selectors/workPeriods.js b/src/store/selectors/workPeriods.js index 3719420..37f3ba6 100644 --- a/src/store/selectors/workPeriods.js +++ b/src/store/selectors/workPeriods.js @@ -23,6 +23,15 @@ export const getWorkPeriods = (state) => state.workPeriods.periods; export const getWorkPeriodsDetails = (state) => state.workPeriods.periodsDetails; +/** + * Returns an object which has working periods' ids for which the payments + * were failed to be scheduled as keys. + * + * @param {Object} state redux root state + * @returns {Object} + */ +export const getWorkPeriodsFailed = (state) => state.workPeriods.periodsFailed; + /** * Returns an object with working periods' ids as keys and booleans showing * whether the period is selected as values. diff --git a/src/store/thunks/workPeriods.jsx b/src/store/thunks/workPeriods.jsx index 2db85ff..60b0df5 100644 --- a/src/store/thunks/workPeriods.jsx +++ b/src/store/thunks/workPeriods.jsx @@ -267,18 +267,20 @@ export const processPayments = async (dispatch, getState) => { errorMessage = error.toString(); } if (results) { - const periodsToDeselect = {}; + const periodsToHighlight = {}; const periodsSucceeded = []; const periodsFailed = []; for (let result of results) { - if ("error" in result) { + let isFailed = "error" in result; + periodsToHighlight[result.workPeriodId] = isFailed; + if (isFailed) { periodsFailed.push(result); } else { - periodsToDeselect[result.workPeriodId] = false; periodsSucceeded.push(result); } } - dispatch(actions.selectWorkPeriods(periodsToDeselect)); + // highlights failed periods and deselects successful periods + dispatch(actions.highlightFailedWorkPeriods(periodsToHighlight)); if (periodsSucceeded.length) { if (periodsFailed.length) { makeWarningToast(periodsSucceeded, periodsFailed); diff --git a/src/styles/variables/_colors.scss b/src/styles/variables/_colors.scss index 9e8c6ba..77b0bd3 100644 --- a/src/styles/variables/_colors.scss +++ b/src/styles/variables/_colors.scss @@ -23,3 +23,5 @@ $control-disabled-text-color: lighten( $checkbox-bg-color: $primary-light-color; $toggle-active-bg-color: $primary-light-color; + +$period-row-failed-bg-color: #f8dde3; diff --git a/src/utils/misc.js b/src/utils/misc.js index 97d8215..17dc0e0 100644 --- a/src/utils/misc.js +++ b/src/utils/misc.js @@ -67,6 +67,15 @@ export function replaceItems(array, map) { return result; } +/** + * Stops event propagation. + * + * @param {Object} event event object + */ +export function stopPropagation(event) { + event.stopPropagation(); +} + /** * This function takes keys referring to truthy values in `newOptions` * and adds them to `oldOptions` returning a new object. @@ -134,7 +143,3 @@ export const extractResponsePagination = ({ headers }) => ({ export const extractJobName = (data) => data.title; export const extractResponseData = (response) => response.data; - -export function stopPropagation(event) { - event.stopPropagation(); -} From d42eeba2062a8c8cbefc90e5d876250600ef1d39 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Mon, 14 Jun 2021 01:34:32 +0300 Subject: [PATCH 2/8] Fixed: issues with search-handle field. --- src/components/SearchHandleField/index.jsx | 85 +++++++++++-------- .../SearchHandleField/styles.module.scss | 25 ++++-- src/store/reducers/workPeriods.js | 19 +++-- 3 files changed, 82 insertions(+), 47 deletions(-) diff --git a/src/components/SearchHandleField/index.jsx b/src/components/SearchHandleField/index.jsx index 38a2168..fbe654d 100644 --- a/src/components/SearchHandleField/index.jsx +++ b/src/components/SearchHandleField/index.jsx @@ -12,6 +12,10 @@ const selectComponents = { IndicatorSeparator: () => null, }; +const loadingMessage = () => "Loading..."; + +const noOptionsMessage = () => "No suggestions"; + /** * Displays search input field. * @@ -25,20 +29,31 @@ const selectComponents = { * @param {string} props.value input value * @returns {JSX.Element} */ -const SearchAutocomplete = ({ +const SearchHandleField = ({ className, id, + name, size = "medium", onChange, placeholder, value, }) => { - // const option = getOptionByValue(options, value); - const [savedInput, setSavedInput] = useState(""); - const onValueChange = useCallback( - (option) => { - onChange(option.value); + (option, { action }) => { + if (action === "clear") { + onChange(""); + } else { + onChange(option.value); + } + }, + [onChange] + ); + + const onInputChange = useCallback( + (value, { action }) => { + if (action === "input-change") { + onChange(value); + } }, [onChange] ); @@ -51,52 +66,52 @@ const SearchAutocomplete = ({ classNamePrefix="custom" components={selectComponents} id={id} + name={name} + isClearable={true} isSearchable={true} // menuIsOpen={true} // for debugging - // onChange={onOptionChange} - // onMenuOpen={onMenuOpen} - // onMenuClose={onMenuClose} - value={{ value, label: value }} - onInputChange={setSavedInput} - onFocus={() => { - setSavedInput(""); - onChange(savedInput); - }} - placeholder={placeholder} + value={null} + inputValue={value} onChange={onValueChange} - noOptionsMessage={() => "No options"} - loadingMessage={() => "Loading..."} + onInputChange={onInputChange} + openMenuOnClick={false} + placeholder={placeholder} + noOptionsMessage={noOptionsMessage} + loadingMessage={loadingMessage} loadOptions={loadSuggestions} - blurInputOnSelect + cacheOptions /> ); }; -const loadSuggestions = (inputVal) => { - return getMemberSuggestions(inputVal) - .then((res) => { - const users = _.get(res, "data.result.content", []); - return users.map((user) => ({ - label: user.handle, - value: user.handle, - })); - }) - .catch(() => { - console.warn("could not get suggestions"); - return []; - }); +const loadSuggestions = async (inputVal) => { + let options = []; + if (inputVal.length < 3) { + return options; + } + try { + const res = await getMemberSuggestions(inputVal); + const users = res.data.result.content; + for (let i = 0, len = users.length; i < len; i++) { + let value = users[i].handle; + options.push({ value, label: value }); + } + } catch (error) { + console.error(error); + console.warn("could not get suggestions"); + } + return options; }; -SearchAutocomplete.propTypes = { +SearchHandleField.propTypes = { className: PT.string, id: PT.string.isRequired, size: PT.oneOf(["medium", "small"]), name: PT.string.isRequired, onChange: PT.func.isRequired, - options: PT.array, placeholder: PT.string, value: PT.oneOfType([PT.number, PT.string]), }; -export default SearchAutocomplete; +export default SearchHandleField; diff --git a/src/components/SearchHandleField/styles.module.scss b/src/components/SearchHandleField/styles.module.scss index e6614cc..266d7d4 100644 --- a/src/components/SearchHandleField/styles.module.scss +++ b/src/components/SearchHandleField/styles.module.scss @@ -2,6 +2,7 @@ @import "styles/mixins"; .container { + position: relative; display: flex; align-items: center; border: 1px solid $control-border-color; @@ -18,6 +19,11 @@ } .icon { + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; margin: auto 10px; width: 16px; height: 16px; @@ -42,7 +48,7 @@ input.input { display: flex; margin: 0; border: none !important; - padding: 8px 16px 8px 0; + padding: 8px 16px 8px 36px; line-height: 22px; background: none; outline: none !important; @@ -68,6 +74,7 @@ input.input { margin: 0; border: none; padding: 0; + max-width: none !important; > * { display: flex; @@ -79,6 +86,8 @@ input.input { margin: 0; border: none; padding: 0; + max-width: none !important; + transform: none !important; } input { @@ -86,12 +95,14 @@ input.input { margin: 0 !important; padding: 0 !important; border: none !important; + max-width: none !important; width: auto !important; height: 22px !important; outline: none !important; box-shadow: none !important; line-height: 22px; color: inherit; + opacity: 1 !important; } } @@ -103,7 +114,8 @@ input.input { :global(.custom__input) { flex: 1 1 0; - display: flex; + display: flex !important; + max-width: none !important; } :global(.custom__placeholder) { @@ -115,9 +127,12 @@ input.input { } :global(.custom__menu) { - margin: 1px 0 0; + left: -1px; + right: -1px; + margin: 2px 0 0; border: 1px solid $control-border-color; border-radius: 0; + width: auto; box-shadow: none; } @@ -141,8 +156,8 @@ input.input { } } - :global(.custom__option--is-selected) { - background-color: #229174 !important; + :global(.custom__option--is-focused) { + background-color: $primary-text-color !important; color: #fff; } } diff --git a/src/store/reducers/workPeriods.js b/src/store/reducers/workPeriods.js index ded3471..5836f6e 100644 --- a/src/store/reducers/workPeriods.js +++ b/src/store/reducers/workPeriods.js @@ -481,13 +481,18 @@ const actionHandlers = { ), }, }), - [ACTION_TYPE.WP_SET_USER_HANDLE]: (state, userHandle) => ({ - ...state, - filters: { - ...state.filters, - userHandle, - }, - }), + [ACTION_TYPE.WP_SET_USER_HANDLE]: (state, userHandle) => { + if (userHandle === state.filters.userHandle) { + return state; + } + return { + ...state, + filters: { + ...state.filters, + userHandle, + }, + }; + }, [ACTION_TYPE.WP_SET_WORKING_DAYS]: (state, { periodId, workingDays }) => { const oldPeriods = state.periods; const periods = []; From e816a74f1d2d2a97b62a09f65c8115779cbe5e89 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Mon, 14 Jun 2021 01:35:25 +0300 Subject: [PATCH 3/8] Fixed: weird error caused by Redirect component. --- src/root.component.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/root.component.jsx b/src/root.component.jsx index 9bec738..fe6e308 100644 --- a/src/root.component.jsx +++ b/src/root.component.jsx @@ -20,6 +20,7 @@ export default function Root() { from={APP_BASE_PATH} to={`${APP_BASE_PATH}/work-periods`} exact + noThrow /> From b7cf7f04fc33d994dea5abf0057e2c21af151ca1 Mon Sep 17 00:00:00 2001 From: Oleg Petrov Date: Mon, 14 Jun 2021 05:41:13 +0300 Subject: [PATCH 4/8] Final fixes Removed unneded toastr messages. Corrected texts for job name states. Commented out "Lock Working Days" section. Fixed: billing accounts dispatched to redux store only after job name. Fixed: toastr messages not centered on small screens. --- src/components/Page/index.jsx | 4 +- src/components/SearchHandleField/index.jsx | 4 +- src/components/ToastrMessage/index.jsx | 18 +++ .../ToastrMessage/styles.module.scss | 14 +- src/constants/index.js | 2 + src/constants/workPeriods.js | 8 + .../components/PeriodDetails/index.jsx | 46 +++--- .../PeriodDetails/styles.module.scss | 2 +- .../components/PeriodsContentHeader/index.jsx | 1 + .../PeriodsContentHeader/styles.module.scss | 4 + .../components/PeriodsHistory/index.jsx | 20 +-- .../components/ToastPaymentsError/index.jsx | 6 +- src/routes/WorkPeriods/index.jsx | 2 +- src/routes/WorkPeriods/styles.module.scss | 4 + src/routes/WorkPeriods/utils/toasts.jsx | 61 ++++++++ src/store/reducers/workPeriods.js | 52 +++++-- .../{workPeriods.jsx => workPeriods.js} | 141 ++++++------------ src/styles/toastr.scss | 16 +- src/utils/workPeriods.js | 9 +- 19 files changed, 256 insertions(+), 158 deletions(-) create mode 100644 src/routes/WorkPeriods/utils/toasts.jsx rename src/store/thunks/{workPeriods.jsx => workPeriods.js} (71%) diff --git a/src/components/Page/index.jsx b/src/components/Page/index.jsx index 2a85959..7591493 100644 --- a/src/components/Page/index.jsx +++ b/src/components/Page/index.jsx @@ -2,6 +2,7 @@ import React from "react"; import PT from "prop-types"; import cn from "classnames"; import ReduxToastr from "react-redux-toastr"; +import { TOAST_DEFAULT_TIMEOUT } from "constants/index.js"; import styles from "./styles.module.scss"; /** @@ -16,8 +17,9 @@ const Page = ({ className, children }) => (
{children} diff --git a/src/components/SearchHandleField/index.jsx b/src/components/SearchHandleField/index.jsx index fbe654d..804b919 100644 --- a/src/components/SearchHandleField/index.jsx +++ b/src/components/SearchHandleField/index.jsx @@ -1,10 +1,8 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback } from "react"; import PT from "prop-types"; import cn from "classnames"; -import _ from "lodash"; import AsyncSelect from "react-select/async"; import { getMemberSuggestions } from "services/teams"; -// import { getOptionByValue } from "utils/misc"; import styles from "./styles.module.scss"; const selectComponents = { diff --git a/src/components/ToastrMessage/index.jsx b/src/components/ToastrMessage/index.jsx index 32aa210..bd51c74 100644 --- a/src/components/ToastrMessage/index.jsx +++ b/src/components/ToastrMessage/index.jsx @@ -1,6 +1,8 @@ import React from "react"; +import { toastr } from "react-redux-toastr"; import PT from "prop-types"; import cn from "classnames"; +import { TOAST_DEFAULT_TIMEOUT } from "constants/index.js"; import styles from "./styles.module.scss"; /** @@ -38,3 +40,19 @@ ToastrMessage.propTypes = { }; export default ToastrMessage; + +/** + * Creates a redux toastr message with the specified type and contents. + * + * @param {string|Object} message + * @param {'info'|'success'|'warning'|'error'} type + */ +export function makeToast(message, type = "error") { + const component = + typeof message === "string" ? ( + + ) : ( + {message} + ); + toastr[type]("", { component, options: { timeOut: TOAST_DEFAULT_TIMEOUT } }); +} diff --git a/src/components/ToastrMessage/styles.module.scss b/src/components/ToastrMessage/styles.module.scss index 606e378..b06041b 100644 --- a/src/components/ToastrMessage/styles.module.scss +++ b/src/components/ToastrMessage/styles.module.scss @@ -1,13 +1,19 @@ +@import "styles/mixins"; + .container { display: block; position: relative; border-radius: 8px; - padding: 14px 27px 15px 64px; + padding: 14px 42px 15px; font-size: 16px; line-height: 26px; text-align: center; color: #fff; + @include desktop { + padding: 14px 64px 15px; + } + a { color: #fff; } @@ -20,7 +26,7 @@ .btnClose { position: absolute; top: 22px; - right: 27px; + right: 22px; margin: 0; border: none; padding: 0; @@ -31,6 +37,10 @@ outline: none !important; cursor: pointer; + @include desktop { + right: 27px; + } + &::before, &::after { content: ""; diff --git a/src/constants/index.js b/src/constants/index.js index 51f91e6..198dbbb 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -16,3 +16,5 @@ export const RESOURCE_BOOKING_STATUS = { CLOSED: "closed", CANCELLED: "cancelled", }; + +export const TOAST_DEFAULT_TIMEOUT = 50000; diff --git a/src/constants/workPeriods.js b/src/constants/workPeriods.js index 5de195d..76d1989 100644 --- a/src/constants/workPeriods.js +++ b/src/constants/workPeriods.js @@ -85,3 +85,11 @@ export const API_PAYMENT_STATUS_MAP = (function () { } return obj; })(); + +export const JOB_NAME_LOADING = "Loading..."; +export const JOB_NAME_NONE = ""; +export const JOB_NAME_ERROR = ""; + +export const BILLING_ACCOUNTS_LOADING = "Loading..."; +export const BILLING_ACCOUNTS_NONE = ""; +export const BILLING_ACCOUNTS_ERROR = ""; diff --git a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx index eec7304..146d645 100644 --- a/src/routes/WorkPeriods/components/PeriodDetails/index.jsx +++ b/src/routes/WorkPeriods/components/PeriodDetails/index.jsx @@ -12,7 +12,7 @@ import { hideWorkPeriodDetails, setBillingAccount, setDetailsHidePastPeriods, - setDetailsLockWorkingDays, + // setDetailsLockWorkingDays, } from "store/actions/workPeriods"; import styles from "./styles.module.scss"; import { updateWorkPeriodBillingAccount } from "store/thunks/workPeriods"; @@ -34,14 +34,15 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { periodId, rbId, jobName, - jobNameIsLoading, + jobNameError, billingAccountId, billingAccounts, - billingAccountsIsLoading, + billingAccountsError, + billingAccountsIsDisabled, periodsVisible, periodsIsLoading, hidePastPeriods, - lockWorkingDays, + // lockWorkingDays, } = details; const onHideDetailsBtnClick = useCallback(() => { @@ -55,12 +56,12 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { [dispatch, periodId] ); - const onChangeLockWorkingDays = useCallback( - (lock) => { - dispatch(setDetailsLockWorkingDays(periodId, lock)); - }, - [dispatch, periodId] - ); + // const onChangeLockWorkingDays = useCallback( + // (lock) => { + // dispatch(setDetailsLockWorkingDays(periodId, lock)); + // }, + // [dispatch, periodId] + // ); const onChangeBillingAccount = useCallback( (value) => { @@ -84,16 +85,6 @@ const PeriodDetails = ({ className, details, isDisabled, isFailed }) => { updateBillingAccount(billingAccountId); }, [billingAccountId]); - const isFailedLoadingJobName = !jobNameIsLoading && jobName === "Error"; - const isFailedLoadingBilAccs = - !billingAccountsIsLoading && - billingAccounts.length === 1 && - billingAccounts[0].value === 0; - const isDisabledBilAccs = - !billingAccountsIsLoading && - billingAccounts.length === 1 && - billingAccounts[0].value === -1; - return ( {
Job Name
- {jobNameIsLoading ? "Loading..." : jobName} + {jobName}
-
+ {/*
Lock Working Days
{ onChange={onChangeLockWorkingDays} isOn={lockWorkingDays} /> -
+
*/}
Billing Account
{