From f7ba709dbec2fc9e78a6cdbb44073a057c769b35 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 10 Oct 2024 18:33:39 +0700 Subject: [PATCH 1/4] fix: do not show cards section when the domain is not provisioned --- src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index 52814f5da23d..dec399c6def8 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -63,6 +63,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [expensifyCardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`); const [allCardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}`); + const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${workspaceAccountID}`); const [isRemoveMemberConfirmModalVisible, setIsRemoveMemberConfirmModalVisible] = useState(false); const [isRoleSelectionModalVisible, setIsRoleSelectionModalVisible] = useState(false); @@ -80,6 +81,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const ownerDetails = personalDetails?.[policy?.ownerAccountID ?? -1] ?? ({} as PersonalDetails); const policyOwnerDisplayName = ownerDetails.displayName ?? policy?.owner ?? ''; const companyCards = CardUtils.getMemberCards(policy, allCardsList, accountID); + const paymentAccountID = cardSettings?.paymentBankAccountID ?? 0; // TODO: for now enabled for testing purposes. Change this to check for the actual multiple feeds when API is ready const hasMultipleFeeds = policy?.areCompanyCardsEnabled; @@ -206,6 +208,8 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM return ; } + const shouldShowCardsSection = (policy?.areExpensifyCardsEnabled && paymentAccountID) ?? policy?.areCompanyCardsEnabled; + return ( setIsRoleSelectionModalVisible(false)} /> - {(policy?.areExpensifyCardsEnabled ?? policy?.areCompanyCardsEnabled) && ( + {shouldShowCardsSection && ( <> From e3fc12cd0dd452f8407de2c4eda432201cf3a6b1 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 11 Oct 2024 19:09:17 +0700 Subject: [PATCH 2/4] fix: show an error when the card cannot be issued --- src/libs/actions/Card.ts | 62 +++++++++++++++++-- .../issueNew/ConfirmationStep.tsx | 30 ++++++--- .../issueNew/IssueNewCardPage.tsx | 6 ++ src/types/onyx/Card.ts | 9 +++ 4 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/Card.ts b/src/libs/actions/Card.ts index c0de9510c6ba..cff3d5d5aae8 100644 --- a/src/libs/actions/Card.ts +++ b/src/libs/actions/Card.ts @@ -22,6 +22,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Card} from '@src/types/onyx'; import type {CardLimitType, ExpensifyCardDetails, IssueNewCardData, IssueNewCardStep} from '@src/types/onyx/Card'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {ConnectionName} from '@src/types/onyx/Policy'; type ReplacementReason = 'damaged' | 'stolen'; @@ -223,7 +224,11 @@ function revealVirtualCardDetails(cardID: number, validateCode: string): Promise ]; // eslint-disable-next-line rulesdir/no-api-side-effects-method - API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.REVEAL_EXPENSIFY_CARD_DETAILS, parameters, {optimisticData, successData, failureData}) + API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.REVEAL_EXPENSIFY_CARD_DETAILS, parameters, { + optimisticData, + successData, + failureData, + }) .then((response) => { if (response?.jsonCode !== CONST.JSON_CODE.SUCCESS) { if (response?.jsonCode === CONST.JSON_CODE.INCORRECT_MAGIC_CODE) { @@ -336,7 +341,7 @@ function getCardDefaultName(userName?: string) { } function setIssueNewCardStepAndData({data, isEditing, step}: IssueNewCardFlowData) { - Onyx.merge(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, {data, isEditing, currentStep: step}); + Onyx.merge(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, {data, isEditing, currentStep: step, errors: null}); } function clearIssueNewCardFlow() { @@ -625,6 +630,39 @@ function issueExpensifyCard(policyID: string, feedCountry: string, data?: IssueN const {assigneeEmail, limit, limitType, cardTitle, cardType} = data; + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, + value: { + isLoading: true, + errors: null, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, + value: { + isLoading: false, + success: true, + }, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, + value: { + isLoading: false, + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), + }, + }, + ]; + const parameters = { policyID, assigneeEmail, @@ -634,14 +672,30 @@ function issueExpensifyCard(policyID: string, feedCountry: string, data?: IssueN }; if (cardType === CONST.EXPENSIFY_CARD.CARD_TYPE.PHYSICAL) { - API.write(WRITE_COMMANDS.CREATE_EXPENSIFY_CARD, {...parameters, feedCountry}); + API.write( + WRITE_COMMANDS.CREATE_EXPENSIFY_CARD, + {...parameters, feedCountry}, + { + optimisticData, + successData, + failureData, + }, + ); return; } const domainAccountID = PolicyUtils.getWorkspaceAccountID(policyID); // eslint-disable-next-line rulesdir/no-multiple-api-calls - API.write(WRITE_COMMANDS.CREATE_ADMIN_ISSUED_VIRTUAL_CARD, {...parameters, domainAccountID}); + API.write( + WRITE_COMMANDS.CREATE_ADMIN_ISSUED_VIRTUAL_CARD, + {...parameters, domainAccountID}, + { + optimisticData, + successData, + failureData, + }, + ); } function openCardDetailsPage(cardID: number) { diff --git a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx index c5a852450828..ae1e56791432 100644 --- a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx @@ -1,7 +1,7 @@ import React, {useEffect, useRef} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; -import Button from '@components/Button'; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; @@ -13,6 +13,7 @@ import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import {getTranslationKeyForLimitType} from '@libs/CardUtils'; import * as CurrencyUtils from '@libs/CurrencyUtils'; +import * as ErrorUtils from '@libs/ErrorUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import Navigation from '@navigation/Navigation'; import * as Card from '@userActions/Card'; @@ -38,6 +39,7 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) { const [issueNewCard] = useOnyx(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD); const data = issueNewCard?.data; + const success = issueNewCard?.success; const submitButton = useRef(null); @@ -45,12 +47,20 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) { submitButton.current?.focus(); }, []); - const submit = () => { - Card.issueExpensifyCard(policyID, CONST.COUNTRY.US, data); + useEffect(() => { + if (!success) { + return; + } Navigation.navigate(backTo ?? ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID ?? '-1')); Card.clearIssueNewCardFlow(); + }, [backTo, policyID, success]); + + const submit = () => { + Card.issueExpensifyCard(policyID, CONST.COUNTRY.US, data); }; + const errorMessage = ErrorUtils.getLatestErrorMessage(issueNewCard); + const editStep = (step: IssueNewCardStep) => { Card.setIssueNewCardStepAndData({step, isEditing: true}); }; @@ -115,14 +125,14 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) { onPress={() => editStep(CONST.EXPENSIFY_CARD.STEP.CARD_NAME)} /> -