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 add distance rate #38035

Merged
merged 22 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c14fbf8
feat: PolicyNewDistanceRatePage
MrMuzyk Mar 7, 2024
b20f519
Merge branch 'feat/policy-distance-rates-page' of github.com:MrMuzyk/…
MrMuzyk Mar 7, 2024
729c746
Merge branch 'feat/policy-distance-rates-page' of github.com:MrMuzyk/…
MrMuzyk Mar 8, 2024
84115b4
Merge branch 'feat/policy-distance-rates-page' of github.com:MrMuzyk/…
MrMuzyk Mar 8, 2024
f7567c3
feat: adding delete
MrMuzyk Mar 8, 2024
c74c9fb
Merge branch 'main' of https://github.com/Expensify/App into feat/pol…
MrMuzyk Mar 11, 2024
d0d8d2c
feat: add
MrMuzyk Mar 11, 2024
d27b9fe
fix: ts error
MrMuzyk Mar 11, 2024
cfa9145
fix: scrap delete from this PR
MrMuzyk Mar 11, 2024
2b1baf7
fix: one line
MrMuzyk Mar 11, 2024
1b53b39
feat: add validation
MrMuzyk Mar 11, 2024
f24b378
Merge branch 'main' of https://github.com/Expensify/App into feat/pol…
MrMuzyk Mar 12, 2024
bf5ba1d
Merge branch 'main' of https://github.com/Expensify/App into feat/pol…
MrMuzyk Mar 13, 2024
f6df548
fix: cr fixes
MrMuzyk Mar 13, 2024
ba3f3b3
fix: error handling
MrMuzyk Mar 13, 2024
ddeabce
Merge branch 'main' of https://github.com/Expensify/App into feat/pol…
MrMuzyk Mar 13, 2024
94638fc
Merge branch 'main' of https://github.com/Expensify/App into feat/pol…
MrMuzyk Mar 13, 2024
0fd5258
fix: cr fixes
MrMuzyk Mar 14, 2024
d04d2a3
fix: last cr fixes
MrMuzyk Mar 15, 2024
9522399
Merge branch 'main' of https://github.com/Expensify/App into feat/pol…
MrMuzyk Mar 15, 2024
78bd350
fix: move validate to util
MrMuzyk Mar 15, 2024
e096ce3
fix: remove extra const
MrMuzyk Mar 15, 2024
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
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ const ONYXKEYS = {
WORKSPACE_DESCRIPTION_FORM_DRAFT: 'workspaceDescriptionFormDraft',
WORKSPACE_RATE_AND_UNIT_FORM: 'workspaceRateAndUnitForm',
WORKSPACE_RATE_AND_UNIT_FORM_DRAFT: 'workspaceRateAndUnitFormDraft',
POLICY_CREATE_DISTANCE_RATE_FORM: 'policyCreateDistanceRateForm',
POLICY_CREATE_DISTANCE_RATE_FORM_DRAFT: 'policyCreateDistanceRateFormDraft',
CLOSE_ACCOUNT_FORM: 'closeAccount',
CLOSE_ACCOUNT_FORM_DRAFT: 'closeAccountDraft',
PROFILE_SETTINGS_FORM: 'profileSettingsForm',
Expand Down Expand Up @@ -453,6 +455,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.PERSONAL_BANK_ACCOUNT]: FormTypes.PersonalBankAccountForm;
[ONYXKEYS.FORMS.WORKSPACE_DESCRIPTION_FORM]: FormTypes.WorkspaceDescriptionForm;
[ONYXKEYS.FORMS.POLICY_TAG_NAME_FORM]: FormTypes.PolicyTagNameForm;
[ONYXKEYS.FORMS.POLICY_CREATE_DISTANCE_RATE_FORM]: FormTypes.PolicyCreateDistanceRateForm;
};

