Skip to content

Commit b3c8b56

Browse files
authored
Merge pull request #52871 from callstack-internal/chore/52820-workspace-cards-cleanup
Chore/52820 workspace cards cleanup
2 parents 2166dff + 2570632 commit b3c8b56

File tree

7 files changed

+92
-18
lines changed

7 files changed

+92
-18
lines changed

src/libs/CardUtils.ts

+13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {TranslationPaths} from '@src/languages/types';
99
import type {OnyxValues} from '@src/ONYXKEYS';
1010
import ONYXKEYS from '@src/ONYXKEYS';
1111
import type {BankAccountList, Card, CardFeeds, CardList, CompanyCardFeed, PersonalDetailsList, WorkspaceCardsList} from '@src/types/onyx';
12+
import type {FilteredCardList} from '@src/types/onyx/Card';
1213
import type {CompanyCardNicknames, CompanyFeeds} from '@src/types/onyx/CardFeeds';
1314
import {isEmptyObject} from '@src/types/utils/EmptyObject';
1415
import type IconAsset from '@src/types/utils/IconAsset';
@@ -352,6 +353,16 @@ function getSelectedFeed(lastSelectedFeed: OnyxEntry<CompanyCardFeed>, cardFeeds
352353
return lastSelectedFeed ?? defaultFeed;
353354
}
354355

356+
function getFilteredCardList(list?: WorkspaceCardsList) {
357+
const {cardList, ...cards} = list ?? {};
358+
// We need to filter out cards which already has been assigned
359+
return Object.fromEntries(Object.entries(cardList ?? {}).filter(([cardNumber]) => !Object.values(cards).find((card) => card.lastFourPAN && cardNumber.endsWith(card.lastFourPAN))));
360+
}
361+
362+
function hasOnlyOneCardToAssign(list: FilteredCardList) {
363+
return Object.keys(list).length === 1;
364+
}
365+
355366
export {
356367
isExpensifyCard,
357368
isCorporateCard,
@@ -378,4 +389,6 @@ export {
378389
getCorrectStepForSelectedBank,
379390
getCustomOrFormattedFeedName,
380391
removeExpensifyCardFromCompanyCards,
392+
getFilteredCardList,
393+
hasOnlyOneCardToAssign,
381394
};

src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx

+35-1
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
1313
import useTheme from '@hooks/useTheme';
1414
import useThemeStyles from '@hooks/useThemeStyles';
1515
import * as CardUtils from '@libs/CardUtils';
16+
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
1617
import * as PolicyUtils from '@libs/PolicyUtils';
1718
import Navigation from '@navigation/Navigation';
1819
import variables from '@styles/variables';
20+
import * as CompanyCards from '@userActions/CompanyCards';
21+
import CONST from '@src/CONST';
1922
import ONYXKEYS from '@src/ONYXKEYS';
2023
import ROUTES from '@src/ROUTES';
2124
import type {CompanyCardFeed} from '@src/types/onyx';
25+
import type {AssignCardData, AssignCardStep} from '@src/types/onyx/AssignCard';
2226

2327
type WorkspaceCompanyCardsListHeaderButtonsProps = {
2428
/** Current policy id */
@@ -41,6 +45,36 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed}: Worksp
4145
const isCustomFeed = CardUtils.isCustomFeed(selectedFeed);
4246
const companyFeeds = CardUtils.getCompanyFeeds(cardFeeds);
4347
const currentFeedData = companyFeeds?.[selectedFeed];
48+
const policy = PolicyUtils.getPolicy(policyID);
49+
50+
const [list] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${selectedFeed}`);
51+
const filteredCardList = CardUtils.getFilteredCardList(list);
52+
53+
const handleAssignCard = () => {
54+
const data: Partial<AssignCardData> = {
55+
bankName: selectedFeed,
56+
};
57+
58+
let currentStep: AssignCardStep = CONST.COMPANY_CARD.STEP.ASSIGNEE;
59+
60+
if (Object.keys(policy?.employeeList ?? {}).length === 1) {
61+
const userEmail = Object.keys(policy?.employeeList ?? {}).at(0) ?? '';
62+
data.email = userEmail;
63+
const personalDetails = PersonalDetailsUtils.getPersonalDetailByEmail(userEmail);
64+
const memberName = personalDetails?.firstName ? personalDetails.firstName : personalDetails?.login;
65+
data.cardName = `${memberName}'s card`;
66+
currentStep = CONST.COMPANY_CARD.STEP.CARD;
67+
68+
if (CardUtils.hasOnlyOneCardToAssign(filteredCardList)) {
69+
currentStep = CONST.COMPANY_CARD.STEP.TRANSACTION_START_DATE;
70+
data.cardNumber = Object.keys(filteredCardList).at(0);
71+
data.encryptedCardNumber = Object.values(filteredCardList).at(0);
72+
}
73+
}
74+
75+
CompanyCards.setAssignCardStepAndData({data, currentStep});
76+
Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ASSIGN_CARD.getRoute(policyID, selectedFeed)));
77+
};
4478

