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: policy distance rates settings #38060

Merged
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1456,6 +1456,10 @@ const CONST = {
DISABLE: 'disable',
ENABLE: 'enable',
},
UNITS: {
MI: 'Miles',
KM: 'Kilometers',
},
},

CUSTOM_UNITS: {
Expand Down
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/distance-rates/new',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/distance-rates/new` as const,
},
WORKSPACE_DISTANCE_RATES_SETTINGS: {
route: 'settings/workspace/:policyID/distance-rates/settings',
getRoute: (policyID: string) => `settings/workspace/${policyID}/distance-rates/settings` as const,
},
// Referral program promotion
REFERRAL_DETAILS_MODAL: {
route: 'referral/:contentType',
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ const SCREENS = {
MEMBER_DETAILS_ROLE_SELECTION: 'Workspace_Member_Details_Role_Selection',
DISTANCE_RATES: 'Distance_Rates',
CREATE_DISTANCE_RATE: 'Create_Distance_Rate',
DISTANCE_RATES_SETTINGS: 'Distance_Rates_Settings',
},

EDIT_REQUEST: {
Expand Down
6 changes: 6 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,12 @@ export default {
status: 'Status',
enabled: 'Enabled',
disabled: 'Disabled',
unit: 'Unit',
defaultCategory: 'Default category',
units: {
MI: 'Miles',
KM: 'Kilometers',
luacmartins marked this conversation as resolved.
Show resolved Hide resolved
},
},
editor: {
descriptionInputLabel: 'Description',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,12 @@ export default {
status: 'Estado',
enabled: 'Activada',
disabled: 'Desactivada',
unit: 'Unidad',
defaultCategory: 'Categoría predeterminada',
units: {
MI: 'Millas',
KM: 'Kilómetros',
},
},
editor: {
nameInputLabel: 'Nombre',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type SetPolicyDistanceRatesDefaultCategoryParams = {
policyID: string;
customUnit: string;
};

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

export default SetPolicyDistanceRatesUnitParams;
2 changes: 2 additions & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,6 @@ export type {default as OpenPolicyTaxesPageParams} from './OpenPolicyTaxesPagePa
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 SetPolicyDistanceRatesUnitParams} from './SetPolicyDistanceRatesUnitParams';
export type {default as SetPolicyDistanceRatesDefaultCategoryParams} from './SetPolicyDistanceRatesDefaultCategoryParams';
export type {default as CreatePolicyTagsParams} from './CreatePolicyTagsParams';
4 changes: 4 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ const WRITE_COMMANDS = {
ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest',
DECLINE_JOIN_REQUEST: 'DeclineJoinRequest',
CREATE_POLICY_DISTANCE_RATE: 'CreatePolicyDistanceRate',
SET_POLICY_DISTANCE_RATES_UNIT: 'SetPolicyDistanceRatesUnit',
SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY: 'SetPolicyDistanceRatesDefaultCategory',
} as const;

type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
Expand Down Expand Up @@ -352,6 +354,8 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.ACCEPT_JOIN_REQUEST]: Parameters.AcceptJoinRequestParams;
[WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams;
[WRITE_COMMANDS.CREATE_POLICY_DISTANCE_RATE]: Parameters.CreatePolicyDistanceRateParams;
[WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_UNIT]: Parameters.SetPolicyDistanceRatesUnitParams;
[WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY]: Parameters.SetPolicyDistanceRatesDefaultCategoryParams;
};

const READ_COMMANDS = {
Expand Down
3 changes: 2 additions & 1 deletion src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.MEMBER_DETAILS_ROLE_SELECTION]: () => require('../../../pages/workspace/members/WorkspaceMemberDetailsRoleSelectionPage').default as React.ComponentType,
[SCREENS.WORKSPACE.CATEGORY_CREATE]: () => require('../../../pages/workspace/categories/CreateCategoryPage').default as React.ComponentType,
[SCREENS.WORKSPACE.CATEGORY_EDIT]: () => require('../../../pages/workspace/categories/EditCategoryPage').default as React.ComponentType,
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: () => require('@pages/workspace/distanceRates/CreateDistanceRatePage').default as React.ComponentType,
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: () => require('../../../pages/workspace/distanceRates/CreateDistanceRatePage').default as React.ComponentType,
[SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: () => require('../../../pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAGS_SETTINGS]: () => require('../../../pages/workspace/tags/WorkspaceTagsSettingsPage').default as React.ComponentType,
[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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
],
[SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE, SCREENS.WORKSPACE.TAG_SETTINGS],
[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],
[SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS],
};

export default FULL_SCREEN_TO_RHP_MAPPING;
3 changes: 3 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: {
path: ROUTES.WORKSPACE_CREATE_DISTANCE_RATE.route,
},
[SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: {
path: ROUTES.WORKSPACE_DISTANCE_RATES_SETTINGS.route,
},
[SCREENS.WORKSPACE.TAGS_SETTINGS]: {
path: ROUTES.WORKSPACE_TAGS_SETTINGS.route,
},
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ type SettingsNavigatorParamList = {
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: {
policyID: string;
};
[SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: {
policyID: string;
};
[SCREENS.GET_ASSISTANCE]: {
backTo: Routes;
};
Expand Down
112 changes: 112 additions & 0 deletions src/libs/actions/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import type {
OpenWorkspaceMembersPageParams,
OpenWorkspaceParams,
OpenWorkspaceReimburseViewParams,
SetPolicyDistanceRatesDefaultCategoryParams,
SetPolicyDistanceRatesUnitParams,
SetWorkspaceApprovalModeParams,
SetWorkspaceAutoReportingFrequencyParams,
SetWorkspaceAutoReportingMonthlyOffsetParams,
Expand Down Expand Up @@ -3829,6 +3831,114 @@ function clearCreateDistanceRateItemAndError(policyID: string, customUnitID: str
});
}

function setPolicyDistanceRatesUnit(policyID: string, currentCustomUnit: CustomUnit, newCustomUnit: CustomUnit) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[newCustomUnit.customUnitID]: {
...newCustomUnit,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
},
},
];

const successData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[newCustomUnit.customUnitID]: {
pendingAction: null,
},
},
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[currentCustomUnit.customUnitID]: {
...currentCustomUnit,
errors: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'),
pendingAction: null,
},
},
},
},
];