type OnyxFormDraftValuesMapping = {
Expand Down
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,10 @@ const ROUTES = {
route: 'workspace/:policyID/distance-rates',
getRoute: (policyID: string) => `workspace/${policyID}/distance-rates` as const,
},
WORKSPACE_CREATE_DISTANCE_RATE: {
route: 'workspace/:policyID/distance-rates/new',
getRoute: (policyID: string) => `workspace/${policyID}/distance-rates/new` as const,
},

// Referral program promotion
REFERRAL_DETAILS_MODAL: {
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ const SCREENS = {
MEMBER_DETAILS: 'Workspace_Member_Details',
MEMBER_DETAILS_ROLE_SELECTION: 'Workspace_Member_Details_Role_Selection',
DISTANCE_RATES: 'Distance_Rates',
CREATE_DISTANCE_RATE: 'Create_Distance_Rate',
},

EDIT_REQUEST: {
Expand Down
3 changes: 3 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,9 @@ export default {
status: 'Status',
enabled: 'Enabled',
disabled: 'Disabled',
errors: {
createRateGenericFailureMessage: 'An error occurred while creating the distance rate, please try again.',
},
},
editor: {
descriptionInputLabel: 'Description',
Expand Down
3 changes: 3 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2000,6 +2000,9 @@ export default {
status: 'Estado',
enabled: 'Activada',
disabled: 'Desactivada',
errors: {
createRateGenericFailureMessage: 'An error occurred while creating the distance rate, please try again.',
},
},
editor: {
nameInputLabel: 'Nombre',
Expand Down
7 changes: 7 additions & 0 deletions src/libs/API/parameters/CreatePolicyDistanceRateParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type CreatePolicyDistanceRateParams = {
policyID: string;
customUnitID: string;
customUnitRate: string;
};

export default CreatePolicyDistanceRateParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,4 @@ export type {default as AcceptJoinRequestParams} from './AcceptJoinRequest';
export type {default as DeclineJoinRequestParams} from './DeclineJoinRequest';
export type {default as JoinPolicyInviteLinkParams} from './JoinPolicyInviteLink';
export type {default as OpenPolicyDistanceRatesPageParams} from './OpenPolicyDistanceRatesPageParams';
export type {default as CreatePolicyDistanceRateParams} from './CreatePolicyDistanceRateParams';
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ const WRITE_COMMANDS = {
JOIN_POLICY_VIA_INVITE_LINK: 'JoinWorkspaceViaInviteLink',
ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest',
DECLINE_JOIN_REQUEST: 'DeclineJoinRequest',
CREATE_POLICY_DISTANCE_RATE: 'CreatePolicyDistanceRate',
} as const;

type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
Expand Down Expand Up @@ -336,6 +337,7 @@ 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.CREATE_POLICY_DISTANCE_RATE]: Parameters.CreatePolicyDistanceRateParams;
};

const READ_COMMANDS = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.MEMBER_DETAILS]: () => require('../../../pages/workspace/members/WorkspaceMemberDetailsPage').default as React.ComponentType,
[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.CREATE_DISTANCE_RATE]: () => require('../../../pages/workspace/distanceRates/PolicyNewDistanceRatePage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAGS_SETTINGS]: () => require('../../../pages/workspace/tags/WorkspaceTagsSettingsPage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType,
[SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial<Record<CentralPaneName, string[]>> =
[SCREENS.WORKSPACE.WORKFLOWS]: [SCREENS.WORKSPACE.WORKFLOWS_APPROVER, SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET],
[SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT],
[SCREENS.WORKSPACE.CATEGORIES]: [SCREENS.WORKSPACE.CATEGORY_CREATE, SCREENS.WORKSPACE.CATEGORY_SETTINGS, SCREENS.WORKSPACE.CATEGORIES_SETTINGS],
[SCREENS.WORKSPACE.DISTANCE_RATES]: [SCREENS.WORKSPACE.CREATE_DISTANCE_RATE],
};

export default CENTRAL_PANE_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 @@ -297,6 +297,9 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.CATEGORY_CREATE]: {
path: ROUTES.WORKSPACE_CATEGORY_CREATE.route,
},
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: {
path: ROUTES.WORKSPACE_CREATE_DISTANCE_RATE.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 @@ -231,6 +231,9 @@ type SettingsNavigatorParamList = {
accountID: string;
backTo: Routes;
};
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: {
policyID: string;
};
[SCREENS.GET_ASSISTANCE]: {
backTo: Routes;
};
Expand Down
92 changes: 92 additions & 0 deletions src/libs/actions/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {ValueOf} from 'type-fest';
import * as API from '@libs/API';
import type {
AddMembersToWorkspaceParams,
CreatePolicyDistanceRateParams,
CreateWorkspaceFromIOUPaymentParams,
CreateWorkspaceParams,
DeleteMembersFromWorkspaceParams,
Expand Down Expand Up @@ -3237,6 +3238,94 @@ function openPolicyDistanceRatesPage(policyID?: string) {
API.read(READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE, params);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case missed when updating workspace currency distance rates are reset based on old logic which had one distance rate: #30156

function createPolicyDistanceRate(customUnitRate: Rate, customUnitID: string, policyID?: string) {
if (!policyID) {
return;
}

const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[customUnitID]: {
rates: {
[customUnitRate.customUnitRateID ?? '']: {
...customUnitRate,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
},
},
},
},
},
},
];

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

const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
customUnits: {
[customUnitID]: {
rates: {
[customUnitRate.customUnitRateID ?? '']: {
errors: ErrorUtils.getMicroSecondOnyxError('workspace.distanceRates.errors.createRateGenericFailureMessage'),
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
},
},
},
},
},
},
];

const params: CreatePolicyDistanceRateParams = {
policyID,
customUnitID,
customUnitRate: JSON.stringify(customUnitRate),
};

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

function clearCreateDistanceRateError(policyID: string, currentRates: Record<string, Rate>, customUnitID?: string, customUnitRateIDToClear?: string) {
if (!policyID || !customUnitID || !customUnitRateIDToClear) {
return;
}

const updatedRates = {...currentRates};
delete updatedRates[customUnitRateIDToClear];

Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {
customUnits: {
[customUnitID]: {
rates: updatedRates,
},
},
});
}