4579
return (
4680
<OfflineWithFeedback
@@ -79,7 +113,7 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed}: Worksp
79113
<Button
80114
success
81115
isDisabled={!currentFeedData || !!currentFeedData?.pending || !!currentFeedData?.errors}
82-
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ASSIGN_CARD.getRoute(policyID, selectedFeed))}
116+
onPress={handleAssignCard}
83117
icon={Expensicons.Plus}
84118
text={translate('workspace.companyCards.assignCard')}
85119
style={shouldChangeLayout && styles.flex1}

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ function AssignCardFeedPage({route, policy}: AssignCardFeedPageProps) {
2525
const policyID = policy?.id ?? '-1';
2626

2727
useEffect(() => {
28-
CompanyCards.setAssignCardStepAndData({data: {bankName: feed}});
29-
}, [feed]);
28+
return () => {
29+
CompanyCards.clearAssignCardStepAndData();
30+
};
31+
}, []);
3032

3133
switch (currentStep) {
3234
case CONST.COMPANY_CARD.STEP.ASSIGNEE:
@@ -52,8 +54,6 @@ function AssignCardFeedPage({route, policy}: AssignCardFeedPageProps) {
5254
default:
5355
return <AssigneeStep policy={policy} />;
5456
}
55-
56-
return <AssigneeStep policy={policy} />;
5757
}
5858

5959
export default withPolicyAndFullscreenLoading(AssignCardFeedPage);

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