const params: SetPolicyDistanceRatesUnitParams = {
policyID,
customUnit: JSON.stringify(newCustomUnit),
};

API.write(WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_UNIT, params, {optimisticData, successData, failureData});
}

function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUnit: CustomUnit, newCustomUnit: CustomUnit) {
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[newCustomUnit.customUnitID]: {
...newCustomUnit,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
},
},
];

const successData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[newCustomUnit.customUnitID]: {
pendingAction: null,
},
},
},
},
];

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[currentCustomUnit.customUnitID]: {
...currentCustomUnit,
errors: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'),
pendingAction: null,
},
},
},
},
];

const params: SetPolicyDistanceRatesDefaultCategoryParams = {
policyID,
customUnit: JSON.stringify(newCustomUnit),
};

API.write(WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY, params, {optimisticData, successData, failureData});
}

export {
removeMembers,
updateWorkspaceMembersRole,
Expand Down Expand Up @@ -3904,6 +4014,8 @@ export {
generateCustomUnitID,
createPolicyDistanceRate,
clearCreateDistanceRateItemAndError,
setPolicyDistanceRatesUnit,
setPolicyDistanceRatesDefaultCategory,
createPolicyTag,
clearPolicyTagErrors,
clearWorkspaceReimbursementErrors,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, {useMemo} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import Modal from '@components/Modal';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import type * as OnyxTypes from '@src/types/onyx';
import type CategoryItemType from './types';

type CategorySelectorModalProps = {
/** Collection of categories attached to a policy */
policyCategories: OnyxEntry<OnyxTypes.PolicyCategories>;

/** Whether the modal is visible */
isVisible: boolean;

/** Selected category */
currentCategory: string;

/** Function to call when the user selects a category */
onCategorySelected: (value: CategoryItemType) => void;

/** Function to call when the user closes the category selector modal */
onClose: () => void;

/** Label to display on field */
label: string;
};

function CategorySelectorModal({policyCategories, isVisible, currentCategory, onCategorySelected, onClose, label}: CategorySelectorModalProps) {
luacmartins marked this conversation as resolved.
Show resolved Hide resolved
const styles = useThemeStyles();

const categories = useMemo(
() =>
Object.values(policyCategories ?? {}).map((value) => ({
value: value.name,
text: value.name,
keyForList: value.name,
isSelected: value.name === currentCategory,
})),
[currentCategory, policyCategories],
);

return (
<Modal
type={CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED}
isVisible={isVisible}
onClose={onClose}
onModalHide={onClose}
hideModalContentWhileAnimating
useNativeDriver
>
luacmartins marked this conversation as resolved.
Show resolved Hide resolved
<ScreenWrapper
style={[styles.pb0]}
includePaddingTop={false}
includeSafeAreaPaddingBottom={false}
testID={CategorySelectorModal.displayName}
>
<HeaderWithBackButton
title={label}
shouldShowBackButton
onBackButtonPress={onClose}
/>
<SelectionList
ListItem={RadioListItem}
sections={[{data: categories, indexOffset: 0}]}
initiallyFocusedOptionKey={currentCategory}
onSelectRow={onCategorySelected}
shouldStopPropagation
shouldUseDynamicMaxToRenderPerBatch
/>
</ScreenWrapper>
</Modal>
);
}

CategorySelectorModal.displayName = 'CategorySelectorModal';

export default CategorySelectorModal;
Loading
Loading