export {
removeMembers,
updateWorkspaceMembersRole,
Expand Down Expand Up @@ -3302,4 +3391,7 @@ export {
enablePolicyTaxes,
enablePolicyWorkflows,
openPolicyDistanceRatesPage,
generateCustomUnitID,
createPolicyDistanceRate,
clearCreateDistanceRateError,
};
39 changes: 25 additions & 14 deletions src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {ActivityIndicator, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
Expand All @@ -13,31 +13,28 @@ import * as Illustrations from '@components/Icon/Illustrations';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import TableListItem from '@components/SelectionList/TableListItem';
import type {ListItem} from '@components/SelectionList/types';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {CentralPaneNavigatorParamList} from '@navigation/types';
import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper';
import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper';
import * as Policy from '@userActions/Policy';
import ButtonWithDropdownMenu from '@src/components/ButtonWithDropdownMenu';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type * as OnyxTypes from '@src/types/onyx';
import type {CustomUnit, Rate} from '@src/types/onyx/Policy';

type RateForList = {
value: string;
text: string;
keyForList: string;
isSelected: boolean;
rightElement: React.ReactNode;
};
type RateForList = ListItem & {value: string};

type PolicyDistanceRatesPageOnyxProps = {
/** Policy details */
Expand All @@ -54,6 +51,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps)
const [selectedDistanceRates, setSelectedDistanceRates] = useState<Rate[]>([]);
const [isWarningModalVisible, setIsWarningModalVisible] = useState(false);
const dropdownButtonRef = useRef(null);
const policyID = route.params.policyID;

const customUnit: CustomUnit | undefined = useMemo(
() => (policy?.customUnits !== undefined ? policy?.customUnits[Object.keys(policy?.customUnits)[0]] : undefined),
Expand All @@ -62,9 +60,19 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps)
const customUnitRates: Record<string, Rate> = useMemo(() => customUnit?.rates ?? {}, [customUnit]);

function fetchDistanceRates() {
Policy.openPolicyDistanceRatesPage(route.params.policyID);
Policy.openPolicyDistanceRatesPage(policyID);
}

const dismissError = useCallback(
(item: RateForList) => {
if (item.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD) {
return;
}
Policy.clearCreateDistanceRateError(policyID, customUnitRates, customUnit?.customUnitID, item.value);
},
[customUnit?.customUnitID, customUnitRates, policyID],
);

const {isOffline} = useNetwork({onReconnect: fetchDistanceRates});

useEffect(() => {
Expand All @@ -81,6 +89,8 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps)
)}`,
keyForList: value.customUnitRateID ?? '',
isSelected: selectedDistanceRates.find((rate) => rate.customUnitRateID === value.customUnitRateID) !== undefined,
pendingAction: value.pendingAction,
errors: value.errors ?? undefined,
rightElement: (
<View style={styles.flexRow}>
<Text style={[styles.alignSelfCenter, !value.enabled && styles.textSupporting]}>
Expand All @@ -99,15 +109,15 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps)
);

const addRate = () => {
// Navigation.navigate(ROUTES.WORKSPACE_CREATE_DISTANCE_RATE.getRoute(route.params.policyID));
Navigation.navigate(ROUTES.WORKSPACE_CREATE_DISTANCE_RATE.getRoute(policyID));
};

const openSettings = () => {
// Navigation.navigate(ROUTES.WORKSPACE_DISTANCE_RATES_SETTINGS.getRoute(route.params.policyID));
// Navigation.navigate(ROUTES.WORKSPACE_DISTANCE_RATES_SETTINGS.getRoute(policyID));
};

const editRate = () => {
// Navigation.navigate(ROUTES.WORKSPACE_EDIT_DISTANCE_RATE.getRoute(route.params.policyID, rateID));
// Navigation.navigate(ROUTES.WORKSPACE_EDIT_DISTANCE_RATE.getRoute(policyID, rateID));
};

const disableRates = () => {
Expand Down Expand Up @@ -230,8 +240,8 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps)
);

return (
<AdminPolicyAccessOrNotFoundWrapper policyID={route.params.policyID}>
<PaidPolicyAccessOrNotFoundWrapper policyID={route.params.policyID}>
<AdminPolicyAccessOrNotFoundWrapper policyID={policyID}>
<PaidPolicyAccessOrNotFoundWrapper policyID={policyID}>
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
style={[styles.defaultModalContainer]}
Expand Down Expand Up @@ -264,6 +274,7 @@ function PolicyDistanceRatesPage({policy, route}: PolicyDistanceRatesPageProps)
onCheckboxPress={toggleRate}
sections={[{data: distanceRatesList, indexOffset: 0, isDisabled: false}]}
onSelectRow={editRate}
onDismissError={dismissError}
showScrollIndicator
customListHeader={getCustomListHeader()}
listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]}
Expand Down
Loading
Loading