From 7517dbc066e5a651c7811410a2a61b79d5b0c763 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 3 Apr 2025 16:45:23 +0200 Subject: [PATCH 01/18] feat: add route for the selector page --- src/ROUTES.ts | 4 + src/SCREENS.ts | 1 + .../ModalStackNavigators/index.tsx | 1 + .../RELATIONS/WORKSPACE_TO_RHP.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 8 +- .../WorkspaceExpensifyCardSelectorPage.tsx | 128 ++++++++++++++++++ 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/pages/workspace/expensifyCard/WorkspaceExpensifyCardSelectorPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 793b26404af4..4e44f02a9817 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1604,6 +1604,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/expensify-card/settings/account', getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/expensify-card/settings/account`, backTo), }, + WORKSPACE_EXPENSIFY_CARD_SELECT_FEED: { + route: 'settings/workspaces/:policyID/expensify-card/select-feed', + getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/expensify-card/select-feed`, backTo), + }, WORKSPACE_EXPENSIFY_CARD_SETTINGS_FREQUENCY: { route: 'settings/workspaces/:policyID/expensify-card/settings/frequency', getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card/settings/frequency` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 13512cd3f6a6..c59692591c0f 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -497,6 +497,7 @@ const SCREENS = { EXPENSIFY_CARD_LIMIT: 'Workspace_ExpensifyCard_Limit', EXPENSIFY_CARD_ISSUE_NEW: 'Workspace_ExpensifyCard_New', EXPENSIFY_CARD_NAME: 'Workspace_ExpensifyCard_Name', + EXPENSIFY_CARD_SELECT_FEED: 'Workspace_ExpensifyCard_Select_Feed', EXPENSIFY_CARD_LIMIT_TYPE: 'Workspace_ExpensifyCard_LimitType', EXPENSIFY_CARD_BANK_ACCOUNT: 'Workspace_ExpensifyCard_BankAccount', EXPENSIFY_CARD_SETTINGS: 'Workspace_ExpensifyCard_Settings', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 09ee31424b50..0cc2ad4418b8 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -562,6 +562,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/expensifyCard/WorkspaceCardSettingsPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceSettlementAccountPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage').default, + [SCREENS.WORKSPACE.EXPENSIFY_CARD_SELECT_FEED]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceExpensifyCardSelectorPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_DETAILS]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceEditCardNamePage').default, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 5654777e003a..2a6090f733f4 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -235,6 +235,7 @@ const WORKSPACE_TO_RHP: Partial['config'] = { [SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT]: { path: ROUTES.WORKSPACE_EXPENSIFY_CARD_SETTINGS_ACCOUNT.route, }, + [SCREENS.WORKSPACE.EXPENSIFY_CARD_SELECT_FEED]: { + path: ROUTES.WORKSPACE_EXPENSIFY_CARD_SELECT_FEED.route, + }, [SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS]: { path: ROUTES.WORKSPACE_COMPANY_CARDS_SETTINGS.route, }, @@ -1277,7 +1280,10 @@ const config: LinkingOptions['config'] = { [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: ROUTES.MONEY_REQUEST_STEP_WAYPOINT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: ROUTES.MONEY_REQUEST_STEP_TAX_RATE.route, - [SCREENS.MONEY_REQUEST.STATE_SELECTOR]: {path: ROUTES.MONEY_REQUEST_STATE_SELECTOR.route, exact: true}, + [SCREENS.MONEY_REQUEST.STATE_SELECTOR]: { + path: ROUTES.MONEY_REQUEST_STATE_SELECTOR.route, + exact: true, + }, [SCREENS.MONEY_REQUEST.STEP_SPLIT_PAYER]: ROUTES.MONEY_REQUEST_STEP_SPLIT_PAYER.route, [SCREENS.MONEY_REQUEST.STEP_ATTENDEES]: ROUTES.MONEY_REQUEST_ATTENDEE.route, [SCREENS.MONEY_REQUEST.STEP_UPGRADE]: ROUTES.MONEY_REQUEST_UPGRADE.route, diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardSelectorPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardSelectorPage.tsx new file mode 100644 index 000000000000..dd7824918ac2 --- /dev/null +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardSelectorPage.tsx @@ -0,0 +1,128 @@ +import React from 'react'; +import {useOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import MenuItem from '@components/MenuItem'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {ListItem} from '@components/SelectionList/types'; +import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; +import useThemeIllustrations from '@hooks/useThemeIllustrations'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {checkIfFeedConnectionIsBroken, filterInactiveCards, getCardFeedIcon, getCompanyFeeds, getCustomOrFormattedFeedName, getSelectedFeed} from '@libs/CardUtils'; +import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types'; +import type {SettingsNavigatorParamList} from '@navigation/types'; +import {isCollectPolicy} from '@libs/PolicyUtils'; +import Navigation from '@navigation/Navigation'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import variables from '@styles/variables'; +import {updateSelectedFeed} from '@userActions/Card'; +import {clearAddNewCardFlow} from '@userActions/CompanyCards'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type CardFeedListItem = ListItem & { + /** Card feed value */ + value: any; +}; + +type WorkspaceExpensifyCardSelectorPageProps = PlatformStackScreenProps; + +function WorkspaceExpensifyCardSelectorPage({route}: WorkspaceExpensifyCardSelectorPageProps) { + const {policyID} = route.params; + const policy = usePolicy(policyID); + const workspaceAccountID = policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID; + + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const illustrations = useThemeIllustrations(); + const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); + const [allFeedsCards] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}`); + const [lastSelectedFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${policyID}`); + const selectedFeed = getSelectedFeed(lastSelectedFeed, cardFeeds); + const companyFeeds = getCompanyFeeds(cardFeeds); + const isCollect = isCollectPolicy(policy); + + const feeds: CardFeedListItem[] = (Object.keys(companyFeeds)).map((feed) => { + const filteredFeedCards = filterInactiveCards(allFeedsCards?.[`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${feed}`]); + const isFeedConnectionBroken = checkIfFeedConnectionIsBroken(filteredFeedCards); + return { + value: feed, + text: getCustomOrFormattedFeedName(feed, cardFeeds?.settings?.companyCardNicknames), + keyForList: feed, + isSelected: feed === selectedFeed, + isDisabled: companyFeeds[feed]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + pendingAction: companyFeeds[feed]?.pendingAction, + brickRoadIndicator: isFeedConnectionBroken ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, + canShowSeveralIndicators: isFeedConnectionBroken, + leftElement: ( + + ), + }; + }); + + const onAddCardsPress = () => { + clearAddNewCardFlow(); + if (isCollect && feeds.length === 1) { + Navigation.navigate( + ROUTES.WORKSPACE_UPGRADE.getRoute(policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.companyCards.alias, ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID)), + ); + return; + } + Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policyID)); + }; + + const goBack = () => Navigation.goBack(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policyID)); + + const selectFeed = (feed: CardFeedListItem) => { + updateSelectedFeed(feed.value, policyID); + goBack(); + }; + + return ( + + + + + } + /> + + + ); +} + +WorkspaceExpensifyCardSelectorPage.displayName = 'WorkspaceExpensifyCardSelectorPage'; + +export default WorkspaceExpensifyCardSelectorPage; From 5b36e01bfa4582444dab0a1dd9e75aa8916ddbc4 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 3 Apr 2025 17:46:41 +0200 Subject: [PATCH 02/18] feat: add a new onyx key for the last selected feed --- src/ONYXKEYS.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 272f81c325ff..b801d1389fbe 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -581,6 +581,9 @@ const ONYXKEYS = { /** Currently displaying feed */ LAST_SELECTED_FEED: 'lastSelectedFeed_', + /** Currently displaying Expensify feed */ + LAST_SELECTED_EXPENSIFY_FEED: 'lastSelectedExpensifyFeed_', + /** Whether the bank account chosen for Expensify Card in on verification waitlist */ NVP_EXPENSIFY_ON_CARD_WAITLIST: 'nvp_expensify_onCardWaitlist_', From b7217c8804e4237b50260818cb1419a6dfac4b84 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 7 Apr 2025 21:20:24 +0200 Subject: [PATCH 03/18] feat: make useDomainFundID return several keys --- src/hooks/useDomainFundID.ts | 45 ++++++++++--------- .../WorkspaceExpensifyCardDetailsPage.tsx | 4 +- .../WorkspaceExpensifyCardPage.tsx | 11 +++-- .../WorkspaceSettlementAccountPage.tsx | 4 +- .../WorkspaceSettlementFrequencyPage.tsx | 4 +- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/hooks/useDomainFundID.ts b/src/hooks/useDomainFundID.ts index 29fe4fb6b3fa..c6476379f285 100644 --- a/src/hooks/useDomainFundID.ts +++ b/src/hooks/useDomainFundID.ts @@ -1,34 +1,35 @@ import {useOnyx} from 'react-native-onyx'; +import {getWorkspaceAccountID} from '@libs/PolicyUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; function useDomainFundID(policyID: string | undefined) { - const [domainFundID] = useOnyx(ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS, { - selector: (cardSettings) => { - const matchingEntry = Object.entries(cardSettings ?? {}).find( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ([_, settings]) => settings?.preferredPolicy && settings.preferredPolicy === policyID, - ); - - if (!matchingEntry) { - return CONST.DEFAULT_NUMBER_ID; - } - - const key = matchingEntry[0]; - const prefix = ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS; - - if (!key.startsWith(prefix)) { - return CONST.DEFAULT_NUMBER_ID; - } + const workspaceAccountID = getWorkspaceAccountID(policyID); + const prefix = ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS; - const accountIDStr = key.substring(prefix.length); - - const accountID = Number(accountIDStr); - return Number.isNaN(accountID) ? CONST.DEFAULT_NUMBER_ID : accountID; + const [domainFundIDs] = useOnyx(ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS, { + selector: (cardSettings) => { + const matchingKeys = Object.entries(cardSettings ?? {}) + .filter( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ([key, settings]) => settings?.preferredPolicy && settings.preferredPolicy === policyID && !key.includes(workspaceAccountID.toString()), + ) + .map(([key]) => { + const accountIDStr = key.substring(prefix.length); + + if (!key?.startsWith(prefix)) { + return undefined; + } + const accountID = Number(accountIDStr); + return Number.isNaN(accountID) ? undefined : accountID; + }); + return matchingKeys; }, }); + console.log(domainFundIDs); + - return domainFundID; + return domainFundIDs; } export default useDomainFundID; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx index d4d3c6bb5c2f..e2aa59faf3b9 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx @@ -45,11 +45,11 @@ type WorkspaceExpensifyCardDetailsPageProps = PlatformStackScreenProps< function WorkspaceExpensifyCardDetailsPage({route}: WorkspaceExpensifyCardDetailsPageProps) { const {policyID, cardID, backTo} = route.params; const workspaceAccountID = useWorkspaceAccountID(policyID); - const domainFundID = useDomainFundID(policyID); + const domainFundIDs = useDomainFundID(policyID); // TODO: add logic for choosing between the domain and workspace feed when both available // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const fundID = domainFundID || workspaceAccountID; + const fundID = domainFundIDs?.[0] || workspaceAccountID; const [isDeactivateModalVisible, setIsDeactivateModalVisible] = useState(false); const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx index 40970656af94..a3208d75c70a 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx @@ -26,13 +26,16 @@ function WorkspaceExpensifyCardPage({route}: WorkspaceExpensifyCardPageProps) { const styles = useThemeStyles(); const theme = useTheme(); - const domainFundID = useDomainFundID(policyID); + const domainFundIDs = useDomainFundID(policyID); // TODO: add logic for choosing between the domain and workspace feed when both available // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const fundID = domainFundID || workspaceAccountID; + const fundID = domainFundIDs?.[0] || workspaceAccountID; const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${fundID}`); const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${fundID}_${CONST.EXPENSIFY_CARD.BANK}`, {selector: filterInactiveCards}); + console.log(cardSettings); + console.log(cardsList); + console.log(domainFundIDs, workspaceAccountID); const fetchExpensifyCards = useCallback(() => { openPolicyExpensifyCardsPage(policyID, fundID); @@ -46,7 +49,7 @@ function WorkspaceExpensifyCardPage({route}: WorkspaceExpensifyCardPageProps) { const isLoading = !isOffline && (!cardSettings || cardSettings.isLoading); const renderContent = () => { - if (!!isLoading && !paymentBankAccountID && !domainFundID) { + if (!!isLoading && !paymentBankAccountID && !domainFundIDs) { return ( ); } - if (!!paymentBankAccountID || domainFundID) { + if (!!paymentBankAccountID || domainFundIDs) { return ( Date: Tue, 8 Apr 2025 09:52:20 +0200 Subject: [PATCH 04/18] feat: get lat selected feed from Onyx --- src/ONYXKEYS.ts | 1 + src/hooks/useDomainFundID.ts | 3 --- .../expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx | 5 ++--- .../expensifyCard/WorkspaceExpensifyCardPage.tsx | 9 +++------ .../expensifyCard/WorkspaceSettlementAccountPage.tsx | 6 +++--- .../expensifyCard/WorkspaceSettlementFrequencyPage.tsx | 5 ++--- src/types/onyx/CardFeeds.ts | 3 +++ src/types/onyx/index.ts | 3 ++- 8 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index b801d1389fbe..c8cc3f6b7bd5 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -940,6 +940,7 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION]: OnyxTypes.PolicyConnectionName; [ONYXKEYS.COLLECTION.EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION]: boolean; [ONYXKEYS.COLLECTION.LAST_SELECTED_FEED]: OnyxTypes.CompanyCardFeed; + [ONYXKEYS.COLLECTION.LAST_SELECTED_EXPENSIFY_FEED]: OnyxTypes.FundID; [ONYXKEYS.COLLECTION.NVP_EXPENSIFY_ON_CARD_WAITLIST]: OnyxTypes.CardOnWaitlist; [ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD]: OnyxTypes.IssueNewCard; }; diff --git a/src/hooks/useDomainFundID.ts b/src/hooks/useDomainFundID.ts index c6476379f285..738786b0eb18 100644 --- a/src/hooks/useDomainFundID.ts +++ b/src/hooks/useDomainFundID.ts @@ -1,6 +1,5 @@ import {useOnyx} from 'react-native-onyx'; import {getWorkspaceAccountID} from '@libs/PolicyUtils'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; function useDomainFundID(policyID: string | undefined) { @@ -26,8 +25,6 @@ function useDomainFundID(policyID: string | undefined) { return matchingKeys; }, }); - console.log(domainFundIDs); - return domainFundIDs; } diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx index e2aa59faf3b9..5b502309229e 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardDetailsPage.tsx @@ -46,10 +46,9 @@ function WorkspaceExpensifyCardDetailsPage({route}: WorkspaceExpensifyCardDetail const {policyID, cardID, backTo} = route.params; const workspaceAccountID = useWorkspaceAccountID(policyID); const domainFundIDs = useDomainFundID(policyID); + const [lastSelectedExpensifyFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_EXPENSIFY_FEED}${policyID}`); - // TODO: add logic for choosing between the domain and workspace feed when both available - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const fundID = domainFundIDs?.[0] || workspaceAccountID; + const fundID = lastSelectedExpensifyFeed ?? domainFundIDs?.[0] ?? workspaceAccountID; const [isDeactivateModalVisible, setIsDeactivateModalVisible] = useState(false); const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx index a3208d75c70a..0684a7cfa577 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx @@ -27,15 +27,12 @@ function WorkspaceExpensifyCardPage({route}: WorkspaceExpensifyCardPageProps) { const styles = useThemeStyles(); const theme = useTheme(); const domainFundIDs = useDomainFundID(policyID); + const [lastSelectedExpensifyFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_EXPENSIFY_FEED}${policyID}`); - // TODO: add logic for choosing between the domain and workspace feed when both available - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const fundID = domainFundIDs?.[0] || workspaceAccountID; + const fundID = lastSelectedExpensifyFeed ?? domainFundIDs?.[0] ?? workspaceAccountID; const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${fundID}`); const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${fundID}_${CONST.EXPENSIFY_CARD.BANK}`, {selector: filterInactiveCards}); - console.log(cardSettings); - console.log(cardsList); - console.log(domainFundIDs, workspaceAccountID); + const fetchExpensifyCards = useCallback(() => { openPolicyExpensifyCardsPage(policyID, fundID); diff --git a/src/pages/workspace/expensifyCard/WorkspaceSettlementAccountPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceSettlementAccountPage.tsx index 2c7b16908419..378a74d02b81 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceSettlementAccountPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceSettlementAccountPage.tsx @@ -36,9 +36,9 @@ function WorkspaceSettlementAccountPage({route}: WorkspaceSettlementAccountPageP const policyID = route.params?.policyID; const workspaceAccountID = useWorkspaceAccountID(policyID); const domainFundIDs = useDomainFundID(policyID); - // TODO: add logic for choosing between the domain and workspace feed when both available - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const fundID = domainFundIDs?.[0] || workspaceAccountID; + const [lastSelectedExpensifyFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_EXPENSIFY_FEED}${policyID}`); + + const fundID = lastSelectedExpensifyFeed ?? domainFundIDs?.[0] ?? workspaceAccountID; const [bankAccountsList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${fundID}`); diff --git a/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx index 283b8caac1ce..94a849a1b01a 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage.tsx @@ -28,10 +28,9 @@ function WorkspaceSettlementFrequencyPage({route}: WorkspaceSettlementFrequencyP const policyID = route.params?.policyID; const workspaceAccountID = useWorkspaceAccountID(policyID); const domainFundIDs = useDomainFundID(policyID); + const [lastSelectedExpensifyFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_EXPENSIFY_FEED}${policyID}`); - // TODO: add logic for choosing between the domain and workspace feed when both available - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const fundID = domainFundIDs?.[0] || workspaceAccountID; + const fundID = lastSelectedExpensifyFeed ?? domainFundIDs?.[0] ?? workspaceAccountID; const [cardSettings] = useOnyx(`${ONYXKEYS.COLLECTION.PRIVATE_EXPENSIFY_CARD_SETTINGS}${fundID}`); diff --git a/src/types/onyx/CardFeeds.ts b/src/types/onyx/CardFeeds.ts index 4886e35ebfce..ab661cd5dd81 100644 --- a/src/types/onyx/CardFeeds.ts +++ b/src/types/onyx/CardFeeds.ts @@ -120,6 +120,8 @@ type AddNewCompanyCardFeed = { isEditing: boolean; }; +type FundID = number; + export default CardFeeds; export type { AddNewCardFeedStep, @@ -133,4 +135,5 @@ export type { CompanyFeeds, CompanyCardNicknames, CompanyCardFeedWithNumber, + FundID }; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index a9eedb0a7d8e..326c057d08dd 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -13,7 +13,7 @@ import type CancellationDetails from './CancellationDetails'; import type Card from './Card'; import type {CardList, IssueNewCard, WorkspaceCardsList} from './Card'; import type CardFeeds from './CardFeeds'; -import type {AddNewCompanyCardFeed, CompanyCardFeed} from './CardFeeds'; +import type {AddNewCompanyCardFeed, CompanyCardFeed, FundID} from './CardFeeds'; import type CardOnWaitlist from './CardOnWaitlist'; import type {CapturedLogs, Log} from './Console'; import type {CorpayFields, CorpayFormField} from './CorpayFields'; @@ -144,6 +144,7 @@ export type { ExpensifyCardBankAccountMetadata, FrequentlyUsedEmoji, Fund, + FundID, FundList, IntroSelected, IOU, From 1b065bca795eb28bdbc5e102fc7c36ccb70e58b8 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 8 Apr 2025 10:17:24 +0200 Subject: [PATCH 05/18] feat: create feed selector component --- src/components/FeedSelector.tsx | 59 +++++++++++++++++++ ...WorkspaceCompanyCardsListHeaderButtons.tsx | 43 +++++--------- 2 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 src/components/FeedSelector.tsx diff --git a/src/components/FeedSelector.tsx b/src/components/FeedSelector.tsx new file mode 100644 index 000000000000..50c92668fc63 --- /dev/null +++ b/src/components/FeedSelector.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import {View} from 'react-native'; +import useThemeStyles from '@hooks/useThemeStyles'; +import variables from '@styles/variables'; +import type IconAsset from '@src/types/utils/IconAsset'; +import CaretWrapper from './CaretWrapper'; +import Icon from './Icon'; +import {PressableWithFeedback} from './Pressable'; +import Text from './Text'; + +type Props = { + /** Function to call when the feed is selected */ + onFeedSelect: () => void; + + /** Icon for the card */ + cardIcon: IconAsset; + + /** Whether to show assign card button */ + shouldChangeLayout?: boolean; + + /** Feed name */ + feedName?: string; + + /** Supporting text */ + supportingText?: string; + + /** Children components */ + children?: React.ReactNode; +}; + +function FeedSelector({onFeedSelect, cardIcon, shouldChangeLayout, feedName, supportingText, children}: Props) { + const styles = useThemeStyles(); + + return ( + + + + + + {feedName} + + {children} + + {supportingText} + + + ); +} + +export default FeedSelector; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx index 37786c6f578c..f4794c7e067c 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx @@ -2,10 +2,9 @@ import React from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; -import CaretWrapper from '@components/CaretWrapper'; +import FeedSelector from '@components/FeedSelector'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import {PressableWithFeedback} from '@components/Pressable'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; @@ -26,7 +25,6 @@ import { isCustomFeed, } from '@libs/CardUtils'; import Navigation from '@navigation/Navigation'; -import variables from '@styles/variables'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {CompanyCardFeed} from '@src/types/onyx'; @@ -67,33 +65,20 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed, shouldS return ( - Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID))} - style={[styles.flexRow, styles.alignItemsCenter, styles.gap3, shouldChangeLayout && styles.mb3]} - accessibilityLabel={formattedFeedName ?? ''} + Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID))} + cardIcon={getCardFeedIcon(selectedFeed, illustrations)} + shouldChangeLayout={shouldChangeLayout} + feedName={formattedFeedName} + supportingText={translate(isCommercialFeed ? 'workspace.companyCards.commercialFeed' : 'workspace.companyCards.directFeed')} > - - - - - {formattedFeedName} - - {checkIfFeedConnectionIsBroken(flatAllCardsList(allFeedsCards, workspaceAccountID), selectedFeed) && ( - - )} - - {translate(isCommercialFeed ? 'workspace.companyCards.commercialFeed' : 'workspace.companyCards.directFeed')} - - - + {checkIfFeedConnectionIsBroken(flatAllCardsList(allFeedsCards, workspaceAccountID), selectedFeed) && ( + + )} + {!!shouldShowAssignCardButton && (