+12-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import useDebouncedState from '@hooks/useDebouncedState';
1313
import useLocalize from '@hooks/useLocalize';
1414
import useNetwork from '@hooks/useNetwork';
1515
import useThemeStyles from '@hooks/useThemeStyles';
16+
import * as CardUtils from '@libs/CardUtils';
1617
import {formatPhoneNumber} from '@libs/LocalePhoneNumber';
1718
import * as OptionsListUtils from '@libs/OptionsListUtils';
1819
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
@@ -35,6 +36,10 @@ function AssigneeStep({policy}: AssigneeStepProps) {
3536
const styles = useThemeStyles();
3637
const {isOffline} = useNetwork();
3738
const [assignCard] = useOnyx(ONYXKEYS.ASSIGN_CARD);
39+
const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policy?.id ?? '-1');
40+
41+
const [list] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${assignCard?.data?.bankName ?? ''}`);
42+
const filteredCardList = CardUtils.getFilteredCardList(list);
3843

3944
const isEditing = assignCard?.isEditing;
4045

@@ -57,8 +62,10 @@ function AssigneeStep({policy}: AssigneeStepProps) {
5762
const personalDetail = PersonalDetailsUtils.getPersonalDetailByEmail(selectedMember);
5863
const memberName = personalDetail?.firstName ? personalDetail.firstName : personalDetail?.login;
5964

65+
const nextStep = CardUtils.hasOnlyOneCardToAssign(filteredCardList) ? CONST.COMPANY_CARD.STEP.TRANSACTION_START_DATE : CONST.COMPANY_CARD.STEP.CARD;
66+
6067
CompanyCards.setAssignCardStepAndData({
61-
currentStep: isEditing ? CONST.COMPANY_CARD.STEP.CONFIRMATION : CONST.COMPANY_CARD.STEP.CARD,
68+
currentStep: isEditing ? CONST.COMPANY_CARD.STEP.CONFIRMATION : nextStep,
6269
data: {
6370
email: selectedMember,
6471
cardName: `${memberName}'s card`,
@@ -69,7 +76,10 @@ function AssigneeStep({policy}: AssigneeStepProps) {
6976

7077
const handleBackButtonPress = () => {
7178
if (isEditing) {
72-
CompanyCards.setAssignCardStepAndData({currentStep: CONST.COMPANY_CARD.STEP.CONFIRMATION, isEditing: false});
79+
CompanyCards.setAssignCardStepAndData({
80+
currentStep: CONST.COMPANY_CARD.STEP.CONFIRMATION,
81+
isEditing: false,
82+
});
7383
return;
7484
}
7585
Navigation.goBack();

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

+2-5
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,8 @@ function CardSelectionStep({feed, policyID}: CardSelectionStepProps) {
4545

4646
const isEditing = assignCard?.isEditing;
4747
const assigneeDisplayName = PersonalDetailsUtils.getPersonalDetailByEmail(assignCard?.data?.email ?? '')?.displayName ?? '';
48-
const {cardList, ...cards} = list ?? {};
49-
// We need to filter out cards which already has been assigned
50-
const filteredCardList = Object.fromEntries(
51-
Object.entries(cardList ?? {}).filter(([cardNumber]) => !Object.values(cards).find((card) => card.lastFourPAN && cardNumber.endsWith(card.lastFourPAN))),
52-
);
48+
const filteredCardList = CardUtils.getFilteredCardList(list);
49+
5350
const [cardSelected, setCardSelected] = useState(assignCard?.data?.encryptedCardNumber ?? '');
5451
const [shouldShowError, setShouldShowError] = useState(false);
5552

src/pages/workspace/members/WorkspaceMemberNewCardPage.tsx

+22-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
2626
import ROUTES from '@src/ROUTES';
2727
import type SCREENS from '@src/SCREENS';
2828
import type {CompanyCardFeed} from '@src/types/onyx';
29+
import type {AssignCardData, AssignCardStep} from '@src/types/onyx/AssignCard';
2930

3031
type CardFeedListItem = ListItem & {
3132
/** Card feed value */
@@ -47,8 +48,12 @@ function WorkspaceMemberNewCardPage({route, personalDetails}: WorkspaceMemberNew
4748

4849
const accountID = Number(route.params.accountID);
4950
const memberLogin = personalDetails?.[accountID]?.login ?? '';
51+
const memberName = personalDetails?.[accountID]?.firstName ? personalDetails?.[accountID]?.firstName : personalDetails?.[accountID]?.login;
5052
const availableCompanyCards = CardUtils.removeExpensifyCardFromCompanyCards(cardFeeds);
5153

54+
const [list] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${selectedFeed}`);
55+
const filteredCardList = CardUtils.getFilteredCardList(list);
56+
5257
const handleSubmit = () => {
5358
if (!selectedFeed) {
5459
setShouldShowError(true);
@@ -64,14 +69,26 @@ function WorkspaceMemberNewCardPage({route, personalDetails}: WorkspaceMemberNew
6469
});
6570
Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID, ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)));
6671
} else {
72+
const data: Partial<AssignCardData> = {
73+
email: memberLogin,
74+
bankName: selectedFeed,
75+
cardName: `${memberName}'s card`,
76+
};
77+
let currentStep: AssignCardStep = CONST.COMPANY_CARD.STEP.CARD;
78+
79+
if (CardUtils.hasOnlyOneCardToAssign(filteredCardList)) {
80+
currentStep = CONST.COMPANY_CARD.STEP.TRANSACTION_START_DATE;
81+
data.cardNumber = Object.keys(filteredCardList).at(0);
82+
data.encryptedCardNumber = Object.values(filteredCardList).at(0);
83+
}
6784
CompanyCards.setAssignCardStepAndData({
68-
currentStep: CONST.COMPANY_CARD.STEP.CARD,
69-
data: {
70-
email: memberLogin,
71-
},
85+
currentStep,
86+
data,
7287
isEditing: false,
7388
});
74-
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ASSIGN_CARD.getRoute(policyID, selectedFeed, ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID)));
89+
Navigation.setNavigationActionToMicrotaskQueue(() =>
90+
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ASSIGN_CARD.getRoute(policyID, selectedFeed, ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(policyID, accountID))),
91+
);
7592
}
7693
};
7794

src/types/onyx/Card.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -180,5 +180,8 @@ type WorkspaceCardsList = Record<string, Card> & {
180180
cardList?: Record<string, string>;
181181
};
182182

183+
/** Card list with only available card */
184+
type FilteredCardList = Record<string, string>;
185+
183186
export default Card;
184-
export type {ExpensifyCardDetails, CardList, IssueNewCard, IssueNewCardStep, IssueNewCardData, WorkspaceCardsList, CardLimitType};
187+
export type {ExpensifyCardDetails, CardList, IssueNewCard, IssueNewCardStep, IssueNewCardData, WorkspaceCardsList, CardLimitType, FilteredCardList};

0 commit comments

Comments
 (0)