Skip to content

Commit 28a0bce

Browse files
authored
Merge pull request Expensify#67207 from gijoe0295/gijoe/65885
do not allow changing card assignee from members page
2 parents 0cd630d + 7cb95e0 commit 28a0bce

14 files changed

Lines changed: 149 additions & 33 deletions

src/CONST/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3186,6 +3186,7 @@ const CONST = {
31863186
},
31873187
LIMIT_VALUE: 21474836,
31883188
STEP_NAMES: ['1', '2', '3', '4', '5', '6'],
3189+
ASSIGNEE_EXCLUDED_STEP_NAMES: ['1', '2', '3', '4', '5'],
31893190
STEP: {
31903191
ASSIGNEE: 'Assignee',
31913192
CARD_TYPE: 'CardType',

src/libs/actions/Card.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ type IssueNewCardFlowData = {
4040

4141
/** ID of the policy */
4242
policyID: string | undefined;
43+
44+
/** Whether the changing assignee is disabled. E.g., The assignee is auto selected from workspace members page */
45+
isChangeAssigneeDisabled?: boolean;
4346
};
4447

4548
function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
@@ -363,12 +366,13 @@ function getCardDefaultName(userName?: string) {
363366
return `${userName}'s Card`;
364367
}
365368

366-
function setIssueNewCardStepAndData({data, isEditing, step, policyID}: IssueNewCardFlowData) {
369+
function setIssueNewCardStepAndData({data, isEditing, step, policyID, isChangeAssigneeDisabled}: IssueNewCardFlowData) {
367370
Onyx.merge(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {
368371
data,
369372
isEditing,
370373
currentStep: step,
371374
errors: null,
375+
isChangeAssigneeDisabled,
372376
});
373377
}
374378

src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import Navigation from '@navigation/Navigation';
2525
import type {SettingsNavigatorParamList} from '@navigation/types';
2626
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
2727
import variables from '@styles/variables';
28-
import {configureExpensifyCardsForPolicy} from '@userActions/Card';
28+
import {configureExpensifyCardsForPolicy, setIssueNewCardStepAndData} from '@userActions/Card';
2929
import CONST from '@src/CONST';
3030
import ONYXKEYS from '@src/ONYXKEYS';
3131
import ROUTES from '@src/ROUTES';
@@ -160,6 +160,7 @@ function WorkspaceExpensifyCardBankAccounts({route}: WorkspaceExpensifyCardBankA
160160
style={[styles.m5, bottomSafeAreaPaddingStyle]}
161161
pressOnEnter
162162
onPress={() => {
163+
setIssueNewCardStepAndData({policyID, isChangeAssigneeDisabled: false});
163164
Navigation.dismissModal();
164165
Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID));
165166
}}

src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
2828
import useSearchResults from '@hooks/useSearchResults';
2929
import useThemeStyles from '@hooks/useThemeStyles';
3030
import useWindowDimensions from '@hooks/useWindowDimensions';
31+
import {setIssueNewCardStepAndData} from '@libs/actions/Card';
3132
import {clearDeletePaymentMethodError} from '@libs/actions/PaymentMethods';
3233
import {filterCardsByPersonalDetails, getCardsByCardholderName, sortCardsByCardholderName} from '@libs/CardUtils';
3334
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
@@ -102,6 +103,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList, fundID}: WorkspaceExp
102103
return;
103104
}
104105
const activeRoute = Navigation.getActiveRoute();
106+
setIssueNewCardStepAndData({policyID, isChangeAssigneeDisabled: false});
105107
Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID, activeRoute));
106108
};
107109

src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ const MINIMUM_MEMBER_TO_SHOW_SEARCH = 8;
2727
type AssigneeStepProps = {
2828
// The policy that the card will be issued under
2929
policy: OnyxEntry<OnyxTypes.Policy>;
30+
31+
/** Array of step names */
32+
stepNames: readonly string[];
33+
34+
/** Start from step index */
35+
startStepIndex: number;
3036
};
3137

