Skip to content

Commit

Permalink
Merge pull request #38373 from software-mansion-labs/wave8/WorkspaceT…
Browse files Browse the repository at this point in the history
…axesSettings

[Simplified Collect][Taxes] Create WorkspaceTaxesSettingsPage and subpages
  • Loading branch information
luacmartins authored Mar 18, 2024
2 parents 59b3919 + c8b2b17 commit 7742bec
Show file tree
Hide file tree
Showing 27 changed files with 617 additions and 44 deletions.
7 changes: 3 additions & 4 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ const CONST = {
INSTALLED: 'installed',
NOT_INSTALLED: 'not-installed',
},
TAX_RATES: {
NAME_MAX_LENGTH: 50,
},
PLATFORM: {
IOS: 'ios',
ANDROID: 'android',
Expand Down Expand Up @@ -4065,10 +4068,6 @@ const CONST = {
SESSION_STORAGE_KEYS: {
INITIAL_URL: 'INITIAL_URL',
},

TAX_RATES: {
NAME_MAX_LENGTH: 50,
},
} as const;

type Country = keyof typeof CONST.ALL_COUNTRIES;
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ const ONYXKEYS = {
WORKSPACE_DESCRIPTION_FORM_DRAFT: 'workspaceDescriptionFormDraft',
WORKSPACE_RATE_AND_UNIT_FORM: 'workspaceRateAndUnitForm',
WORKSPACE_RATE_AND_UNIT_FORM_DRAFT: 'workspaceRateAndUnitFormDraft',
WORKSPACE_TAX_CUSTOM_NAME: 'workspaceTaxCustomName',
WORKSPACE_TAX_CUSTOM_NAME_DRAFT: 'workspaceTaxCustomNameDraft',
POLICY_CREATE_DISTANCE_RATE_FORM: 'policyCreateDistanceRateForm',
POLICY_CREATE_DISTANCE_RATE_FORM_DRAFT: 'policyCreateDistanceRateFormDraft',
CLOSE_ACCOUNT_FORM: 'closeAccount',
Expand Down Expand Up @@ -424,6 +426,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM]: FormTypes.WorkspaceCategoryForm;
[ONYXKEYS.FORMS.WORKSPACE_TAG_CREATE_FORM]: FormTypes.WorkspaceTagCreateForm;
[ONYXKEYS.FORMS.WORKSPACE_RATE_AND_UNIT_FORM]: FormTypes.WorkspaceRateAndUnitForm;
[ONYXKEYS.FORMS.WORKSPACE_TAX_CUSTOM_NAME]: FormTypes.WorkspaceTaxCustomName;
[ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM]: FormTypes.CloseAccountForm;
[ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM]: FormTypes.ProfileSettingsForm;
[ONYXKEYS.FORMS.DISPLAY_NAME_FORM]: FormTypes.DisplayNameForm;
Expand Down
16 changes: 16 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,22 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/taxes',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes` as const,
},
WORKSPACE_TAXES_SETTINGS: {
route: 'settings/workspaces/:policyID/taxes/settings',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes/settings` as const,
},
WORKSPACE_TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT: {
route: 'settings/workspaces/:policyID/taxes/settings/workspace-currency',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes/settings/workspace-currency` as const,
},
WORKSPACE_TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT: {
route: 'settings/workspaces/:policyID/taxes/settings/foreign-currency',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes/settings/foreign-currency` as const,
},
WORKSPACE_TAXES_SETTINGS_CUSTOM_TAX_NAME: {
route: 'settings/workspaces/:policyID/taxes/settings/tax-name',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes/settings/tax-name` as const,
},
WORKSPACE_MEMBER_DETAILS: {
route: 'settings/workspaces/:policyID/members/:accountID',
getRoute: (policyID: string, accountID: number, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/members/${accountID}`, backTo),
Expand Down
4 changes: 4 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ const SCREENS = {
TAGS_SETTINGS: 'Tags_Settings',
TAGS_EDIT: 'Tags_Edit',
TAXES: 'Workspace_Taxes',
TAXES_SETTINGS: 'Workspace_Taxes_Settings',
TAXES_SETTINGS_CUSTOM_TAX_NAME: 'Workspace_Taxes_Settings_CustomTaxName',
TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT: 'Workspace_Taxes_Settings_WorkspaceCurrency',
TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT: 'Workspace_Taxes_Settings_ForeignCurrency',
TAX_CREATE: 'Workspace_Tax_Create',
TAG_CREATE: 'Tag_Create',
TAG_SETTINGS: 'Tag_Settings',
Expand Down
49 changes: 22 additions & 27 deletions src/components/TaxPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React, {useMemo, useState} from 'react';
import React, {useCallback, useMemo, useState} from 'react';
import type {EdgeInsets} from 'react-native-safe-area-context';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import type {TaxRatesWithDefault} from '@src/types/onyx';
import OptionsSelector from './OptionsSelector';
import SelectionList from './SelectionList';
import RadioListItem from './SelectionList/RadioListItem';
import type {ListItem} from './SelectionList/types';

type TaxPickerProps = {
/** Collection of tax rates attached to a policy */
taxRates: TaxRatesWithDefault;
taxRates?: TaxRatesWithDefault;

/** The selected tax rate of an expense */
selectedTaxRate?: string;
Expand All @@ -23,60 +24,54 @@ type TaxPickerProps = {
insets?: EdgeInsets;

/** Callback to fire when a tax is pressed */
onSubmit: () => void;
onSubmit: (tax: ListItem) => void;
};

function TaxPicker({selectedTaxRate = '', taxRates, insets, onSubmit}: TaxPickerProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const [searchValue, setSearchValue] = useState('');

const taxRatesCount = TransactionUtils.getEnabledTaxRateCount(taxRates.taxes);
const taxRatesCount = TransactionUtils.getEnabledTaxRateCount(taxRates?.taxes ?? {});
const isTaxRatesCountBelowThreshold = taxRatesCount < CONST.TAX_RATES_LIST_THRESHOLD;

const shouldShowTextInput = !isTaxRatesCountBelowThreshold;

const getTaxName = useCallback((key: string) => taxRates?.taxes[key].name, [taxRates?.taxes]);

const selectedOptions = useMemo(() => {
if (!selectedTaxRate) {
return [];
}

return [
{
name: selectedTaxRate,
name: getTaxName(selectedTaxRate),
enabled: true,
accountID: null,
},
];
}, [selectedTaxRate]);
}, [selectedTaxRate, getTaxName]);

const sections = useMemo(() => {
const {taxRatesOptions} = OptionsListUtils.getFilteredOptions({}, {}, [], searchValue, selectedOptions, [], false, false, false, {}, [], false, {}, [], false, false, true, taxRates);
const taxRatesOptions = OptionsListUtils.getTaxRatesSection(taxRates, selectedOptions as OptionsListUtils.Category[], searchValue, selectedTaxRate);
return taxRatesOptions;
}, [taxRates, searchValue, selectedOptions]);
}, [taxRates, searchValue, selectedOptions, selectedTaxRate]);

const selectedOptionKey = sections?.[0]?.data?.find((taxRate) => taxRate.searchText === selectedTaxRate)?.keyForList;
const headerMessage = OptionsListUtils.getHeaderMessageForNonUserList(sections[0].data.length > 0, searchValue);

return (
<OptionsSelector
// @ts-expect-error TODO: Remove this once OptionsSelector (https://github.com/Expensify/App/issues/25125) is migrated to TypeScript.
contentContainerStyles={[{paddingBottom: StyleUtils.getSafeAreaMargins(insets).marginBottom}]}
optionHoveredStyle={styles.hoveredComponentBG}
sectionHeaderStyle={styles.mt5}
<SelectionList
ListItem={RadioListItem}
onSelectRow={onSubmit}
initiallyFocusedOptionKey={selectedTaxRate}
sections={sections}
selectedOptions={selectedOptions}
value={searchValue}
// Focus the first option when searching
focusedIndex={0}
initiallyFocusedOptionKey={selectedOptionKey}
textInputLabel={translate('common.search')}
boldStyle
highlightSelectedOptions
containerStyle={{paddingBottom: StyleUtils.getSafeAreaMargins(insets).marginBottom}}
textInputLabel={shouldShowTextInput ? translate('common.search') : undefined}
isRowMultilineSupported
shouldShowTextInput={shouldShowTextInput}
headerMessage={headerMessage}
textInputValue={searchValue}
onChangeText={setSearchValue}
onSelectRow={onSubmit}
/>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,7 @@ export default {
addRate: 'Add rate',
workspaceDefault: 'Workspace currency default',
foreignDefault: 'Foreign currency default',
customTaxName: 'Custom tax name',
value: 'Value',
errors: {
taxRateAlreadyExists: 'This tax name is already in use.',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,7 @@ export default {
addRate: 'Añadir tasa',
workspaceDefault: 'Moneda por defecto del espacio de trabajo',
foreignDefault: 'Moneda extranjera por defecto',
customTaxName: 'Nombre del impuesto',
value: 'Valor',
errors: {
taxRateAlreadyExists: 'Ya existe un impuesto con este nombre',
Expand Down
6 changes: 6 additions & 0 deletions src/libs/API/parameters/SetPolicyCurrencyDefaultParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type SetPolicyCurrencyDefaultParams = {
policyID: string;
taxCode: string;
};

export default SetPolicyCurrencyDefaultParams;
6 changes: 6 additions & 0 deletions src/libs/API/parameters/SetPolicyCustomTaxNameParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type SetPolicyCustomTaxNameParams = {
policyID: string;
customTaxName: string;
};

export default SetPolicyCustomTaxNameParams;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type SetPolicyForeignCurrencyDefaultParams = {
policyID: string;
taxCode: string;
};

export default SetPolicyForeignCurrencyDefaultParams;
3 changes: 3 additions & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,6 @@ export type {default as EnablePolicyTaxesParams} from './EnablePolicyTaxesParams
export type {default as OpenPolicyMoreFeaturesPageParams} from './OpenPolicyMoreFeaturesPageParams';
export type {default as CreatePolicyDistanceRateParams} from './CreatePolicyDistanceRateParams';
export type {default as CreatePolicyTagsParams} from './CreatePolicyTagsParams';
export type {default as SetPolicyCustomTaxNameParams} from './SetPolicyCustomTaxNameParams';
export type {default as SetPolicyForeignCurrencyDefaultParams} from './SetPolicyForeignCurrencyDefaultParams';
export type {default as SetPolicyCurrencyDefaultParams} from './SetPolicyCurrencyDefaultParams';
6 changes: 6 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ const WRITE_COMMANDS = {
ENABLE_POLICY_TAXES: 'EnablePolicyTaxes',
ENABLE_POLICY_WORKFLOWS: 'EnablePolicyWorkflows',
ENABLE_POLICY_REPORT_FIELDS: 'EnablePolicyReportFields',
SET_POLICY_TAXES_CURRENCY_DEFAULT: 'SetPolicyCurrencyDefaultTax',
SET_POLICY_TAXES_FOREIGN_CURRENCY_DEFAULT: 'SetPolicyForeignCurrencyDefaultTax',
SET_POLICY_CUSTOM_TAX_NAME: 'SetPolicyCustomTaxName',
JOIN_POLICY_VIA_INVITE_LINK: 'JoinWorkspaceViaInviteLink',
ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest',
DECLINE_JOIN_REQUEST: 'DeclineJoinRequest',
Expand Down Expand Up @@ -352,6 +355,9 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.JOIN_POLICY_VIA_INVITE_LINK]: Parameters.JoinPolicyInviteLinkParams;
[WRITE_COMMANDS.ACCEPT_JOIN_REQUEST]: Parameters.AcceptJoinRequestParams;
[WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams;
[WRITE_COMMANDS.SET_POLICY_TAXES_CURRENCY_DEFAULT]: Parameters.SetPolicyCurrencyDefaultParams;
[WRITE_COMMANDS.SET_POLICY_CUSTOM_TAX_NAME]: Parameters.SetPolicyCustomTaxNameParams;
[WRITE_COMMANDS.SET_POLICY_TAXES_FOREIGN_CURRENCY_DEFAULT]: Parameters.SetPolicyForeignCurrencyDefaultParams;
[WRITE_COMMANDS.CREATE_POLICY_TAX]: Parameters.CreatePolicyTaxParams;
[WRITE_COMMANDS.CREATE_POLICY_DISTANCE_RATE]: Parameters.CreatePolicyDistanceRateParams;
};
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.TAG_SETTINGS]: () => require('../../../pages/workspace/tags/TagSettingsPage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAG_CREATE]: () => require('../../../pages/workspace/tags/WorkspaceCreateTagPage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAXES_SETTINGS]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsPage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName').default as React.ComponentType,
[SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsForeignCurrency').default as React.ComponentType,
[SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsWorkspaceCurrency').default as React.ComponentType,
[SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType,
[SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType,
[SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET,
SCREENS.WORKSPACE.WORKFLOWS_PAYER,
],
[SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE, SCREENS.WORKSPACE.TAG_SETTINGS],
[SCREENS.WORKSPACE.TAXES]: [SCREENS.WORKSPACE.TAX_CREATE],
[SCREENS.WORKSPACE.TAXES]: [
SCREENS.WORKSPACE.TAXES_SETTINGS,
SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME,
SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT,
SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT,
],
[SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE, SCREENS.WORKSPACE.TAG_SETTINGS, SCREENS.WORKSPACE.TAX_CREATE],
[SCREENS.WORKSPACE.CATEGORIES]: [SCREENS.WORKSPACE.CATEGORY_CREATE, SCREENS.WORKSPACE.CATEGORY_SETTINGS, SCREENS.WORKSPACE.CATEGORIES_SETTINGS, SCREENS.WORKSPACE.CATEGORY_EDIT],
[SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE],
};
Expand Down
12 changes: 12 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,18 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
tagName: (tagName: string) => decodeURIComponent(tagName),
},
},
[SCREENS.WORKSPACE.TAXES_SETTINGS]: {
path: ROUTES.WORKSPACE_TAXES_SETTINGS.route,
},
[SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME]: {
path: ROUTES.WORKSPACE_TAXES_SETTINGS_CUSTOM_TAX_NAME.route,
},
[SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT]: {
path: ROUTES.WORKSPACE_TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT.route,
},
[SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT]: {
path: ROUTES.WORKSPACE_TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT.route,
},
[SCREENS.REIMBURSEMENT_ACCOUNT]: {
path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route,
exact: true,
Expand Down
12 changes: 12 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ type SettingsNavigatorParamList = {
policyID: string;
tagName: string;
};
[SCREENS.WORKSPACE.TAXES_SETTINGS]: {
policyID: string;
};
[SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME]: {
policyID: string;
};
[SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT]: {
policyID: string;
};
[SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT]: {
policyID: string;
};
[SCREENS.WORKSPACE.MEMBER_DETAILS]: {
policyID: string;
accountID: string;
Expand Down
11 changes: 6 additions & 5 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1202,8 +1202,8 @@ function hasEnabledTags(policyTagList: Array<PolicyTagList[keyof PolicyTagList]>
* @param taxRates - The original tax rates object.
* @returns The transformed tax rates object.g
*/
function transformedTaxRates(taxRates: TaxRatesWithDefault | undefined): Record<string, TaxRate> {
const defaultTaxKey = taxRates?.defaultExternalID;
function transformedTaxRates(taxRates: TaxRatesWithDefault | undefined, defaultKey?: string): Record<string, TaxRate> {
const defaultTaxKey = defaultKey ?? taxRates?.defaultExternalID;
const getModifiedName = (data: TaxRate, code: string) => `${data.name} (${data.value})${defaultTaxKey === code ? ` • ${Localize.translateLocal('common.default')}` : ''}`;
const taxes = Object.fromEntries(Object.entries(taxRates?.taxes ?? {}).map(([code, data]) => [code, {...data, code, modifiedName: getModifiedName(data, code), name: data.name}]));
return taxes;
Expand Down Expand Up @@ -1234,10 +1234,10 @@ function getTaxRatesOptions(taxRates: Array<Partial<TaxRate>>): Option[] {
/**
* Builds the section list for tax rates
*/
function getTaxRatesSection(taxRates: TaxRatesWithDefault | undefined, selectedOptions: Category[], searchInputValue: string): CategorySection[] {
function getTaxRatesSection(taxRates: TaxRatesWithDefault | undefined, selectedOptions: Category[], searchInputValue: string, defaultTaxKey?: string): CategorySection[] {
const policyRatesSections = [];

const taxes = transformedTaxRates(taxRates);
const taxes = transformedTaxRates(taxRates, defaultTaxKey);

const sortedTaxRates = sortTaxRates(taxes);
const enabledTaxRates = sortedTaxRates.filter((taxRate) => !taxRate.isDisabled);
Expand Down Expand Up @@ -2074,6 +2074,7 @@ export {
formatSectionsFromSearchTerm,
transformedTaxRates,
getShareLogOptions,
getTaxRatesSection,
};

export type {MemberForList, CategorySection, GetOptions, PayeePersonalDetails};
export type {MemberForList, CategorySection, GetOptions, PayeePersonalDetails, Category};
Loading

0 comments on commit 7742bec

Please sign in to comment.