Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3182,6 +3182,7 @@ const CONST = {
},
LIMIT_VALUE: 21474836,
STEP_NAMES: ['1', '2', '3', '4', '5', '6'],
ASSIGNEE_EXCLUDED_STEP_NAMES: ['1', '2', '3', '4', '5'],
STEP: {
ASSIGNEE: 'Assignee',
CARD_TYPE: 'CardType',
Expand Down
6 changes: 5 additions & 1 deletion src/libs/actions/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type IssueNewCardFlowData = {

/** ID of the policy */
policyID: string | undefined;

/** Whether the changing assignee is disabled. E.g., The assignee is auto selected from workspace members page */
isChangeAssigneeDisabled?: boolean;
};

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

function setIssueNewCardStepAndData({data, isEditing, step, policyID}: IssueNewCardFlowData) {
function setIssueNewCardStepAndData({data, isEditing, step, policyID, isChangeAssigneeDisabled}: IssueNewCardFlowData) {
Onyx.merge(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {
data,
isEditing,
currentStep: step,
errors: null,
isChangeAssigneeDisabled,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import Navigation from '@navigation/Navigation';
import type {SettingsNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import variables from '@styles/variables';
import {configureExpensifyCardsForPolicy} from '@userActions/Card';
import {configureExpensifyCardsForPolicy, setIssueNewCardStepAndData} from '@userActions/Card';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand Down Expand Up @@ -160,6 +160,7 @@ function WorkspaceExpensifyCardBankAccounts({route}: WorkspaceExpensifyCardBankA
style={[styles.m5, bottomSafeAreaPaddingStyle]}
pressOnEnter
onPress={() => {
setIssueNewCardStepAndData({policyID, isChangeAssigneeDisabled: false});
Navigation.dismissModal();
Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID));
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSearchResults from '@hooks/useSearchResults';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {setIssueNewCardStepAndData} from '@libs/actions/Card';
import {clearDeletePaymentMethodError} from '@libs/actions/PaymentMethods';
import {filterCardsByPersonalDetails, getCardsByCardholderName, sortCardsByCardholderName} from '@libs/CardUtils';
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
Expand Down Expand Up @@ -102,6 +103,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList, fundID}: WorkspaceExp
return;
}
const activeRoute = Navigation.getActiveRoute();
setIssueNewCardStepAndData({policyID, isChangeAssigneeDisabled: false});
Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID, activeRoute));
};

Expand Down
12 changes: 9 additions & 3 deletions src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ const MINIMUM_MEMBER_TO_SHOW_SEARCH = 8;
type AssigneeStepProps = {
// The policy that the card will be issued under
policy: OnyxEntry<OnyxTypes.Policy>;

/** Array of step names */
stepNames: readonly string[];

/** Start from step index */
startStepIndex: number;
};

function AssigneeStep({policy}: AssigneeStepProps) {
function AssigneeStep({policy, stepNames, startStepIndex}: AssigneeStepProps) {
const {translate, formatPhoneNumber, localeCompare} = useLocalize();
const styles = useThemeStyles();
const {isOffline} = useNetwork();
Expand Down Expand Up @@ -139,8 +145,8 @@ function AssigneeStep({policy}: AssigneeStepProps) {
shouldEnableMaxHeight
headerTitle={translate('workspace.card.issueCard')}
handleBackButtonPress={handleBackButtonPress}
startStepIndex={0}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
startStepIndex={startStepIndex}
stepNames={stepNames}
enableEdgeToEdgeBottomSafeAreaPadding
>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.whoNeedsCard')}</Text>
Expand Down
14 changes: 10 additions & 4 deletions src/pages/workspace/expensifyCard/issueNew/CardNameStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ import INPUT_IDS from '@src/types/form/IssueNewExpensifyCardForm';
type CardNameStepProps = {
/** ID of the policy */
policyID: string | undefined;

/** Array of step names */
stepNames: readonly string[];

/** Start from step index */
startStepIndex: number;
};

function CardNameStep({policyID}: CardNameStepProps) {
function CardNameStep({policyID, stepNames, startStepIndex}: CardNameStepProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {inputCallbackRef} = useAutoFocusInput();
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`);
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});

const isEditing = issueNewCard?.isEditing;
const data = issueNewCard?.data;
Expand Down Expand Up @@ -73,8 +79,8 @@ function CardNameStep({policyID}: CardNameStepProps) {
shouldEnableMaxHeight
headerTitle={translate('workspace.card.issueCard')}
handleBackButtonPress={handleBackButtonPress}
startStepIndex={4}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
startStepIndex={startStepIndex}
stepNames={stepNames}
enableEdgeToEdgeBottomSafeAreaPadding
>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.giveItName')}</Text>
Expand Down
22 changes: 17 additions & 5 deletions src/pages/workspace/expensifyCard/issueNew/CardTypeStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,27 @@ import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
import {setIssueNewCardStepAndData} from '@libs/actions/Card';
import {clearIssueNewCardFlow, setIssueNewCardStepAndData} from '@libs/actions/Card';
import Navigation from '@libs/Navigation/Navigation';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';

type CardTypeStepProps = {
/** ID of the policy */
policyID: string | undefined;

/** Array of step names */
stepNames: readonly string[];

/** Start from step index */
startStepIndex: number;
};

function CardTypeStep({policyID}: CardTypeStepProps) {
function CardTypeStep({policyID, stepNames, startStepIndex}: CardTypeStepProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`);
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});

const isEditing = issueNewCard?.isEditing;

Expand All @@ -41,6 +48,11 @@ function CardTypeStep({policyID}: CardTypeStepProps) {
setIssueNewCardStepAndData({step: CONST.EXPENSIFY_CARD.STEP.CONFIRMATION, isEditing: false, policyID});
return;
}
if (issueNewCard?.isChangeAssigneeDisabled) {
Navigation.goBack();
clearIssueNewCardFlow(policyID);
return;
}
setIssueNewCardStepAndData({step: CONST.EXPENSIFY_CARD.STEP.ASSIGNEE, policyID});
};

Expand All @@ -52,8 +64,8 @@ function CardTypeStep({policyID}: CardTypeStepProps) {
offlineIndicatorStyle={styles.mtAuto}
headerTitle={translate('workspace.card.issueCard')}
handleBackButtonPress={handleBackButtonPress}
startStepIndex={1}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
startStepIndex={startStepIndex}
stepNames={stepNames}
enableEdgeToEdgeBottomSafeAreaPadding
>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.chooseCardType')}</Text>
Expand Down
15 changes: 11 additions & 4 deletions src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,15 @@ type ConfirmationStepProps = {

/** Route to navigate to */
backTo?: Route;

/** Array of step names */
stepNames: readonly string[];

/** Start from step index */
startStepIndex: number;
};

function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) {
function ConfirmationStep({policyID, backTo, stepNames, startStepIndex}: ConfirmationStepProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {isOffline} = useNetwork();
Expand Down Expand Up @@ -90,8 +96,8 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) {
shouldEnableMaxHeight
headerTitle={translate('workspace.card.issueCard')}
handleBackButtonPress={handleBackButtonPress}
startStepIndex={5}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
startStepIndex={startStepIndex}
stepNames={stepNames}
enableEdgeToEdgeBottomSafeAreaPadding
>
<ScrollView
Expand All @@ -104,7 +110,8 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) {
<MenuItemWithTopDescription
description={translate('workspace.card.issueNewCard.cardholder')}
title={getUserNameByEmail(data?.assigneeEmail ?? '', 'displayName')}
shouldShowRightIcon
shouldShowRightIcon={!issueNewCard?.isChangeAssigneeDisabled}
interactive={!issueNewCard?.isChangeAssigneeDisabled}
onPress={() => editStep(CONST.EXPENSIFY_CARD.STEP.ASSIGNEE)}
/>
<MenuItemWithTopDescription
Expand Down
74 changes: 67 additions & 7 deletions src/pages/workspace/expensifyCard/issueNew/IssueNewCardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {useEffect} from 'react';
import React, {useEffect, useMemo} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper';
import ScreenWrapper from '@components/ScreenWrapper';
import useInitial from '@hooks/useInitial';
Expand All @@ -13,6 +14,7 @@ import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullsc
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
import type {IssueNewCard, IssueNewCardStep} from '@src/types/onyx/Card';
import AssigneeStep from './AssigneeStep';
import CardNameStep from './CardNameStep';
import CardTypeStep from './CardTypeStep';
Expand All @@ -22,6 +24,24 @@ import LimitTypeStep from './LimitTypeStep';

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

function getStartStepIndex(issueNewCard: OnyxEntry<IssueNewCard>): number {
if (!issueNewCard) {
return 0;
}

const STEP_INDEXES: Record<IssueNewCardStep, number> = {
[CONST.EXPENSIFY_CARD.STEP.ASSIGNEE]: 0,
[CONST.EXPENSIFY_CARD.STEP.CARD_TYPE]: 1,
[CONST.EXPENSIFY_CARD.STEP.LIMIT_TYPE]: 2,
[CONST.EXPENSIFY_CARD.STEP.LIMIT]: 3,
[CONST.EXPENSIFY_CARD.STEP.CARD_NAME]: 4,
[CONST.EXPENSIFY_CARD.STEP.CONFIRMATION]: 5,
};

const stepIndex = STEP_INDEXES[issueNewCard.currentStep];
return issueNewCard.isChangeAssigneeDisabled ? stepIndex - 1 : stepIndex;
}

function IssueNewCardPage({policy, route}: IssueNewCardPageProps) {
const policyID = policy?.id;
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});
Expand All @@ -30,6 +50,8 @@ function IssueNewCardPage({policy, route}: IssueNewCardPageProps) {
const firstAssigneeEmail = useInitial(issueNewCard?.data?.assigneeEmail);
const shouldUseBackToParam = !firstAssigneeEmail || firstAssigneeEmail === issueNewCard?.data?.assigneeEmail;
const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate, canBeMissing: true});
const stepNames = issueNewCard?.isChangeAssigneeDisabled ? CONST.EXPENSIFY_CARD.ASSIGNEE_EXCLUDED_STEP_NAMES : CONST.EXPENSIFY_CARD.STEP_NAMES;
const startStepIndex = useMemo(() => getStartStepIndex(issueNewCard), [issueNewCard]);

useEffect(() => {
startIssueNewCardFlow(policyID);
Expand All @@ -38,24 +60,62 @@ function IssueNewCardPage({policy, route}: IssueNewCardPageProps) {
const getCurrentStep = () => {
switch (currentStep) {
case CONST.EXPENSIFY_CARD.STEP.ASSIGNEE:
return <AssigneeStep policy={policy} />;
return (
<AssigneeStep
policy={policy}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
case CONST.EXPENSIFY_CARD.STEP.CARD_TYPE:
return <CardTypeStep policyID={policyID} />;
return (
<CardTypeStep
policyID={policyID}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
case CONST.EXPENSIFY_CARD.STEP.LIMIT_TYPE:
return <LimitTypeStep policy={policy} />;
return (
<LimitTypeStep
policy={policy}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
case CONST.EXPENSIFY_CARD.STEP.LIMIT:
return <LimitStep policyID={policyID} />;
return (
<LimitStep
policyID={policyID}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
case CONST.EXPENSIFY_CARD.STEP.CARD_NAME:
return <CardNameStep policyID={policyID} />;
return (
<CardNameStep
policyID={policyID}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
case CONST.EXPENSIFY_CARD.STEP.CONFIRMATION:
return (
<ConfirmationStep
policyID={policyID}
backTo={shouldUseBackToParam ? backTo : undefined}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
default:
return <AssigneeStep policy={policy} />;
return (
<AssigneeStep
policy={policy}
stepNames={stepNames}
startStepIndex={startStepIndex}
/>
);
}
};

Expand Down
14 changes: 10 additions & 4 deletions src/pages/workspace/expensifyCard/issueNew/LimitStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ import INPUT_IDS from '@src/types/form/IssueNewExpensifyCardForm';
type LimitStepProps = {
/** ID of the policy */
policyID: string | undefined;

/** Array of step names */
stepNames: readonly string[];

/** Start from step index */
startStepIndex: number;
};

function LimitStep({policyID}: LimitStepProps) {
function LimitStep({policyID, stepNames, startStepIndex}: LimitStepProps) {
const {translate} = useLocalize();
const {inputCallbackRef} = useAutoFocusInput();
const styles = useThemeStyles();
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`);
const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true});
const isEditing = issueNewCard?.isEditing;

const submit = useCallback(
Expand Down Expand Up @@ -75,8 +81,8 @@ function LimitStep({policyID}: LimitStepProps) {
shouldEnableMaxHeight
headerTitle={translate('workspace.card.issueCard')}
handleBackButtonPress={handleBackButtonPress}
startStepIndex={3}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
startStepIndex={startStepIndex}
stepNames={stepNames}
enableEdgeToEdgeBottomSafeAreaPadding
>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.setLimit')}</Text>
Expand Down
Loading
Loading