32-
function AssigneeStep({policy}: AssigneeStepProps) {
38+
function AssigneeStep({policy, stepNames, startStepIndex}: AssigneeStepProps) {
3339
const {translate, formatPhoneNumber, localeCompare} = useLocalize();
3440
const styles = useThemeStyles();
3541
const {isOffline} = useNetwork();
@@ -139,8 +145,8 @@ function AssigneeStep({policy}: AssigneeStepProps) {
139145
shouldEnableMaxHeight
140146
headerTitle={translate('workspace.card.issueCard')}
141147
handleBackButtonPress={handleBackButtonPress}
142-
startStepIndex={0}
143-
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
148+
startStepIndex={startStepIndex}
149+
stepNames={stepNames}
144150
enableEdgeToEdgeBottomSafeAreaPadding
145151
>
146152
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.whoNeedsCard')}</Text>

src/pages/workspace/expensifyCard/issueNew/CardNameStep.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,19 @@ import INPUT_IDS from '@src/types/form/IssueNewExpensifyCardForm';
2121
type CardNameStepProps = {
2222
/** ID of the policy */
2323
policyID: string | undefined;
24+
25+
/** Array of step names */
26+
stepNames: readonly string[];
27+
28+
/** Start from step index */
29+
startStepIndex: number;
2430
};
2531

26-
function CardNameStep({policyID}: CardNameStepProps) {
32+
function CardNameStep({policyID, stepNames, startStepIndex}: CardNameStepProps) {
2733
const {translate} = useLocalize();
2834
const styles = useThemeStyles();
2935
const {inputCallbackRef} = useAutoFocusInput();
30-
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`);
36+
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});
3137

3238
const isEditing = issueNewCard?.isEditing;
3339
const data = issueNewCard?.data;
@@ -73,8 +79,8 @@ function CardNameStep({policyID}: CardNameStepProps) {
7379
shouldEnableMaxHeight
7480
headerTitle={translate('workspace.card.issueCard')}
7581
handleBackButtonPress={handleBackButtonPress}
76-
startStepIndex={4}
77-
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
82+
startStepIndex={startStepIndex}
83+
stepNames={stepNames}
7884
enableEdgeToEdgeBottomSafeAreaPadding
7985
>
8086
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.giveItName')}</Text>

src/pages/workspace/expensifyCard/issueNew/CardTypeStep.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,27 @@ import Text from '@components/Text';
88
import useLocalize from '@hooks/useLocalize';
99
import useOnyx from '@hooks/useOnyx';
1010
import useThemeStyles from '@hooks/useThemeStyles';
11-
import {setIssueNewCardStepAndData} from '@libs/actions/Card';
11+
import {clearIssueNewCardFlow, setIssueNewCardStepAndData} from '@libs/actions/Card';
12+
import Navigation from '@libs/Navigation/Navigation';
1213
import variables from '@styles/variables';
1314
import CONST from '@src/CONST';
1415
import ONYXKEYS from '@src/ONYXKEYS';
1516

1617
type CardTypeStepProps = {
1718
/** ID of the policy */
1819
policyID: string | undefined;
20+
21+
/** Array of step names */
22+
stepNames: readonly string[];
23+
24+
/** Start from step index */
25+
startStepIndex: number;
1926
};
2027

21-
function CardTypeStep({policyID}: CardTypeStepProps) {
28+
function CardTypeStep({policyID, stepNames, startStepIndex}: CardTypeStepProps) {
2229
const {translate} = useLocalize();
2330
const styles = useThemeStyles();
24-
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`);
31+
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});
2532

2633
const isEditing = issueNewCard?.isEditing;
2734

@@ -41,6 +48,11 @@ function CardTypeStep({policyID}: CardTypeStepProps) {
4148
setIssueNewCardStepAndData({step: CONST.EXPENSIFY_CARD.STEP.CONFIRMATION, isEditing: false, policyID});
4249
return;
4350
}
51+
if (issueNewCard?.isChangeAssigneeDisabled) {
52+
Navigation.goBack();
53+
clearIssueNewCardFlow(policyID);
54+
return;
55+
}
4456
setIssueNewCardStepAndData({step: CONST.EXPENSIFY_CARD.STEP.ASSIGNEE, policyID});
4557
};
4658

@@ -52,8 +64,8 @@ function CardTypeStep({policyID}: CardTypeStepProps) {
5264
offlineIndicatorStyle={styles.mtAuto}
5365
headerTitle={translate('workspace.card.issueCard')}
5466
handleBackButtonPress={handleBackButtonPress}
55-
startStepIndex={1}
56-
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
67+
startStepIndex={startStepIndex}
68+
stepNames={stepNames}
5769
enableEdgeToEdgeBottomSafeAreaPadding
5870
>
5971
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.chooseCardType')}</Text>

src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,15 @@ type ConfirmationStepProps = {
3131

3232
/** Route to navigate to */
3333
backTo?: Route;
34+
35+
/** Array of step names */
36+
stepNames: readonly string[];
37+
38+
/** Start from step index */
39+
startStepIndex: number;
3440
};
3541

36-
function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) {
42+
function ConfirmationStep({policyID, backTo, stepNames, startStepIndex}: ConfirmationStepProps) {
3743
const {translate} = useLocalize();
3844
const styles = useThemeStyles();
3945
const {isOffline} = useNetwork();
@@ -90,8 +96,8 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) {
9096
shouldEnableMaxHeight
9197
headerTitle={translate('workspace.card.issueCard')}
9298
handleBackButtonPress={handleBackButtonPress}
93-
startStepIndex={5}
94-
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
99+
startStepIndex={startStepIndex}
100+
stepNames={stepNames}
95101
enableEdgeToEdgeBottomSafeAreaPadding
96102
>
97103
<ScrollView
@@ -104,7 +110,8 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) {
104110
<MenuItemWithTopDescription
105111
description={translate('workspace.card.issueNewCard.cardholder')}
106112
title={getUserNameByEmail(data?.assigneeEmail ?? '', 'displayName')}
107-
shouldShowRightIcon
113+
shouldShowRightIcon={!issueNewCard?.isChangeAssigneeDisabled}
114+
interactive={!issueNewCard?.isChangeAssigneeDisabled}
108115
onPress={() => editStep(CONST.EXPENSIFY_CARD.STEP.ASSIGNEE)}
109116
/>
110117
<MenuItemWithTopDescription

src/pages/workspace/expensifyCard/issueNew/IssueNewCardPage.tsx

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React, {useEffect} from 'react';
1+
import React, {useEffect, useMemo} from 'react';
2+
import type {OnyxEntry} from 'react-native-onyx';
23
import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper';
34
import ScreenWrapper from '@components/ScreenWrapper';
45
import useInitial from '@hooks/useInitial';
@@ -13,6 +14,7 @@ import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullsc
1314
import CONST from '@src/CONST';
1415
import ONYXKEYS from '@src/ONYXKEYS';
1516
import type SCREENS from '@src/SCREENS';
17+
import type {IssueNewCard, IssueNewCardStep} from '@src/types/onyx/Card';
1618
import AssigneeStep from './AssigneeStep';
1719
import CardNameStep from './CardNameStep';
1820
import CardTypeStep from './CardTypeStep';
@@ -22,6 +24,24 @@ import LimitTypeStep from './LimitTypeStep';
2224

2325
type IssueNewCardPageProps = WithPolicyAndFullscreenLoadingProps & PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW>;
2426

27+
function getStartStepIndex(issueNewCard: OnyxEntry<IssueNewCard>): number {
28+
if (!issueNewCard) {
29+
return 0;
30+
}
31+
32+
const STEP_INDEXES: Record<IssueNewCardStep, number> = {
33+
[CONST.EXPENSIFY_CARD.STEP.ASSIGNEE]: 0,
34+
[CONST.EXPENSIFY_CARD.STEP.CARD_TYPE]: 1,
35+
[CONST.EXPENSIFY_CARD.STEP.LIMIT_TYPE]: 2,
36+
[CONST.EXPENSIFY_CARD.STEP.LIMIT]: 3,
37+
[CONST.EXPENSIFY_CARD.STEP.CARD_NAME]: 4,
38+
[CONST.EXPENSIFY_CARD.STEP.CONFIRMATION]: 5,
39+
};
40+
41+
const stepIndex = STEP_INDEXES[issueNewCard.currentStep];
42+
return issueNewCard.isChangeAssigneeDisabled ? stepIndex - 1 : stepIndex;
43+
}
44+
2545
function IssueNewCardPage({policy, route}: IssueNewCardPageProps) {
2646
const policyID = policy?.id;
2747
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});
@@ -30,6 +50,8 @@ function IssueNewCardPage({policy, route}: IssueNewCardPageProps) {
3050
const firstAssigneeEmail = useInitial(issueNewCard?.data?.assigneeEmail);
3151
const shouldUseBackToParam = !firstAssigneeEmail || firstAssigneeEmail === issueNewCard?.data?.assigneeEmail;
3252
const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate, canBeMissing: true});
53+
const stepNames = issueNewCard?.isChangeAssigneeDisabled ? CONST.EXPENSIFY_CARD.ASSIGNEE_EXCLUDED_STEP_NAMES : CONST.EXPENSIFY_CARD.STEP_NAMES;
54+
const startStepIndex = useMemo(() => getStartStepIndex(issueNewCard), [issueNewCard]);
3355

3456
useEffect(() => {
3557
startIssueNewCardFlow(policyID);
@@ -38,24 +60,62 @@ function IssueNewCardPage({policy, route}: IssueNewCardPageProps) {
3860
const getCurrentStep = () => {
3961
switch (currentStep) {
4062
case CONST.EXPENSIFY_CARD.STEP.ASSIGNEE:
41-
return <AssigneeStep policy={policy} />;
63+
return (
64+
<AssigneeStep
65+
policy={policy}
66+
stepNames={stepNames}
67+
startStepIndex={startStepIndex}
68+
/>
69+
);
4270
case CONST.EXPENSIFY_CARD.STEP.CARD_TYPE:
43-
return <CardTypeStep policyID={policyID} />;
71+
return (
72+
<CardTypeStep
73+
policyID={policyID}
74+
stepNames={stepNames}
75+
startStepIndex={startStepIndex}
76+
/>
77+
);
4478
case CONST.EXPENSIFY_CARD.STEP.LIMIT_TYPE:
45-
return <LimitTypeStep policy={policy} />;
79+
return (
80+
<LimitTypeStep
81+
policy={policy}
82+
stepNames={stepNames}
83+
startStepIndex={startStepIndex}
84+
/>
85+
);
4686
case CONST.EXPENSIFY_CARD.STEP.LIMIT:
47-
return <LimitStep policyID={policyID} />;
87+
return (
88+
<LimitStep
89+
policyID={policyID}
90+
stepNames={stepNames}
91+
startStepIndex={startStepIndex}
92+
/>
93+
);
4894
case CONST.EXPENSIFY_CARD.STEP.CARD_NAME:
49-
return <CardNameStep policyID={policyID} />;
95+
return (
96+
<CardNameStep
97+
policyID={policyID}
98+
stepNames={stepNames}
99+
startStepIndex={startStepIndex}
100+
/>
101+
);
50102
case CONST.EXPENSIFY_CARD.STEP.CONFIRMATION:
51103
return (
52104
<ConfirmationStep
53105
policyID={policyID}
54106
backTo={shouldUseBackToParam ? backTo : undefined}
107+
stepNames={stepNames}
108+
startStepIndex={startStepIndex}
55109
/>
56110
);
57111
default:
58-
return <AssigneeStep policy={policy} />;
112+
return (
113+
<AssigneeStep
114+
policy={policy}
115+
stepNames={stepNames}
116+
startStepIndex={startStepIndex}
117+
/>
118+
);
59119
}
60120
};
61121

src/pages/workspace/expensifyCard/issueNew/LimitStep.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,19 @@ import INPUT_IDS from '@src/types/form/IssueNewExpensifyCardForm';
1919
type LimitStepProps = {
2020
/** ID of the policy */
2121
policyID: string | undefined;
22+
23+
/** Array of step names */
24+
stepNames: readonly string[];
25+
26+
/** Start from step index */
27+
startStepIndex: number;
2228
};
2329

24-
function LimitStep({policyID}: LimitStepProps) {
30+
function LimitStep({policyID, stepNames, startStepIndex}: LimitStepProps) {
2531
const {translate} = useLocalize();
2632
const {inputCallbackRef} = useAutoFocusInput();
2733
const styles = useThemeStyles();
28-
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`);
34+
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});
2935
const isEditing = issueNewCard?.isEditing;
3036

3137
const submit = useCallback(
@@ -75,8 +81,8 @@ function LimitStep({policyID}: LimitStepProps) {
7581
shouldEnableMaxHeight
7682
headerTitle={translate('workspace.card.issueCard')}
7783
handleBackButtonPress={handleBackButtonPress}
78-
startStepIndex={3}
79-
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
84+
startStepIndex={startStepIndex}
85+
stepNames={stepNames}
8086
enableEdgeToEdgeBottomSafeAreaPadding
8187
>
8288
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.setLimit')}</Text>

0 commit comments

Comments
 (0)