From f629f89335c4b7987586f9af946e9ae8d8747793 Mon Sep 17 00:00:00 2001 From: Dan Labrecque Date: Wed, 26 Jul 2023 12:56:14 -0400 Subject: [PATCH] Update cost type and currency APIs for new settings page https://issues.redhat.com/browse/COST-3307 --- src/api/accountSettings.ts | 16 ++++ .../settings/calculations/calculations.tsx | 37 ++++----- .../accountSettings/accountSettingsActions.ts | 78 ++++++++++++++++++- .../accountSettings/accountSettingsReducer.ts | 52 ++++++++++++- .../accountSettingsSelectors.ts | 9 +++ 5 files changed, 169 insertions(+), 23 deletions(-) diff --git a/src/api/accountSettings.ts b/src/api/accountSettings.ts index 965f950ff..9be729d49 100644 --- a/src/api/accountSettings.ts +++ b/src/api/accountSettings.ts @@ -13,6 +13,22 @@ export interface AccountSettings { data: AccountSettingsData; } +export interface CostTypePayload { + cost_type?: string; +} + +export interface CurrencyPayload { + currency?: string; +} + export function fetchAccountSettings() { return axios.get(`account-settings/`); } + +export function updateCostType(payload: CostTypePayload) { + return axios.put(`account-settings/cost-type`, payload); +} + +export function updateCurrency(payload: CurrencyPayload) { + return axios.put(`account-settings/currency`, payload); +} diff --git a/src/routes/settings/calculations/calculations.tsx b/src/routes/settings/calculations/calculations.tsx index f36be01f5..9a0509ee8 100644 --- a/src/routes/settings/calculations/calculations.tsx +++ b/src/routes/settings/calculations/calculations.tsx @@ -6,10 +6,10 @@ import { injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import { CostType } from 'routes/components/costType'; import { Currency } from 'routes/components/currency'; +import { accountSettingsActions, accountSettingsSelectors } from 'store/accountSettings'; import type { FetchStatus } from 'store/common'; import { createMapStateToProps } from 'store/common'; import { rbacActions, rbacSelectors } from 'store/rbac'; -import { settingsActions, settingsSelectors } from 'store/settings'; import { getCostType, getCurrency, setAccountCurrency, setCostType, setCurrency } from 'utils/localStorage'; import type { RouterComponentProps } from 'utils/router'; import { withRouter } from 'utils/router'; @@ -22,12 +22,14 @@ interface SettingsOwnProps { interface SettingsDispatchProps { fetchRbac: typeof rbacActions.fetchRbac; - updateSettings: typeof settingsActions.updateSettings; + updateCostType: typeof accountSettingsActions.updateCostType; + updateCurrency: typeof accountSettingsActions.updateCurrency; } interface SettingsStateProps { canWrite?: boolean; - updateSettingsStatus: FetchStatus; + updateCostTypeStatus: FetchStatus; + updateCurrencyStatus: FetchStatus; } interface SettingsState { @@ -109,32 +111,24 @@ class SettingsBase extends React.Component { }; private handleOnCostTypeSelected = value => { - const { updateSettings } = this.props; + const { updateCostType } = this.props; this.setState({ currentCostType: value }, () => { setCostType(value); - updateSettings({ - api: { - settings: { - cost_type: value, - }, - }, + updateCostType({ + cost_type: value, }); }); }; private handleOnCurrencySelected = value => { - const { updateSettings } = this.props; + const { updateCurrency } = this.props; this.setState({ currentCurrency: value }, () => { setCurrency(value); setAccountCurrency(value); // Todo: remove account currency after settings page has been moved - updateSettings({ - api: { - settings: { - currency: value, - }, - }, + updateCurrency({ + currency: value, }); }); }; @@ -156,17 +150,20 @@ class SettingsBase extends React.Component { // eslint-disable-next-line @typescript-eslint/no-unused-vars const mapStateToProps = createMapStateToProps(state => { - const updateSettingsStatus = settingsSelectors.selectSettingsUpdateStatus(state); + const updateCostTypeStatus = accountSettingsSelectors.selectUpdateCostTypeStatus(state); + const updateCurrencyStatus = accountSettingsSelectors.selectUpdateCurrencyStatus(state); return { canWrite: rbacSelectors.isSettingsWritePermission(state), - updateSettingsStatus, + updateCostTypeStatus, + updateCurrencyStatus, }; }); const mapDispatchToProps: SettingsDispatchProps = { fetchRbac: rbacActions.fetchRbac, - updateSettings: settingsActions.updateSettings, + updateCostType: accountSettingsActions.updateCostType, + updateCurrency: accountSettingsActions.updateCurrency, }; const Calculations = injectIntl(withRouter(connect(mapStateToProps, mapDispatchToProps)(SettingsBase))); diff --git a/src/store/accountSettings/accountSettingsActions.ts b/src/store/accountSettings/accountSettingsActions.ts index 81a69a795..94a35520b 100644 --- a/src/store/accountSettings/accountSettingsActions.ts +++ b/src/store/accountSettings/accountSettingsActions.ts @@ -1,6 +1,12 @@ -import type { AccountSettings } from 'api/accountSettings'; +import { AlertVariant } from '@patternfly/react-core'; +import { addNotification } from '@redhat-cloud-services/frontend-components-notifications/redux'; +import type { AccountSettings, CostTypePayload, CurrencyPayload } from 'api/accountSettings'; import { fetchAccountSettings as apiGetAccountSettings } from 'api/accountSettings'; +import { updateCostType as apiUpdateCostType, updateCurrency as apiUpdateCurrency } from 'api/accountSettings'; import type { AxiosError } from 'axios'; +import type { AxiosResponse } from 'axios'; +import { intl } from 'components/i18n'; +import messages from 'locales/messages'; import type { ThunkAction } from 'store/common'; import { FetchStatus } from 'store/common'; import { createAction } from 'typesafe-actions'; @@ -21,6 +27,16 @@ export const fetchAccountSettingsFailure = createAction('accountSettings/fetch/f AxiosError, AccountSettingsActionMeta >(); +export const updateCostTypeRequest = createAction('accountSettings/update/costType/request')(); +export const updateCostTypeSuccess = createAction('accountSettings/update/costType/success')< + AxiosResponse +>(); +export const updateCostTypeFailure = createAction('accountSettings/update/costType/failure')(); +export const updateCurrencyRequest = createAction('accountSettings/update/currency/request')(); +export const updateCurrencySuccess = createAction('accountSettings/update/currency/success')< + AxiosResponse +>(); +export const updateCurrencyFailure = createAction('accountSettings/update/currency/failure')(); export function fetchAccountSettings(): ThunkAction { return (dispatch, getState) => { @@ -46,3 +62,63 @@ export function fetchAccountSettings(): ThunkAction { }); }; } + +export function updateCostType(payload): ThunkAction { + return dispatch => { + dispatch(updateCostTypeRequest()); + + return apiUpdateCostType(payload) + .then((res: any) => { + dispatch(updateCostTypeSuccess(res)); + dispatch( + addNotification({ + title: intl.formatMessage(messages.settingsSuccessTitle), + description: intl.formatMessage(messages.settingsSuccessDesc), + variant: AlertVariant.success, + dismissable: true, + }) + ); + }) + .catch(err => { + dispatch(updateCostTypeFailure(err)); + dispatch( + addNotification({ + title: intl.formatMessage(messages.settingsErrorTitle), + description: intl.formatMessage(messages.settingsErrorDesc), + variant: AlertVariant.danger, + dismissable: true, + }) + ); + }); + }; +} + +export function updateCurrency(payload): ThunkAction { + return dispatch => { + dispatch(updateCurrencyRequest()); + + return apiUpdateCurrency(payload) + .then((res: any) => { + dispatch(updateCurrencySuccess(res)); + dispatch( + addNotification({ + title: intl.formatMessage(messages.settingsSuccessTitle), + description: intl.formatMessage(messages.settingsSuccessDesc), + variant: AlertVariant.success, + dismissable: true, + }) + ); + }) + .catch(err => { + dispatch(updateCurrencyFailure(err)); + dispatch( + addNotification({ + title: intl.formatMessage(messages.settingsErrorTitle), + description: intl.formatMessage(messages.settingsErrorDesc), + variant: AlertVariant.danger, + dismissable: true, + }) + ); + }); + }; +} diff --git a/src/store/accountSettings/accountSettingsReducer.ts b/src/store/accountSettings/accountSettingsReducer.ts index b7503c0f2..d62062334 100644 --- a/src/store/accountSettings/accountSettingsReducer.ts +++ b/src/store/accountSettings/accountSettingsReducer.ts @@ -17,12 +17,20 @@ import { fetchAccountSettingsFailure, fetchAccountSettingsRequest, fetchAccountSettingsSuccess, + updateCostTypeFailure, + updateCostTypeRequest, + updateCostTypeSuccess, + updateCurrencyFailure, + updateCurrencyRequest, + updateCurrencySuccess, } from './accountSettingsActions'; export type AccountSettingsState = Readonly<{ byId: Map; - errors: Map; - fetchStatus: Map; + error?: AxiosError; + errors?: Map; + fetchStatus?: Map; + status?: FetchStatus; }>; export const defaultState: AccountSettingsState = { @@ -35,6 +43,12 @@ export type AccountSettingsAction = ActionType< | typeof fetchAccountSettingsFailure | typeof fetchAccountSettingsRequest | typeof fetchAccountSettingsSuccess + | typeof updateCostTypeFailure + | typeof updateCostTypeRequest + | typeof updateCostTypeSuccess + | typeof updateCurrencyFailure + | typeof updateCurrencyRequest + | typeof updateCurrencySuccess | typeof resetState >; @@ -72,6 +86,40 @@ export function accountSettingsReducer(state = defaultState, action: AccountSett fetchStatus: new Map(state.fetchStatus).set(action.meta.fetchId, FetchStatus.complete), errors: new Map(state.errors).set(action.meta.fetchId, action.payload), }; + case getType(updateCostTypeRequest): + return { + ...state, + status: FetchStatus.inProgress, + }; + case getType(updateCostTypeSuccess): + return { + ...state, + error: null, + status: FetchStatus.complete, + }; + case getType(updateCostTypeFailure): + return { + ...state, + error: action.payload, + status: FetchStatus.complete, + }; + case getType(updateCurrencyRequest): + return { + ...state, + status: FetchStatus.inProgress, + }; + case getType(updateCurrencySuccess): + return { + ...state, + error: null, + status: FetchStatus.complete, + }; + case getType(updateCurrencyFailure): + return { + ...state, + error: action.payload, + status: FetchStatus.complete, + }; default: return state; } diff --git a/src/store/accountSettings/accountSettingsSelectors.ts b/src/store/accountSettings/accountSettingsSelectors.ts index 4a8665f3d..7a8c9c73d 100644 --- a/src/store/accountSettings/accountSettingsSelectors.ts +++ b/src/store/accountSettings/accountSettingsSelectors.ts @@ -1,4 +1,5 @@ import type { RootState } from 'store/rootReducer'; +import { selectSettingsState } from 'store/settings/settingsSelectors'; import { getFetchId, stateKey } from './accountSettingsCommon'; @@ -13,3 +14,11 @@ export const selectAccountSettingsFetchStatus = (state: RootState) => export const selectAccountSettingsError = (state: RootState) => selectAccountSettingsState(state).errors.get(getFetchId()); + +export const selectUpdateCostTypeError = (state: RootState) => selectSettingsState(state).error; + +export const selectUpdateCostTypeStatus = (state: RootState) => selectSettingsState(state).status; + +export const selectUpdateCurrencyError = (state: RootState) => selectSettingsState(state).error; + +export const selectUpdateCurrencyStatus = (state: RootState) => selectSettingsState(state).status;