Skip to content

Commit 3762bf4

Browse files
authored
Merge pull request Expensify#80631 from nkdengineer/fix/80146
fix: Generic Error Displayed When Assigning a Card Already Assigned on another feed
2 parents 0be235c + af93342 commit 3762bf4

10 files changed

Lines changed: 49 additions & 199 deletions

File tree

src/ONYXKEYS.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -731,9 +731,6 @@ const ONYXKEYS = {
731731
*/
732732
WORKSPACE_CARDS_LIST: 'cards_',
733733

734-
/** Collection of objects where each object represents the card assignment that failed because we can't store errors in cardList or card feed due to server-provided IDs that aren't optimistic. */
735-
FAILED_COMPANY_CARDS_ASSIGNMENTS: 'failedCompanyCardsAssignments_',
736-
737734
/** Expensify cards settings */
738735
PRIVATE_EXPENSIFY_CARD_SETTINGS: 'private_expensifyCardSettings_',
739736

@@ -1186,7 +1183,6 @@ type OnyxCollectionValuesMapping = {
11861183
[ONYXKEYS.COLLECTION.EXPENSIFY_CARD_BANK_ACCOUNT_METADATA]: OnyxTypes.ExpensifyCardBankAccountMetadata;
11871184
[ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_MANUAL_BILLING]: boolean;
11881185
[ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST]: OnyxTypes.WorkspaceCardsList;
1189-
[ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS]: OnyxTypes.FailedCompanyCardAssignments;
11901186
[ONYXKEYS.COLLECTION.EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION]: OnyxTypes.PolicyConnectionName;
11911187
[ONYXKEYS.COLLECTION.EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION]: OnyxTypes.CardContinuousReconciliation;
11921188
[ONYXKEYS.COLLECTION.LAST_SELECTED_FEED]: OnyxTypes.CompanyCardFeedWithDomainID;

src/hooks/useCardFeedErrors.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const DEFAULT_CARD_FEED_ERROR_STATE: CardFeedErrorState = {
77
isFeedConnectionBroken: false,
88
hasFeedErrors: false,
99
hasWorkspaceErrors: false,
10-
hasFailedCardAssignments: false,
1110
};
1211

1312
const DEFAULT_CARD_FEED_ERRORS: CardFeedErrors = {

src/libs/actions/CompanyCards.ts

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
2222
import * as ReportUtils from '@libs/ReportUtils';
2323
import CONST from '@src/CONST';
2424
import ONYXKEYS from '@src/ONYXKEYS';
25-
import type {Card, FailedCompanyCardAssignment, Policy} from '@src/types/onyx';
25+
import type {Card, Policy} from '@src/types/onyx';
2626
import type {AssignCard, AssignCardData} from '@src/types/onyx/AssignCard';
2727
import type {
2828
AddNewCardFeedData,
@@ -60,6 +60,10 @@ function clearAssignCardStepAndData() {
6060
Onyx.set(ONYXKEYS.ASSIGN_CARD, {});
6161
}
6262

63+
function clearAssignCardErrors() {
64+
Onyx.merge(ONYXKEYS.ASSIGN_CARD, {errors: null});
65+
}
66+
6367
function setAddNewCompanyCardStepAndData({data, isEditing, step}: NullishDeep<AddNewCompanyCardFlowData>) {
6468
Onyx.merge(ONYXKEYS.ADD_NEW_COMPANY_CARD, {data, isEditing, currentStep: step});
6569
}
@@ -317,23 +321,10 @@ function assignWorkspaceCompanyCard(
317321
if (!data || !policy?.id) {
318322
return;
319323
}
320-
const {bankName = '', email = '', encryptedCardNumber = '', startDate = '', cardName = '', cardholder, customCardName = ''} = data;
324+
const {bankName = '', email = '', encryptedCardNumber = '', startDate = '', customCardName = ''} = data;
321325
const assigneeDetails = PersonalDetailsUtils.getPersonalDetailByEmail(email);
322326
const optimisticCardAssignedReportAction = ReportUtils.buildOptimisticCardAssignedReportAction(assigneeDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID);
323327

324-
const failedCardAssignment: FailedCompanyCardAssignment = {
325-
domainOrWorkspaceAccountID,
326-
feed,
327-
cardholder,
328-
cardName,
329-
customCardName,
330-
encryptedCardNumber,
331-
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
332-
errors: {
333-
failed: translate('workspace.companyCards.assignCardFailedError'),
334-
},
335-
};
336-
337328
const parameters: AssignCompanyCardParams = {
338329
domainAccountID: domainOrWorkspaceAccountID,
339330
policyID: policy.id,
@@ -346,7 +337,7 @@ function assignWorkspaceCompanyCard(
346337
};
347338
const policyExpenseChat = ReportUtils.getPolicyExpenseChat(policy.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID, policy.id);
348339

349-
const onyxData: OnyxData<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS | typeof ONYXKEYS.ASSIGN_CARD | typeof ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS> = {
340+
const onyxData: OnyxData<typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS | typeof ONYXKEYS.ASSIGN_CARD> = {
350341
optimisticData: [
351342
{
352343
onyxMethod: Onyx.METHOD.MERGE,
@@ -369,10 +360,8 @@ function assignWorkspaceCompanyCard(
369360
},
370361
{
371362
onyxMethod: Onyx.METHOD.MERGE,
372-
key: `${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feed}`,
373-
value: {
374-
[encryptedCardNumber]: null,
375-
},
363+
key: ONYXKEYS.ASSIGN_CARD,
364+
value: {isAssignmentFinished: true},
376365
},
377366
],
378367
failureData: [
@@ -386,36 +375,19 @@ function assignWorkspaceCompanyCard(
386375
},
387376
},
388377
},
389-
{
390-
onyxMethod: Onyx.METHOD.MERGE,
391-
key: `${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feed}`,
392-
value: {
393-
[encryptedCardNumber]: failedCardAssignment,
394-
},
395-
},
396378
],
397379
finallyData: [
398380
{
399381
onyxMethod: Onyx.METHOD.MERGE,
400382
key: ONYXKEYS.ASSIGN_CARD,
401-
value: {isAssigning: false, isAssignmentFinished: true},
383+
value: {isAssigning: false},
402384
},
403385
],
404386
};
405387

406388
API.write(WRITE_COMMANDS.ASSIGN_COMPANY_CARD, parameters, onyxData);
407389
}
408390

409-
function resetFailedWorkspaceCompanyCardAssignment(domainOrWorkspaceAccountID: number, feed: CompanyCardFeedWithDomainID | undefined, encryptedCardNumber: string) {
410-
if (!feed) {
411-
return;
412-
}
413-
414-
Onyx.merge(`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feed}`, {
415-
[encryptedCardNumber]: null,
416-
});
417-
}
418-
419391
function unassignWorkspaceCompanyCard(domainOrWorkspaceAccountID: number, bankName: CompanyCardFeed, card: Card) {
420392
const cardID = card.cardID;
421393

@@ -1087,7 +1059,6 @@ export {
10871059
openPolicyCompanyCardsFeed,
10881060
addNewCompanyCardsFeed,
10891061
assignWorkspaceCompanyCard,
1090-
resetFailedWorkspaceCompanyCardAssignment,
10911062
unassignWorkspaceCompanyCard,
10921063
resetFailedWorkspaceCompanyCardUnassignment,
10931064
updateWorkspaceCompanyCard,
@@ -1104,4 +1075,5 @@ export {
11041075
setTransactionStartDate,
11051076
setFeedStatementPeriodEndDay,
11061077
clearErrorField,
1078+
clearAssignCardErrors,
11071079
};

src/libs/actions/OnyxDerived/configs/cardFeedErrors.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
1111

1212
const DEFAULT_CARD_FEED_ERROR_STATE: CardFeedErrorState = {
1313
shouldShowRBR: false,
14-
hasFailedCardAssignments: false,
1514
hasFeedErrors: false,
1615
hasWorkspaceErrors: false,
1716
isFeedConnectionBroken: false,
@@ -24,17 +23,14 @@ function getShouldShowRBR(state: Partial<CardFeedErrorState>): boolean {
2423
if (state.hasWorkspaceErrors) {
2524
return true;
2625
}
27-
if (state.hasFailedCardAssignments) {
28-
return true;
29-
}
3026

3127
return !!state.isFeedConnectionBroken;
3228
}
3329

3430
export default createOnyxDerivedValueConfig({
3531
key: ONYXKEYS.DERIVED.CARD_FEED_ERRORS,
36-
dependencies: [ONYXKEYS.CARD_LIST, ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS, ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER],
37-
compute: ([globalCardList, allWorkspaceCards, failedCompanyCardAssignmentsPerFeed, cardFeeds]) => {
32+
dependencies: [ONYXKEYS.CARD_LIST, ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST, ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER],
33+
compute: ([globalCardList, allWorkspaceCards, cardFeeds]) => {
3834
const combinedCompanyCardFeeds = getCombinedCardFeedsFromAllFeeds(cardFeeds);
3935
const workspaceCardFeedsStatus = getWorkspaceCardFeedsStatus(cardFeeds);
4036

@@ -71,10 +67,6 @@ export default createOnyxDerivedValueConfig({
7167
const workspaceErrors = workspaceCardFeedsStatus?.[workspaceAccountID]?.errors;
7268
const hasWorkspaceErrors = !!workspaceErrors;
7369

74-
const hasFailedCardAssignments = !isEmptyObject(
75-
failedCompanyCardAssignmentsPerFeed?.[`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${workspaceAccountID}_${feedNameWithDomainID}`],
76-
);
77-
7870
const hasCardErrors = !isEmptyObject(card.errors) || !isEmptyObject(card.errorFields) || card.pendingAction;
7971
const cardErrors = {
8072
...previousFeedErrors.cardErrors,
@@ -96,7 +88,6 @@ export default createOnyxDerivedValueConfig({
9688
isFeedConnectionBroken: isFeedConnectionBroken || previousFeedErrors.isFeedConnectionBroken,
9789
hasFeedErrors: hasFeedErrors || previousFeedErrors.hasFeedErrors,
9890
hasWorkspaceErrors: hasWorkspaceErrors || previousFeedErrors.hasWorkspaceErrors,
99-
hasFailedCardAssignments: hasFailedCardAssignments || previousFeedErrors.hasFailedCardAssignments,
10091
};
10192

10293
const shouldShowRBR = getShouldShowRBR(newFeedState) || previousFeedErrors.shouldShowRBR;
@@ -120,12 +111,10 @@ export default createOnyxDerivedValueConfig({
120111
allFeedsState.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken;
121112
allFeedsState.hasFeedErrors ||= newFeedState.hasFeedErrors;
122113
allFeedsState.hasWorkspaceErrors ||= newFeedState.hasWorkspaceErrors;
123-
allFeedsState.hasFailedCardAssignments ||= newFeedState.hasFailedCardAssignments;
124114

125115
cardTypeState.isFeedConnectionBroken ||= newFeedState.isFeedConnectionBroken;
126116
cardTypeState.hasFeedErrors ||= newFeedState.hasFeedErrors;
127117
cardTypeState.hasWorkspaceErrors ||= newFeedState.hasWorkspaceErrors;
128-
cardTypeState.hasFailedCardAssignments ||= newFeedState.hasFailedCardAssignments;
129118

130119
shouldShowRbrForWorkspaceAccountID[workspaceAccountID] ||= shouldShowRBR;
131120
shouldShowRbrForFeedNameWithDomainID[feedNameWithDomainID] ||= shouldShowRBR;

src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import useNetwork from '@hooks/useNetwork';
1616
import useOnyx from '@hooks/useOnyx';
1717
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1818
import useThemeStyles from '@hooks/useThemeStyles';
19-
import {resetFailedWorkspaceCompanyCardAssignment, resetFailedWorkspaceCompanyCardUnassignment} from '@libs/actions/CompanyCards';
19+
import {resetFailedWorkspaceCompanyCardUnassignment} from '@libs/actions/CompanyCards';
2020
import {getDefaultCardName, getPlaidInstitutionId} from '@libs/CardUtils';
2121
import tokenizedSearch from '@libs/tokenizedSearch';
2222
import WorkspaceCompanyCardPageEmptyState from '@pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState';
@@ -90,7 +90,6 @@ function WorkspaceCompanyCardsTable({
9090
const [countryByIp] = useOnyx(ONYXKEYS.COUNTRY, {canBeMissing: false});
9191
const [personalDetails, personalDetailsMetadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false});
9292
const [customCardNames] = useOnyx(ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES, {canBeMissing: true});
93-
const [failedCompanyCardAssignments] = useOnyx(`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feedName ?? ''}`, {canBeMissing: true});
9493

9594
const hasNoAssignedCard = Object.keys(assignedCards ?? {}).length === 0;
9695

@@ -152,17 +151,6 @@ function WorkspaceCompanyCardsTable({
152151
const cardsData: WorkspaceCompanyCardTableItemData[] = isLoadingCards
153152
? []
154153
: (Object.entries(cardNamesToEncryptedCardNumberMapping ?? {}).map(([cardName, encryptedCardNumber]) => {
155-
const failedCompanyCardAssignment = failedCompanyCardAssignments?.[encryptedCardNumber];
156-
157-
if (failedCompanyCardAssignment) {
158-
return {
159-
...failedCompanyCardAssignment,
160-
onDismissError: () => resetFailedWorkspaceCompanyCardAssignment(domainOrWorkspaceAccountID, feedName, failedCompanyCardAssignment.encryptedCardNumber),
161-
isCardDeleted: false,
162-
isAssigned: true,
163-
};
164-
}
165-
166154
const assignedCard = Object.values(assignedCards ?? {}).find((card: Card) => card.encryptedCardNumber === encryptedCardNumber || card.cardName === cardName);
167155
const cardholder = assignedCard?.accountID ? personalDetails?.[assignedCard.accountID] : undefined;
168156

src/pages/workspace/companyCards/assignCard/ConfirmationStep.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
2323
import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils';
2424
import {getDefaultAvatarURL} from '@libs/UserAvatarUtils';
2525
import Navigation from '@navigation/Navigation';
26-
import {assignWorkspaceCompanyCard, clearAssignCardStepAndData, setAddNewCompanyCardStepAndData, setAssignCardStepAndData} from '@userActions/CompanyCards';
26+
import {
27+
assignWorkspaceCompanyCard,
28+
clearAssignCardErrors as clearAssignCardErrorsAction,
29+
clearAssignCardStepAndData,
30+
setAddNewCompanyCardStepAndData,
31+
setAssignCardStepAndData,
32+
} from '@userActions/CompanyCards';
2733
import CONST from '@src/CONST';
2834
import ONYXKEYS from '@src/ONYXKEYS';
2935
import ROUTES from '@src/ROUTES';
@@ -136,6 +142,11 @@ function ConfirmationStep({route}: ConfirmationStepProps) {
136142
Navigation.goBack(ROUTES.WORKSPACE_COMPANY_CARDS_ASSIGN_CARD_ASSIGNEE.getRoute({policyID, feed, cardID}), {compareParams: false});
137143
};
138144

145+
const clearAssignCardErrors = () => {
146+
clearAssignCardErrorsAction();
147+
setCardError(undefined);
148+
};
149+
139150
return (
140151
<InteractiveStepWrapper
141152
wrapperID="ConfirmationStep"
@@ -187,7 +198,7 @@ function ConfirmationStep({route}: ConfirmationStepProps) {
187198
<OfflineWithFeedback
188199
shouldDisplayErrorAbove
189200
errors={assignCard?.errors ?? cardError}
190-
onClose={() => setCardError(undefined)}
201+
onClose={clearAssignCardErrors}
191202
errorRowStyles={styles.mv2}
192203
>
193204
<Button

src/types/onyx/Card.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {ValueOf} from 'type-fest';
22
import type CONST from '@src/CONST';
3-
import type {CompanyCardFeedWithDomainID} from './CardFeeds';
43
import type * as OnyxCommon from './OnyxCommon';
54
import type PersonalDetails from './PersonalDetails';
65

@@ -345,20 +344,6 @@ type CardAssignmentData = {
345344
pendingAction?: OnyxCommon.PendingAction;
346345
};
347346

348-
/**
349-
* Pending action for a company card assignment
350-
*/
351-
type FailedCompanyCardAssignment = CardAssignmentData & {
352-
/** The domain or workspace account ID */
353-
domainOrWorkspaceAccountID: number;
354-
355-
/** The name of the feed */
356-
feed: CompanyCardFeedWithDomainID;
357-
};
358-
359-
/** Pending action for a company card assignment */
360-
type FailedCompanyCardAssignments = Record<string, FailedCompanyCardAssignment>;
361-
362347
export default Card;
363348
export type {
364349
ExpensifyCardDetails,
@@ -368,8 +353,6 @@ export type {
368353
IssueNewCardData,
369354
WorkspaceCardsList,
370355
CardAssignmentData,
371-
FailedCompanyCardAssignment,
372-
FailedCompanyCardAssignments,
373356
CardLimitType,
374357
ProvisioningCardData,
375358
AssignableCardsList,

src/types/onyx/DerivedValues.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,6 @@ type CardFeedErrorState = {
105105
*/
106106
shouldShowRBR: boolean;
107107

108-
/**
109-
* Whether some failed card assignments.
110-
*/
111-
hasFailedCardAssignments: boolean;
112-
113108
/**
114109
* Whether a specific feed within a workspace/domain has errors.
115110
*/

src/types/onyx/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type BillingStatus from './BillingStatus';
1616
import type BlockedFromConcierge from './BlockedFromConcierge';
1717
import type CancellationDetails from './CancellationDetails';
1818
import type Card from './Card';
19-
import type {CardList, FailedCompanyCardAssignment, FailedCompanyCardAssignments, IssueNewCard, ProvisioningCardData, WorkspaceCardsList} from './Card';
19+
import type {CardList, IssueNewCard, ProvisioningCardData, WorkspaceCardsList} from './Card';
2020
import type CardContinuousReconciliation from './CardContinuousReconciliation';
2121
import type CardFeeds from './CardFeeds';
2222
import type {
@@ -188,8 +188,6 @@ export type {
188188
Download,
189189
DuplicateWorkspace,
190190
WorkspaceCardsList,
191-
FailedCompanyCardAssignment,
192-
FailedCompanyCardAssignments,
193191
ExpenseRule,
194192
ExpensifyCardSettings,
195193
ExpensifyCardBankAccountMetadata,

0 commit comments

Comments
 (0)