Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(workspace-settings): currency selector push to page #27861

Merged
2 changes: 2 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export default {
WORKSPACE_INVITE: 'workspace/:policyID/invite',
WORKSPACE_INVITE_MESSAGE: 'workspace/:policyID/invite-message',
WORKSPACE_SETTINGS: 'workspace/:policyID/settings',
WORKSPACE_SETTINGS_CURRENCY: 'workspace/:policyID/settings/currency',
WORKSPACE_CARD: 'workspace/:policyID/card',
WORKSPACE_REIMBURSE: 'workspace/:policyID/reimburse',
WORKSPACE_RATE_AND_UNIT: 'workspace/:policyID/rateandunit',
Expand All @@ -202,6 +203,7 @@ export default {
getWorkspaceInviteRoute: (policyID: string) => `workspace/${policyID}/invite`,
getWorkspaceInviteMessageRoute: (policyID: string) => `workspace/${policyID}/invite-message`,
getWorkspaceSettingsRoute: (policyID: string) => `workspace/${policyID}/settings`,
getWorkspaceSettingsCurrencyRoute: (policyID: string) => `workspace/${policyID}/settings/currency`,
getWorkspaceCardRoute: (policyID: string) => `workspace/${policyID}/card`,
getWorkspaceReimburseRoute: (policyID: string) => `workspace/${policyID}/reimburse`,
getWorkspaceRateAndUnitRoute: (policyID: string) => `workspace/${policyID}/rateandunit`,
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.js
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([
},
name: 'Workspace_Settings',
},
{
getComponent: () => {
const WorkspaceSettingsCurrencyPage = require('../../../pages/workspace/WorkspaceSettingsCurrencyPage').default;
return WorkspaceSettingsCurrencyPage;
},
name: 'Workspace_Settings_Currency',
},
{
getComponent: () => {
const WorkspaceCardPage = require('../../../pages/workspace/card/WorkspaceCardPage').default;
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/linkingConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ export default {
Workspace_Settings: {
path: ROUTES.WORKSPACE_SETTINGS,
},
Workspace_Settings_Currency: {
path: ROUTES.WORKSPACE_SETTINGS_CURRENCY,
},
Workspace_Card: {
path: ROUTES.WORKSPACE_CARD,
},
Expand Down
106 changes: 106 additions & 0 deletions src/pages/workspace/WorkspaceSettingsCurrencyPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, {useState, useMemo, useCallback} from 'react';
import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import useLocalize from '../../hooks/useLocalize';
import ScreenWrapper from '../../components/ScreenWrapper';
import HeaderWithBackButton from '../../components/HeaderWithBackButton';
import SelectionList from '../../components/SelectionList';
import Navigation from '../../libs/Navigation/Navigation';
import ROUTES from '../../ROUTES';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
import withPolicy, {policyDefaultProps, policyPropTypes} from './withPolicy';
import * as Policy from '../../libs/actions/Policy';

const propTypes = {
/** Constant, list of available currencies */
currencyList: PropTypes.objectOf(
PropTypes.shape({
/** Symbol of the currency */
symbol: PropTypes.string,
}),
),
...policyPropTypes,
};

const defaultProps = {
currencyList: {},
...policyDefaultProps,
};

function WorkspaceSettingsCurrencyPage({currencyList, policy}) {
const {translate} = useLocalize();
const [searchText, setSearchText] = useState('');

const getDisplayText = useCallback((currencyCode, currencySymbol) => `${currencyCode} - ${currencySymbol}`, []);

const {sections, initiallyFocusedOptionKey} = useMemo(() => {
const trimmedText = searchText.trim().toLowerCase();
const currencyListKeys = _.keys(currencyList);

const filteredItems = _.filter(currencyListKeys, (currencyCode) => {
const currency = currencyList[currencyCode];
return getDisplayText(currencyCode, currency.symbol).toLowerCase().includes(trimmedText);
});

let selectedCurrencyCode;

const currencyItems = _.map(filteredItems, (currencyCode) => {
const currency = currencyList[currencyCode];
const isSelected = policy.outputCurrency === currencyCode;

if (isSelected) {
selectedCurrencyCode = currencyCode;
}

return {
text: getDisplayText(currencyCode, currency.symbol),
keyForList: currencyCode,
isSelected,
};
});

return {
sections: [{data: currencyItems, indexOffset: 0}],
initiallyFocusedOptionKey: selectedCurrencyCode,
};
}, [getDisplayText, currencyList, policy.outputCurrency, searchText]);

const headerMessage = Boolean(searchText.trim()) && !sections[0].data.length ? translate('common.noResultsFound') : '';

const onSelectCurrency = (item) => {
Policy.updateGeneralSettings(policy.id, policy.name, item.keyForList);
Navigation.goBack(ROUTES.getWorkspaceSettingsRoute(policy.id));
};

return (
<ScreenWrapper includeSafeAreaPaddingBottom={false}>
<HeaderWithBackButton
title={translate('workspace.editor.currencyInputLabel')}
onBackButtonPress={() => Navigation.goBack(ROUTES.getWorkspaceSettingsRoute(policy.id))}
/>

<SelectionList
sections={sections}
textInputLabel={translate('workspace.editor.currencyInputLabel')}
textInputValue={searchText}
onChangeText={setSearchText}
onSelectRow={onSelectCurrency}
headerMessage={headerMessage}
initiallyFocusedOptionKey={initiallyFocusedOptionKey}
showScrollIndicator
/>
</ScreenWrapper>
);
}

WorkspaceSettingsCurrencyPage.propTypes = propTypes;
WorkspaceSettingsCurrencyPage.defaultProps = defaultProps;

export default compose(
withPolicy,
withOnyx({
currencyList: {key: ONYXKEYS.CURRENCY_LIST},
}),
)(WorkspaceSettingsCurrencyPage);
44 changes: 20 additions & 24 deletions src/pages/workspace/WorkspaceSettingsPage.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, {useCallback, useMemo} from 'react';
import React, {useCallback} from 'react';
import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import _ from 'underscore';
import lodashGet from 'lodash/get';
import ONYXKEYS from '../../ONYXKEYS';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
Expand All @@ -12,7 +11,6 @@ import * as Policy from '../../libs/actions/Policy';
import * as Expensicons from '../../components/Icon/Expensicons';
import AvatarWithImagePicker from '../../components/AvatarWithImagePicker';
import CONST from '../../CONST';
import Picker from '../../components/Picker';
import TextInput from '../../components/TextInput';
import WorkspacePageWithSections from './WorkspacePageWithSections';
import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy';
Expand All @@ -25,12 +23,14 @@ import Avatar from '../../components/Avatar';
import Navigation from '../../libs/Navigation/Navigation';
import ROUTES from '../../ROUTES';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
import MenuItemWithTopDescription from '../../components/MenuItemWithTopDescription';
import Text from '../../components/Text';

const propTypes = {
// The currency list constant object from Onyx
/** Constant, list of available currencies */
currencyList: PropTypes.objectOf(
PropTypes.shape({
// Symbol for the currency
/** Symbol of the currency */
symbol: PropTypes.string,
}),
),
Expand All @@ -45,25 +45,19 @@ const defaultProps = {
};

function WorkspaceSettingsPage(props) {
const currencyItems = useMemo(() => {
const currencyListKeys = _.keys(props.currencyList);
return _.map(currencyListKeys, (currencyCode) => ({
value: currencyCode,
label: `${currencyCode} - ${props.currencyList[currencyCode].symbol}`,
}));
}, [props.currencyList]);
const formattedCurrency = `${props.policy.outputCurrency} - ${props.currencyList[props.policy.outputCurrency].symbol}`;

const submit = useCallback(
(values) => {
if (props.policy.isPolicyUpdating) {
return;
}
const outputCurrency = values.currency;
Policy.updateGeneralSettings(props.policy.id, values.name.trim(), outputCurrency);

Policy.updateGeneralSettings(props.policy.id, values.name.trim(), props.policy.outputCurrency);
Keyboard.dismiss();
Navigation.goBack(ROUTES.getWorkspaceInitialRoute(props.policy.id));
},
[props.policy.id, props.policy.isPolicyUpdating],
[props.policy.id, props.policy.isPolicyUpdating, props.policy.outputCurrency],
);

const validate = useCallback((values) => {
Expand Down Expand Up @@ -93,7 +87,7 @@ function WorkspaceSettingsPage(props) {
<Form
formID={ONYXKEYS.FORMS.WORKSPACE_SETTINGS_FORM}
submitButtonText={props.translate('workspace.editor.save')}
style={[styles.mh5, styles.flexGrow1]}
style={[styles.flexGrow1]}
scrollContextEnabled
validate={validate}
onSubmit={submit}
Expand Down Expand Up @@ -136,20 +130,22 @@ function WorkspaceSettingsPage(props) {
inputID="name"
label={props.translate('workspace.editor.nameInputLabel')}
accessibilityLabel={props.translate('workspace.editor.nameInputLabel')}
containerStyles={[styles.mt4]}
containerStyles={[styles.mt4, styles.mh5]}
defaultValue={props.policy.name}
maxLength={CONST.WORKSPACE_NAME_CHARACTER_LIMIT}
spellCheck={false}
/>
<View style={[styles.mt4]}>
<Picker
inputID="currency"
label={props.translate('workspace.editor.currencyInputLabel')}
items={currencyItems}
isDisabled={hasVBA}
defaultValue={props.policy.outputCurrency}
hintText={hasVBA ? props.translate('workspace.editor.currencyInputDisabledText') : props.translate('workspace.editor.currencyInputHelpText')}
<MenuItemWithTopDescription
title={formattedCurrency}
description={props.translate('workspace.editor.currencyInputLabel')}
shouldShowRightIcon
disabled={hasVBA}
onPress={() => Navigation.navigate(ROUTES.getWorkspaceSettingsCurrencyRoute(props.policy.id))}
/>
<Text style={[styles.textLabel, styles.colorMuted, styles.mt2, styles.mh5]}>
{hasVBA ? props.translate('workspace.editor.currencyInputDisabledText') : props.translate('workspace.editor.currencyInputHelpText')}
</Text>
</View>
</OfflineWithFeedback>
</Form>
Expand Down