diff --git a/src/CONST/index.ts b/src/CONST/index.ts index e665436d47b7b..b56bc4c2c589e 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -3848,10 +3848,6 @@ const CONST = { MOCK_BANK: 'oauth.mockbank.com', UPLOAD: 'upload', }, - LINK_FEED_TYPE: { - COMPANY_CARD: 'CompanyCard', - EXPENSIFY_CARD: 'ExpensifyCard', - }, FEED_KEY_SEPARATOR: '#', CARD_NUMBER_MASK_CHAR: 'X', STEP_NAMES: ['1', '2', '3', '4'], diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 889b439411127..e3ad99032f8a4 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1065,8 +1065,6 @@ const ONYXKEYS = { MERCHANT_RULE_FORM_DRAFT: 'merchantRuleFormDraft', ADD_DOMAIN_MEMBER_FORM: 'addDomainMemberForm', ADD_DOMAIN_MEMBER_FORM_DRAFT: 'addDomainMemberFormDraft', - ADD_WORK_EMAIL_FORM: 'addWorkEmailForm', - ADD_WORK_EMAIL_FORM_DRAFT: 'addWorkEmailFormDraft', }, DERIVED: { REPORT_ATTRIBUTES: 'reportAttributes', @@ -1206,7 +1204,6 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.EXPENSE_RULE_FORM]: FormTypes.ExpenseRuleForm; [ONYXKEYS.FORMS.MERCHANT_RULE_FORM]: FormTypes.MerchantRuleForm; [ONYXKEYS.FORMS.ADD_DOMAIN_MEMBER_FORM]: FormTypes.AddDomainMemberForm; - [ONYXKEYS.FORMS.ADD_WORK_EMAIL_FORM]: FormTypes.AddWorkEmailForm; }; type OnyxFormDraftValuesMapping = { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 28d2b18b6a0f2..a68c3dd78fe1e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -2584,14 +2584,6 @@ const ROUTES = { getRoute: (policyID: string, cardID: string, feed: CompanyCardFeedWithDomainID) => `workspaces/${policyID}/company-cards/${encodeURIComponent(feed)}/${encodeURIComponent(cardID)}/edit/name` as const, }, - WORKSPACE_COMPANY_CARD_ADD_WORK_EMAIL: { - route: 'workspaces/:policyID/company-cards/:feed/work-email', - getRoute: (policyID: string, feed: CompanyCardFeedWithDomainID) => `workspaces/${policyID}/company-cards/${encodeURIComponent(feed)}/work-email` as const, - }, - WORKSPACE_COMPANY_CARD_VERIFY_WORK_EMAIL: { - route: 'workspaces/:policyID/company-cards/:feed/verify-work-email', - getRoute: (policyID: string, feed: CompanyCardFeedWithDomainID) => `workspaces/${policyID}/company-cards/${encodeURIComponent(feed)}/verify-work-email` as const, - }, WORKSPACE_COMPANY_CARD_EDIT_TRANSACTION_START_DATE: { route: 'workspaces/:policyID/company-cards/:feed/:cardID/edit/transaction-start-date', getRoute: (policyID: string, cardID: string, feed: CompanyCardFeedWithDomainID) => diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 0b34df90b022d..3350a2aa5ab33 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -681,8 +681,6 @@ const SCREENS = { COMPANY_CARDS_SETTINGS_STATEMENT_CLOSE_DATE: 'Workspace_CompanyCards_Settings_Statement_Close_Date', COMPANY_CARD_DETAILS: 'Workspace_CompanyCard_Details', COMPANY_CARD_EDIT_CARD_NAME: 'Workspace_CompanyCard_Edit_Card_Name', - COMPANY_CARD_ADD_WORK_EMAIL: 'Workspace_CompanyCard_Add_Work_Email', - COMPANY_CARD_VERIFY_WORK_EMAIL: 'Workspace_CompanyCard_Verify_Work_Email', COMPANY_CARD_EDIT_TRANSACTION_START_DATE: 'Workspace_CompanyCard_Edit_Transaction_Start_Date', COMPANY_CARD_EXPORT: 'Workspace_CompanyCard_Export', EXPENSIFY_CARD: 'Workspace_ExpensifyCard', diff --git a/src/components/SelectionList/ListItem/RadioListItem.tsx b/src/components/SelectionList/ListItem/RadioListItem.tsx index 5646b32ebd0c8..dbf969f7ceff0 100644 --- a/src/components/SelectionList/ListItem/RadioListItem.tsx +++ b/src/components/SelectionList/ListItem/RadioListItem.tsx @@ -70,7 +70,6 @@ function RadioListItem({ onFocus={onFocus} shouldSyncFocus={shouldSyncFocus} pendingAction={item.pendingAction} - errors={item.errors} shouldHighlightSelectedItem={shouldHighlightSelectedItem} shouldDisableHoverStyle={shouldDisableHoverStyle} accessibilityRole={accessibilityRole} diff --git a/src/hooks/useCardFeeds.tsx b/src/hooks/useCardFeeds.tsx index 7887d49ed578b..658d1641d3846 100644 --- a/src/hooks/useCardFeeds.tsx +++ b/src/hooks/useCardFeeds.tsx @@ -28,12 +28,8 @@ const useCardFeeds = (policyID: string | undefined): [CombinedCardFeeds | undefi let workspaceFeeds: CombinedCardFeeds | undefined; if (policyID && allFeeds) { - const shouldIncludeFeedPredicate = (combinedCardFeed: CombinedCardFeed) => { - if (combinedCardFeed?.linkedPolicyIDs) { - return combinedCardFeed.linkedPolicyIDs.includes(policyID); - } - return combinedCardFeed.preferredPolicy ? combinedCardFeed.preferredPolicy === policyID : combinedCardFeed.domainID === workspaceAccountID; - }; + const shouldIncludeFeedPredicate = (combinedCardFeed: CombinedCardFeed) => + combinedCardFeed.preferredPolicy ? combinedCardFeed.preferredPolicy === policyID : combinedCardFeed.domainID === workspaceAccountID; workspaceFeeds = getCombinedCardFeedsFromAllFeeds(allFeeds, shouldIncludeFeedPredicate, feedKeysWithCards); } diff --git a/src/hooks/useOtherFeedsForFeedSelector.tsx b/src/hooks/useOtherFeedsForFeedSelector.tsx deleted file mode 100644 index d64dc863b4102..0000000000000 --- a/src/hooks/useOtherFeedsForFeedSelector.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import {Str} from 'expensify-common'; -import React from 'react'; -import Icon from '@components/Icon'; -import PlaidCardFeedIcon from '@components/PlaidCardFeedIcon'; -import type {ListItem} from '@components/SelectionList/types'; -import {getCardFeedIcon, getCustomOrFormattedFeedName, getPlaidInstitutionIconUrl} from '@libs/CardUtils'; -import variables from '@styles/variables'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type {CompanyCardFeedWithDomainID, CompanyCardFeedWithNumber} from '@src/types/onyx/CardFeeds'; -import useCardFeedErrors from './useCardFeedErrors'; -import useCardFeedsForActivePolicies from './useCardFeedsForActivePolicies'; -import {useCompanyCardFeedIcons} from './useCompanyCardIcons'; -import useCompanyCards from './useCompanyCards'; -import useLocalize from './useLocalize'; -import useOnyx from './useOnyx'; -import useThemeIllustrations from './useThemeIllustrations'; -import useThemeStyles from './useThemeStyles'; - -type CardFeedListItem = ListItem & { - /** Combined feed key */ - value: CompanyCardFeedWithDomainID; - /** Card feed value */ - feed: CompanyCardFeedWithNumber; - /** Feed fund value */ - fundID?: number; - /** Feed country value */ - country?: string; -}; - -/** - * Returns feed list items for card feeds from other workspaces (not the current policy), - * excluding feeds already linked to the current policy. Used in the workspace company card feed selector. - */ -function useOtherFeedsForFeedSelector(policyID: string): CardFeedListItem[] { - const {translate} = useLocalize(); - const styles = useThemeStyles(); - const illustrations = useThemeIllustrations(); - const companyCardFeedIcons = useCompanyCardFeedIcons(); - const [allDomains] = useOnyx(ONYXKEYS.COLLECTION.DOMAIN); - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const {cardFeedsByPolicy} = useCardFeedsForActivePolicies(); - const {feedName: selectedFeedName} = useCompanyCards({policyID}); - const {shouldShowRbrForFeedNameWithDomainID} = useCardFeedErrors(); - - const getOtherFeeds = () => { - const otherPolicyFeeds: CardFeedListItem[] = []; - for (const [feedPolicyID, cardFeeds] of Object.entries(cardFeedsByPolicy ?? {})) { - for (const feed of cardFeeds) { - if (feed?.linkedPolicyIDs?.includes(policyID)) { - continue; - } - const feedName = feed.feed; - const plaidUrl = getPlaidInstitutionIconUrl(feedName); - const domain = allDomains?.[`${ONYXKEYS.COLLECTION.DOMAIN}${feed.fundID}`]; - const feedPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${feed?.linkedPolicyIDs?.[0] ?? feedPolicyID}`]; - const domainName = domain?.email ? Str.extractEmailDomain(domain.email) : undefined; - const shouldShowRBR = shouldShowRbrForFeedNameWithDomainID[feed.id]; - - otherPolicyFeeds.push({ - value: feed.id as CompanyCardFeedWithDomainID, - feed: feedName as CompanyCardFeedWithNumber, - fundID: Number(feed.fundID), - country: feed?.country, - alternateText: domainName ?? feedPolicy?.name, - text: getCustomOrFormattedFeedName(translate, feedName, feed.name), - keyForList: feed.id, - isSelected: feed.id === selectedFeedName, - brickRoadIndicator: shouldShowRBR ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined, - canShowSeveralIndicators: shouldShowRBR, - leftElement: plaidUrl ? ( - - ) : ( - - ), - }); - } - } - return otherPolicyFeeds; - }; - return getOtherFeeds(); -} - -export default useOtherFeedsForFeedSelector; -export type {CardFeedListItem}; diff --git a/src/hooks/usePrimaryContactMethod.ts b/src/hooks/usePrimaryContactMethod.ts deleted file mode 100644 index e4be551181a81..0000000000000 --- a/src/hooks/usePrimaryContactMethod.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {emailSelector} from '@selectors/Session'; -import ONYXKEYS from '@src/ONYXKEYS'; -import useOnyx from './useOnyx'; - -function usePrimaryContactMethod(): string { - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const [sessionEmail] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector}); - return account?.primaryLogin ?? sessionEmail ?? ''; -} - -export default usePrimaryContactMethod; diff --git a/src/languages/de.ts b/src/languages/de.ts index 9a0616c1ba1d7..7a573575b85d3 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -5051,9 +5051,6 @@ _Für ausführlichere Anweisungen [besuchen Sie unsere Hilfeseite](${CONST.NETSU companyCards: { addCards: 'Karten hinzufügen', selectCards: 'Karten auswählen', - fromOtherWorkspaces: 'Aus anderen Workspaces', - addWorkEmail: 'Fügen Sie Ihre Arbeits-E-Mail hinzu', - addWorkEmailDescription: 'Bitte fügen Sie Ihre Arbeits-E-Mail hinzu, um vorhandene Feeds aus anderen Workspaces zu nutzen.', error: { workspaceFeedsCouldNotBeLoadedTitle: 'Kartendaten konnten nicht geladen werden', workspaceFeedsCouldNotBeLoadedMessage: diff --git a/src/languages/en.ts b/src/languages/en.ts index 506aa727cb1ad..777faddb5e536 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -5074,9 +5074,6 @@ const translations = { companyCards: { addCards: 'Add cards', selectCards: 'Select cards', - fromOtherWorkspaces: 'From other workspaces', - addWorkEmail: 'Add your work email', - addWorkEmailDescription: 'Please add your work email in order to use existing feeds from other workspaces.', error: { workspaceFeedsCouldNotBeLoadedTitle: "Couldn't load card feeds", workspaceFeedsCouldNotBeLoadedMessage: 'An error occurred while loading workspace card feeds. Please try again or contact your administrator.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 8cc4013564018..6fef992803193 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4950,9 +4950,6 @@ ${amount} para ${merchant} - ${date}`, companyCards: { addCards: 'Añadir tarjetas', selectCards: 'Seleccionar tarjetas', - fromOtherWorkspaces: 'De otros espacios de trabajo', - addWorkEmail: 'Añade tu correo electrónico de trabajo', - addWorkEmailDescription: 'Por favor, añade tu correo de trabajo para poder usar los feeds existentes de otros espacios de trabajo.', error: { workspaceFeedsCouldNotBeLoadedTitle: 'Error al cargar las fuentes de tarjetas del espacio de trabajo', workspaceFeedsCouldNotBeLoadedMessage: diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 0602f9ca755e4..78e03a6f00f47 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -5062,9 +5062,6 @@ _Pour des instructions plus détaillées, [visitez notre site d’aide](${CONST. companyCards: { addCards: 'Ajouter des cartes', selectCards: 'Sélectionner des cartes', - fromOtherWorkspaces: "D'autres espaces de travail", - addWorkEmail: 'Ajoutez votre adresse e-mail professionnelle', - addWorkEmailDescription: "Veuillez ajouter votre e-mail professionnel pour utiliser les flux existants d'autres espaces de travail.", error: { workspaceFeedsCouldNotBeLoadedTitle: 'Impossible de charger les flux de cartes', workspaceFeedsCouldNotBeLoadedMessage: diff --git a/src/languages/it.ts b/src/languages/it.ts index ec1dc72b8cf55..bd39b03f6df4c 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -5039,9 +5039,6 @@ _Per istruzioni più dettagliate, [visita il nostro sito di assistenza](${CONST. companyCards: { addCards: 'Aggiungi carte', selectCards: 'Seleziona carte', - fromOtherWorkspaces: 'Da altri spazi di lavoro', - addWorkEmail: 'Aggiungi la tua email di lavoro', - addWorkEmailDescription: 'Aggiungi la tua email di lavoro per utilizzare i feed esistenti di altri spazi di lavoro.', error: { workspaceFeedsCouldNotBeLoadedTitle: 'Impossibile caricare i feed della carta', workspaceFeedsCouldNotBeLoadedMessage: diff --git a/src/languages/ja.ts b/src/languages/ja.ts index b8f1ffe0496b3..e2f628792f832 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -4994,9 +4994,6 @@ _詳しい手順については、[ヘルプサイトをご覧ください](${CO companyCards: { addCards: 'カードを追加', selectCards: 'カードを選択', - fromOtherWorkspaces: '他のワークスペースから', - addWorkEmail: 'あなたの勤務用メールアドレスを追加', - addWorkEmailDescription: '他のワークスペースの既存フィードを使用するには、勤務用メールアドレスを追加してください。', error: { workspaceFeedsCouldNotBeLoadedTitle: 'カードフィードを読み込めませんでした', workspaceFeedsCouldNotBeLoadedMessage: 'ワークスペースカードフィードの読み込み中にエラーが発生しました。もう一度お試しいただくか、管理者にお問い合わせください。', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 2cb3628c6c2f8..ed0dc5ab2cb3d 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -5031,9 +5031,6 @@ _Voor meer gedetailleerde instructies, [bezoek onze help-site](${CONST.NETSUITE_ companyCards: { addCards: 'Kaarten toevoegen', selectCards: 'Kaarten selecteren', - fromOtherWorkspaces: 'Uit andere workspaces', - addWorkEmail: 'Voeg je werkmail toe', - addWorkEmailDescription: 'Voeg je werkmail toe om bestaande feeds van andere workspaces te gebruiken.', error: { workspaceFeedsCouldNotBeLoadedTitle: 'Kaartfeeds konden niet worden geladen', workspaceFeedsCouldNotBeLoadedMessage: 'Er is een fout opgetreden bij het laden van workspacekaartfeeds. Probeer het opnieuw of neem contact op met je beheerder.', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index d7934e9fe99b8..74a94cdab5e94 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -5024,9 +5024,6 @@ _Aby uzyskać bardziej szczegółowe instrukcje, [odwiedź naszą stronę pomocy companyCards: { addCards: 'Dodaj karty', selectCards: 'Wybierz karty', - fromOtherWorkspaces: 'Z innych przestrzeni roboczych', - addWorkEmail: 'Dodaj swój służbowy e-mail', - addWorkEmailDescription: 'Dodaj swój służbowy e-mail, aby korzystać z istniejących kanałów z innych przestrzeni roboczych.', error: { workspaceFeedsCouldNotBeLoadedTitle: 'Nie można wczytać kanałów kart', workspaceFeedsCouldNotBeLoadedMessage: 'Wystąpił błąd podczas ładowania kanałów kart w przestrzeni roboczej. Spróbuj ponownie lub skontaktuj się ze swoim administratorem.', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 6eba72d55b425..a622d315ff058 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -5024,9 +5024,6 @@ _Para instruções mais detalhadas, [visite nossa central de ajuda](${CONST.NETS companyCards: { addCards: 'Adicionar cartões', selectCards: 'Selecionar cartões', - fromOtherWorkspaces: 'De outros workspaces', - addWorkEmail: 'Adicione seu e-mail de trabalho', - addWorkEmailDescription: 'Adicione seu e-mail de trabalho para usar os feeds existentes de outros workspaces.', error: { workspaceFeedsCouldNotBeLoadedTitle: 'Não foi possível carregar os feeds do cartão', workspaceFeedsCouldNotBeLoadedMessage: 'Ocorreu um erro ao carregar os feeds de cartões do workspace. Tente novamente ou contate o seu administrador.', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index ee907759fcc52..b8c2640690633 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -4903,9 +4903,6 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM companyCards: { addCards: '添加卡片', selectCards: '选择卡片', - fromOtherWorkspaces: '来自其他工作区', - addWorkEmail: '添加您的工作邮箱', - addWorkEmailDescription: '请添加您的工作邮箱以使用其他工作区的现有流水。', error: { workspaceFeedsCouldNotBeLoadedTitle: '无法加载卡片流水', workspaceFeedsCouldNotBeLoadedMessage: '加载工作区卡片动态时发生错误。请重试或联系管理员。', diff --git a/src/libs/API/parameters/LinkCardToPolicyParams.ts b/src/libs/API/parameters/LinkCardToPolicyParams.ts deleted file mode 100644 index e79cb1948b7ce..0000000000000 --- a/src/libs/API/parameters/LinkCardToPolicyParams.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type {CardFeedWithNumber} from '@src/types/onyx/CardFeeds'; - -type LinkCardToPolicyParams = { - domainAccountID: number; - policyID: string; - feedName?: CardFeedWithNumber; - feedType: string; - feedCountry?: string; -}; - -export default LinkCardToPolicyParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 1b6ca257a76fd..92386d124ab33 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -108,7 +108,6 @@ export type {default as UpdatePreferredLocaleParams} from './UpdatePreferredLoca export type {default as UpdatePronounsParams} from './UpdatePronounsParams'; export type {default as UpdateSelectedTimezoneParams} from './UpdateSelectedTimezoneParams'; export type {default as UpdateStatusParams} from './UpdateStatusParams'; -export type {default as LinkCardToPolicyParams} from './LinkCardToPolicyParams'; export type {default as UpdateThemeParams} from './UpdateThemeParams'; export type {default as UpdateUserAvatarParams} from './UpdateUserAvatarParams'; export type {default as UpdateGroupChatAvatarParams} from './UpdateGroupChatAvatarParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index a4615daedb865..0543d2922ad19 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -1378,7 +1378,6 @@ const SIDE_EFFECT_REQUEST_COMMANDS = { AUTHORIZE_TRANSACTION: 'AuthorizeTransaction', DENY_TRANSACTION: 'DenyTransaction', GET_TRANSACTIONS_PENDING_3DS_REVIEW: 'GetTransactionsPending3DSReview', - LINK_CARD_FEED_TO_POLICY: 'LinkCardFeedToPolicy', REVEAL_CARD_PIN: 'RevealCardPIN', CHANGE_CARD_PIN: 'ChangeCardPIN', } as const; @@ -1417,7 +1416,6 @@ type SideEffectRequestCommandParameters = { [SIDE_EFFECT_REQUEST_COMMANDS.AUTHORIZE_TRANSACTION]: Parameters.AuthorizeTransactionParams; [SIDE_EFFECT_REQUEST_COMMANDS.DENY_TRANSACTION]: Parameters.DenyTransactionParams; [SIDE_EFFECT_REQUEST_COMMANDS.GET_TRANSACTIONS_PENDING_3DS_REVIEW]: null; - [SIDE_EFFECT_REQUEST_COMMANDS.LINK_CARD_FEED_TO_POLICY]: Parameters.LinkCardToPolicyParams; [SIDE_EFFECT_REQUEST_COMMANDS.REVEAL_CARD_PIN]: Parameters.RevealCardPINParams; [SIDE_EFFECT_REQUEST_COMMANDS.CHANGE_CARD_PIN]: Parameters.ChangeCardPINParams; }; diff --git a/src/libs/CardFeedUtils.ts b/src/libs/CardFeedUtils.ts index fd4b7a26ac92d..2b0b3cec08ac2 100644 --- a/src/libs/CardFeedUtils.ts +++ b/src/libs/CardFeedUtils.ts @@ -44,8 +44,6 @@ type CardFeedForDisplay = { feed: CardFeedWithNumber; fundID: string; name: string; - country?: string; - linkedPolicyIDs?: string[]; }; type CardFeedsForDisplay = Record; @@ -90,16 +88,6 @@ function getWorkspaceCardFeedKey(cardFeedKey: string) { return cardFeedKey; } -/** - * Resolves the display name of a linked policy when preferredPolicy differs from the current policyID. - */ -function getLinkedPolicyName(allPolicies: OnyxCollection, preferredPolicy: string | undefined, currentPolicyID: string, fallbackName: string | undefined): string | undefined { - if (preferredPolicy && preferredPolicy !== currentPolicyID) { - return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${preferredPolicy}`]?.name ?? fallbackName; - } - return fallbackName; -} - function createCardFilterItem( card: Card, personalDetailsList: PersonalDetailsList, @@ -547,17 +535,13 @@ function getCardFeedsForDisplayPerPolicy( for (const [key, feedData] of Object.entries(getOriginalCompanyFeeds(cardFeeds, feedKeysWithCards, Number(fundID)))) { const preferredPolicy = feedData && 'preferredPolicy' in feedData ? (feedData.preferredPolicy ?? '') : ''; - const country = feedData && 'country' in feedData ? (feedData.country ?? '') : ''; - const linkedPolicyIDs = feedData && 'linkedPolicyIDs' in feedData ? feedData.linkedPolicyIDs : undefined; const feed = key as CardFeedWithNumber; const id = `${fundID}_${feed}`; (cardFeedsForDisplayPerPolicy[preferredPolicy] ||= []).push({ id, feed, - country, fundID, - linkedPolicyIDs, name: getCustomOrFormattedFeedName(translate, feed, cardFeeds?.settings?.companyCardNicknames?.[feed], false) ?? feed, }); } @@ -566,26 +550,6 @@ function getCardFeedsForDisplayPerPolicy( return cardFeedsForDisplayPerPolicy; } -/** - * Finds a feed by id in the card feeds grouped by policy. - * - * @param feedId - The feed id (e.g. `${fundID}_${feed}`) to look up - * @param cardFeedsByPolicy - Card feeds per policy from getCardFeedsForDisplayPerPolicy - * @returns The matching CardFeedForDisplay or undefined - */ -function getFeedInfo(feedId: string, cardFeedsByPolicy?: Record): CardFeedForDisplay | undefined { - if (!feedId || !cardFeedsByPolicy) { - return undefined; - } - for (const cardFeeds of Object.values(cardFeedsByPolicy)) { - const found = cardFeeds.find((item) => item.id === feedId); - if (found) { - return found; - } - } - return undefined; -} - function getCardFeedStatus(feed: CardFeeds | undefined): CardFeedsStatus { return { errors: feed?.errors, @@ -671,8 +635,6 @@ export { createCardFeedKey, getCardFeedKey, getWorkspaceCardFeedKey, - getFeedInfo, - getLinkedPolicyName, generateDomainFeedData, getDomainFeedData, getCardFeedsForDisplay, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index e7a413775309a..af2fddd22be3f 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -795,8 +795,6 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/companyCards/BrokenCardFeedConnectionPage').default, [SCREENS.WORKSPACE.COMPANY_CARDS_REFRESH_CARD_FEED_CONNECTION]: () => require('../../../../pages/workspace/companyCards/RefreshCardFeedConnectionPage').default, [SCREENS.WORKSPACE.COMPANY_CARDS_VERIFY_ACCOUNT]: () => require('../../../../pages/workspace/companyCards/WorkspaceCompanyCardsVerifyAccountPage').default, - [SCREENS.WORKSPACE.COMPANY_CARD_ADD_WORK_EMAIL]: () => require('../../../../pages/workspace/companyCards/WorkspaceCompanyCardAddWorkEmailPage').default, - [SCREENS.WORKSPACE.COMPANY_CARD_VERIFY_WORK_EMAIL]: () => require('../../../../pages/workspace/companyCards/WorkspaceVerifyWorkAccountPage').default, [SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD_ASSIGNEE]: () => require('../../../../pages/workspace/companyCards/assignCard/AssigneeStep').default, [SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD_CARD_SELECTION]: () => require('../../../../pages/workspace/companyCards/assignCard/CardSelectionStep').default, [SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD_TRANSACTION_START_DATE]: () => diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 97d78694d8818..51d0aaf4f5b02 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -256,8 +256,6 @@ const WORKSPACE_TO_RHP: Partial['config'] = { [SCREENS.WORKSPACE.COMPANY_CARDS_VERIFY_ACCOUNT]: { path: ROUTES.WORKSPACE_COMPANY_CARDS_VERIFY_ACCOUNT.route, }, - [SCREENS.WORKSPACE.COMPANY_CARD_ADD_WORK_EMAIL]: { - path: ROUTES.WORKSPACE_COMPANY_CARD_ADD_WORK_EMAIL.route, - }, - [SCREENS.WORKSPACE.COMPANY_CARD_VERIFY_WORK_EMAIL]: { - path: ROUTES.WORKSPACE_COMPANY_CARD_VERIFY_WORK_EMAIL.route, - }, [SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD_ASSIGNEE]: { path: ROUTES.WORKSPACE_COMPANY_CARDS_ASSIGN_CARD_ASSIGNEE.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 8c66f0f224b35..e96bbe9950641 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1322,14 +1322,6 @@ type SettingsNavigatorParamList = { /** Present when verifying before a feed refresh; absent when verifying before adding a new feed */ feed?: CompanyCardFeedWithDomainID; }; - [SCREENS.WORKSPACE.COMPANY_CARD_ADD_WORK_EMAIL]: { - policyID: string; - feed: CompanyCardFeedWithDomainID; - }; - [SCREENS.WORKSPACE.COMPANY_CARD_VERIFY_WORK_EMAIL]: { - policyID: string; - feed: CompanyCardFeedWithDomainID; - }; [SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD_ASSIGNEE]: { policyID: string; feed: CompanyCardFeedWithDomainID; diff --git a/src/libs/actions/CompanyCards.ts b/src/libs/actions/CompanyCards.ts index d2c7ff7d58a70..9cba075ff64b1 100644 --- a/src/libs/actions/CompanyCards.ts +++ b/src/libs/actions/CompanyCards.ts @@ -15,7 +15,7 @@ import type { UpdateCardTransactionStartDateParams, UpdateCompanyCardNameParams, } from '@libs/API/parameters'; -import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; +import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as CardUtils from '@libs/CardUtils'; import {getCardFeedWithDomainID} from '@libs/CardUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -28,7 +28,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Card, CardFeeds, CurrencyList, Policy, WorkspaceCardsList} from '@src/types/onyx'; import type {AssignCard, AssignCardData} from '@src/types/onyx/AssignCard'; -import type {ExpensifyCardDetails} from '@src/types/onyx/Card'; import type { AddNewCardFeedData, AddNewCardFeedStep, @@ -320,7 +319,9 @@ function deleteWorkspaceCompanyCardFeed( cardIDs: string[], feedToOpen?: CompanyCardFeedWithDomainID, ) { + const isCustomFeed = CardUtils.isCustomFeed(bankName); const optimisticFeedUpdates = {[bankName]: {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}}; + const successFeedUpdates = {[bankName]: null}; const failureFeedUpdates = {[bankName]: {pendingAction: null, errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}}; const optimisticCardUpdates = Object.fromEntries(cardIDs.map((cardID) => [cardID, {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}])); const successCardUpdates = Object.fromEntries(cardIDs.map((cardID) => [cardID, null])); @@ -355,8 +356,19 @@ function deleteWorkspaceCompanyCardFeed( }, ]; - // Card collections only: API onyxData provides SHARED_NVP on success (avoid merge-after-set on that key). - const successData: Array> = [ + const successData: Array> = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${domainOrWorkspaceAccountID}`, + value: { + settings: { + ...(isCustomFeed ? {companyCards: successFeedUpdates} : {oAuthAccountDetails: successFeedUpdates, companyCards: successFeedUpdates}), + companyCardNicknames: { + [bankName]: null, + }, + }, + }, + }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${domainOrWorkspaceAccountID}_${bankName}`, @@ -1372,29 +1384,6 @@ function clearErrorField(bankName: CompanyCardFeedWithNumber, domainAccountID: n }); } -function linkCardFeedToPolicy(domainAccountID: number, policyID: string, feedType: string, feedCountry?: string, feedName?: CompanyCardFeedWithNumber) { - return new Promise((resolve, reject) => { - const parameters = { - policyID, - domainAccountID, - feedType, - feedName, - feedCountry: feedCountry && feedCountry.length > 0 ? feedCountry : CONST.COUNTRY.US, - }; - // eslint-disable-next-line rulesdir/no-api-side-effects-method - API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.LINK_CARD_FEED_TO_POLICY, parameters) - .then((response) => { - if (response?.jsonCode !== CONST.JSON_CODE.SUCCESS) { - // eslint-disable-next-line prefer-promise-reject-errors - reject('common.genericErrorMessage'); - return; - } - resolve(response as ExpensifyCardDetails); - }) - // eslint-disable-next-line prefer-promise-reject-errors - .catch(() => reject('common.genericErrorMessage')); - }); -} export { setWorkspaceCompanyCardFeedName, deleteWorkspaceCompanyCardFeed, @@ -1421,7 +1410,6 @@ export { importCSVCompanyCards, clearErrorField, clearAssignCardErrors, - linkCardFeedToPolicy, seedCardFeedRefresh, startCardFeedRefresh, }; diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index e161fa3572414..f634e05075386 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -1050,7 +1050,6 @@ function generateStatementPDF(period: string) { /** * Sets a contact method / secondary login as the user's "Default" contact method. - * @param skipNavigation - When true, do not navigate (caller handles navigation, e.g. via useEffect when primaryContactMethod updates). */ function setContactMethodAsDefault( currentUserPersonalDetails: OnyxEntry, @@ -1058,7 +1057,6 @@ function setContactMethodAsDefault( newDefaultContactMethod: string, formatPhoneNumber: LocaleContextProps['formatPhoneNumber'], backTo?: string, - skipNavigation?: boolean, ) { const oldDefaultContactMethod = currentEmail; const optimisticData: Array< @@ -1213,9 +1211,7 @@ function setContactMethodAsDefault( successData, failureData, }); - if (!skipNavigation) { - Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); - } + Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); } function updateTheme(theme: ValueOf, shouldGoBack = true) { diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardAddWorkEmailPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardAddWorkEmailPage.tsx deleted file mode 100644 index c77e45c9ef085..0000000000000 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardAddWorkEmailPage.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import {PUBLIC_DOMAINS_SET, Str} from 'expensify-common'; -import React, {useEffect, useRef, useState} from 'react'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import type {FormOnyxValues} from '@components/Form/types'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import type {AnimatedTextInputRef} from '@components/RNTextInput'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Text from '@components/Text'; -import TextInput from '@components/TextInput'; -import useCardFeedsForActivePolicies from '@hooks/useCardFeedsForActivePolicies'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import useLocalize from '@hooks/useLocalize'; -import useNetwork from '@hooks/useNetwork'; -import useOnyx from '@hooks/useOnyx'; -import usePrimaryContactMethod from '@hooks/usePrimaryContactMethod'; -import useThemeStyles from '@hooks/useThemeStyles'; -import {setContactMethodAsDefault} from '@libs/actions/User'; -import {getFeedInfo} from '@libs/CardFeedUtils'; -import {getCardFeedWithDomainID} from '@libs/CardUtils'; -import {addErrorMessage} from '@libs/ErrorUtils'; -import Log from '@libs/Log'; -import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import {isValidEmail} from '@libs/ValidationUtils'; -import Navigation from '@navigation/Navigation'; -import type {SettingsNavigatorParamList} from '@navigation/types'; -import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; -import {updateSelectedFeed} from '@userActions/Card'; -import {linkCardFeedToPolicy} from '@userActions/CompanyCards'; -import {AddWorkEmail} from '@userActions/Session'; -import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; -import INPUT_IDS from '@src/types/form/AddWorkEmailForm'; -import type {CompanyCardFeedWithDomainID} from '@src/types/onyx'; -import type {CompanyCardFeedWithNumber} from '@src/types/onyx/CardFeeds'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; - -type WorkspaceCompanyCardAddWorkEmailPageProps = PlatformStackScreenProps; - -function WorkspaceCompanyCardAddWorkEmailPage({route}: WorkspaceCompanyCardAddWorkEmailPageProps) { - const {policyID, feed} = route.params; - const primaryContactMethod = usePrimaryContactMethod(); - const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const {isOffline} = useNetwork(); - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const [loading, setLoading] = useState(false); - const {cardFeedsByPolicy} = useCardFeedsForActivePolicies(); - const feedInfo = getFeedInfo(feed, cardFeedsByPolicy); - - const {translate, formatPhoneNumber} = useLocalize(); - const styles = useThemeStyles(); - const [email, setEmail] = React.useState(''); - const emailLoginKey = email ? Object.keys(loginList ?? {}).find((login) => login.toLowerCase() === email.toLowerCase()) : undefined; - const isWorkEmailValidated = emailLoginKey ? !!loginList?.[emailLoginKey]?.validatedDate : false; - - const emailInputRef = useRef(null); - - const handleSubmit = (values: FormOnyxValues) => { - const submittedEmail = values[INPUT_IDS.EMAIL].trim(); - const existingLoginKey = Object.keys(loginList ?? {}).find((login) => login.toLowerCase() === submittedEmail.toLowerCase()); - const isExistingLoginValidated = existingLoginKey ? !!loginList?.[existingLoginKey]?.validatedDate : false; - - if (existingLoginKey) { - if (!isExistingLoginValidated) { - setEmail(submittedEmail); - Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARD_VERIFY_WORK_EMAIL.getRoute(policyID, feed)); - return; - } - setContactMethodAsDefault(currentUserPersonalDetails, allPolicies, existingLoginKey, formatPhoneNumber, undefined, true); - if (!feedInfo) { - setEmail(submittedEmail); - return; - } - setLoading(true); - const feedValue = getCardFeedWithDomainID(feedInfo.feed, feedInfo.fundID) as CompanyCardFeedWithDomainID; - linkCardFeedToPolicy(Number(feedInfo.fundID), policyID, CONST.COMPANY_CARD.LINK_FEED_TYPE.COMPANY_CARD, feedInfo?.country, feedInfo.feed as CompanyCardFeedWithNumber) - .then(() => { - updateSelectedFeed(feedValue, policyID); - Navigation.closeRHPFlow(); - }) - .catch((error: TranslationPaths) => { - addErrorMessage({}, INPUT_IDS.EMAIL, translate(error)); - }) - .finally(() => { - setLoading(false); - }); - } else { - AddWorkEmail(submittedEmail); - } - setEmail(submittedEmail); - }; - - useEffect(() => { - if (!email || !primaryContactMethod || primaryContactMethod.toLowerCase() !== email.toLowerCase() || isWorkEmailValidated) { - return; - } - Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARD_VERIFY_WORK_EMAIL.getRoute(policyID, feed)); - }, [primaryContactMethod, email, policyID, feed, isWorkEmailValidated]); - - const validate = (values: FormOnyxValues): Errors => { - const errors = {}; - const userEmail = values.email; - const emailParts = userEmail.split('@'); - const domain = emailParts.at(1) ?? ''; - - if (!values.email) { - addErrorMessage(errors, INPUT_IDS.EMAIL, translate('common.error.fieldRequired')); - } else if (values.email.length > CONST.LOGIN_CHARACTER_LIMIT) { - addErrorMessage(errors, INPUT_IDS.EMAIL, translate('common.error.characterLimitExceedCounter', values.email.length, CONST.LOGIN_CHARACTER_LIMIT)); - } else if ((!Str.isValidEmail(userEmail) || PUBLIC_DOMAINS_SET.has(domain.toLowerCase())) && !isOffline) { - Log.hmmm('User is trying to add an invalid work email', {userEmail, domain}); - addErrorMessage(errors, INPUT_IDS.EMAIL, translate('onboarding.workEmailValidationError.publicEmail')); - } - - if (isOffline ?? false) { - addErrorMessage(errors, INPUT_IDS.EMAIL, translate('onboarding.workEmailValidationError.offline')); - } - - const isEmailInvalid = !!values.email && !isValidEmail(values.email); - - if (isEmailInvalid) { - addErrorMessage(errors, INPUT_IDS.EMAIL, translate('messages.errorMessageInvalidEmail')); - } - return errors; - }; - - return ( - - - - {translate('workspace.companyCards.addWorkEmail')} - {translate('workspace.companyCards.addWorkEmailDescription')} - - - - - - ); -} - -export default WorkspaceCompanyCardAddWorkEmailPage; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx index 83fed8579ca1b..55f766922240a 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx @@ -1,6 +1,6 @@ import {isUserValidatedSelector} from '@selectors/Account'; import {Str} from 'expensify-common'; -import React, {useState} from 'react'; +import React from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import MenuItem from '@components/MenuItem'; @@ -8,7 +8,7 @@ import PlaidCardFeedIcon from '@components/PlaidCardFeedIcon'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/ListItem/RadioListItem'; -import Text from '@components/Text'; +import type {ListItem} from '@components/SelectionList/types'; import useCardFeedErrors from '@hooks/useCardFeedErrors'; import type {CombinedCardFeed, CompanyCardFeedWithDomainID} from '@hooks/useCardFeeds'; import {useCompanyCardFeedIcons} from '@hooks/useCompanyCardIcons'; @@ -16,32 +16,31 @@ import useCompanyCards from '@hooks/useCompanyCards'; import useIsBlockedToAddFeed from '@hooks/useIsBlockedToAddFeed'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; -import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; -import useOtherFeedsForFeedSelector from '@hooks/useOtherFeedsForFeedSelector'; -import type {CardFeedListItem} from '@hooks/useOtherFeedsForFeedSelector'; import usePolicy from '@hooks/usePolicy'; -import usePrimaryContactMethod from '@hooks/usePrimaryContactMethod'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getLinkedPolicyName} from '@libs/CardFeedUtils'; -import {getCardFeedIcon, getCardFeedWithDomainID, getCustomOrFormattedFeedName, getPlaidInstitutionIconUrl} from '@libs/CardUtils'; -import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; -import {isEmailPublicDomain} from '@libs/LoginUtils'; +import {getCardFeedIcon, getCustomOrFormattedFeedName, getPlaidInstitutionIconUrl} from '@libs/CardUtils'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import Navigation from '@navigation/Navigation'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import variables from '@styles/variables'; import {updateSelectedFeed} from '@userActions/Card'; -import {clearAddNewCardFlow, linkCardFeedToPolicy} from '@userActions/CompanyCards'; +import {clearAddNewCardFlow} from '@userActions/CompanyCards'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {CompanyCardFeedWithNumber} from '@src/types/onyx/CardFeeds'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; + +type CardFeedListItem = ListItem & { + /** Combined feed key */ + value: CompanyCardFeedWithDomainID; + + /** Card feed value */ + feed: CompanyCardFeedWithNumber; +}; type WorkspaceCompanyCardFeedSelectorPageProps = PlatformStackScreenProps; @@ -50,24 +49,16 @@ function WorkspaceCompanyCardFeedSelectorPage({route}: WorkspaceCompanyCardFeedS const policy = usePolicy(policyID); const {translate} = useLocalize(); - const {isOffline} = useNetwork(); const [allDomains] = useOnyx(ONYXKEYS.COLLECTION.DOMAIN); const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector}); - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); const styles = useThemeStyles(); const illustrations = useThemeIllustrations(); const companyCardFeedIcons = useCompanyCardFeedIcons(); const {isBlockedToAddNewFeeds} = useIsBlockedToAddFeed(policyID); const icons = useMemoizedLazyExpensifyIcons(['Plus']); - const [feedWithError, setFeedWithError] = useState<{feed?: string; error?: Errors} | undefined>(undefined); const {companyCardFeeds, feedName: selectedFeedName} = useCompanyCards({policyID}); const {shouldShowRbrForFeedNameWithDomainID} = useCardFeedErrors(); - const otherFeeds = useOtherFeedsForFeedSelector(policyID); - const primaryContactMethod = usePrimaryContactMethod(); - - const isUserFromPublicDomain = isEmailPublicDomain(primaryContactMethod); const feeds: CardFeedListItem[] = (Object.entries(companyCardFeeds ?? {}) as Array<[CompanyCardFeedWithDomainID, CombinedCardFeed]>).map(([feedName, feedSettings]) => { const plaidUrl = getPlaidInstitutionIconUrl(feedSettings.feed); @@ -76,12 +67,10 @@ function WorkspaceCompanyCardFeedSelectorPage({route}: WorkspaceCompanyCardFeedS const shouldShowRBR = shouldShowRbrForFeedNameWithDomainID[feedName]; - const policyName = getLinkedPolicyName(allPolicies, feedSettings?.preferredPolicy, policyID, policy?.name); - return { value: feedName, feed: feedSettings.feed as CompanyCardFeedWithNumber, - alternateText: domainName ?? policyName, + alternateText: domainName ?? policy?.name, text: getCustomOrFormattedFeedName(translate, feedSettings.feed, feedSettings.customFeedName), keyForList: feedName, isSelected: feedName === selectedFeedName, @@ -127,69 +116,6 @@ function WorkspaceCompanyCardFeedSelectorPage({route}: WorkspaceCompanyCardFeedS goBack(); }; - const selectOtherFeed = (feed: CardFeedListItem) => { - if (isUserFromPublicDomain) { - Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARD_ADD_WORK_EMAIL.getRoute(policyID, feed.value)); - return; - } - const primaryLoginKey = primaryContactMethod ? Object.keys(loginList ?? {}).find((login) => login.toLowerCase() === primaryContactMethod.toLowerCase()) : undefined; - const isPrimaryContactValidated = primaryLoginKey ? !!loginList?.[primaryLoginKey]?.validatedDate : !primaryContactMethod; - if (!isPrimaryContactValidated) { - Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARD_VERIFY_WORK_EMAIL.getRoute(policyID, feed.value)); - return; - } - if (!feed.fundID) { - return; - } - const feedValue = getCardFeedWithDomainID(feed.feed, feed.fundID) as CompanyCardFeedWithDomainID; - linkCardFeedToPolicy(feed.fundID, policyID, CONST.COMPANY_CARD.LINK_FEED_TYPE.COMPANY_CARD, feed?.country, feed.feed) - .then(() => { - updateSelectedFeed(feedValue, policyID); - goBack(); - }) - .catch((error: TranslationPaths) => { - setFeedWithError({ - feed: feed.value, - error: getMicroSecondOnyxErrorWithTranslationKey(error), - }); - }); - }; - - const onDismissError = () => { - setFeedWithError(undefined); - }; - - const otherMenuItemFeeds = ( - <> - - {otherFeeds.length > 0 && ( - <> - {translate('workspace.companyCards.fromOtherWorkspaces')} - {otherFeeds.map((feed) => { - const isFeedWithError = feedWithError?.feed === feed.value; - const itemWithError = isFeedWithError && feedWithError?.error ? {...feed, errors: feedWithError.error} : feed; - return ( - - ); - })} - - )} - - ); - return ( - {feeds.length ? ( - - ) : ( - otherMenuItemFeeds - )} + + } + /> ); diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx index 7942c036cf6ef..f3c68cd85873a 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx @@ -8,7 +8,6 @@ import Text from '@components/Text'; import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useOtherFeedsForFeedSelector from '@hooks/useOtherFeedsForFeedSelector'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -38,7 +37,6 @@ function WorkspaceCompanyCardPageEmptyState({policyID, shouldShowGBDisclaimer}: const policy = usePolicy(policyID); const workspaceAccountID = policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID; const shouldShowExpensifyCardPromotionBanner = !hasIssuedExpensifyCard(workspaceAccountID, allWorkspaceCards); - const otherFeeds = useOtherFeedsForFeedSelector(policyID); const illustrations = useMemoizedLazyIllustrations([ 'CreditCardsNew', @@ -98,10 +96,6 @@ function WorkspaceCompanyCardPageEmptyState({policyID, shouldShowGBDisclaimer}: Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_VERIFY_ACCOUNT.getRoute(policy.id)); return; } - if (otherFeeds.length > 0) { - Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policy.id)); - return; - } clearAddNewCardFlow(); Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policy.id)); }; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx index 8c17b44554d66..7635bf993c267 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx @@ -18,7 +18,6 @@ import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getLinkedPolicyName} from '@libs/CardFeedUtils'; import {getCompanyFeeds, getCustomOrFormattedFeedName, getPlaidCountry, getPlaidInstitutionId, isCustomFeed} from '@libs/CardUtils'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import Navigation from '@navigation/Navigation'; @@ -65,7 +64,6 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading, const currentFeedData = feedName ? companyFeeds?.[feedName] : undefined; const [domain] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${currentFeedData?.domainID}`); const [countryByIp] = useOnyx(ONYXKEYS.COUNTRY); - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const {cardFeedErrors} = useCardFeedErrors(); const feedErrors = cardFeedErrors[feedName]; @@ -110,8 +108,7 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading, const isCsvFeed = feedName?.includes(CONST.COMPANY_CARD.FEED_BANK_NAME.CSV); const firstPart = translate(isCommercialFeed ? 'workspace.companyCards.commercialFeed' : 'workspace.companyCards.directFeed'); const domainName = domain?.email ? Str.extractEmailDomain(domain.email) : undefined; - const policyName = getLinkedPolicyName(allPolicies, currentFeedData?.preferredPolicy, policyID, policy?.name); - const secondPart = ` (${domainName ?? policyName})`; + const secondPart = ` (${domainName ?? policy?.name})`; const supportingText = isCsvFeed ? translate('cardPage.csvCardDescription') : `${firstPart}${secondPart}`; const shouldShowNarrowLayout = shouldUseNarrowLayout || isMediumScreenWidth; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx index a552e7e45a6ff..f7272512eead3 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx @@ -118,9 +118,7 @@ function WorkspaceCompanyCardsTable({ // If we already have fetched cards, then do not show skeleton loader (let the remaining updates refresh in the background), else show it const hasCards = (companyCardEntries ?? []).length > 0; - // When the last feed is removed, card data already implies no feed (isNoFeed); lastSelectedFeed Onyx metadata can still report loading after optimistic clear. - const isLoadingFeed = - !hasCards && ((!feedName && isInitiallyLoadingFeeds) || !isPolicyLoaded || (!isNoFeed && isLoadingOnyxValue(lastSelectedFeedMetadata)) || !!selectedFeedStatus?.isLoading); + const isLoadingFeed = !hasCards && ((!feedName && isInitiallyLoadingFeeds) || !isPolicyLoaded || isLoadingOnyxValue(lastSelectedFeedMetadata) || !!selectedFeedStatus?.isLoading); const isLoadingCards = !hasCards ? isLoadingOnyxValue(cardListMetadata) : false; const isLoadingPage = !isOffline && !hasCards && (isLoadingFeed || isLoadingOnyxValue(personalDetailsMetadata) || areWorkspaceCardFeedsLoading); diff --git a/src/pages/workspace/companyCards/WorkspaceVerifyWorkAccountPage.tsx b/src/pages/workspace/companyCards/WorkspaceVerifyWorkAccountPage.tsx deleted file mode 100644 index 86061d66cfefa..0000000000000 --- a/src/pages/workspace/companyCards/WorkspaceVerifyWorkAccountPage.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent'; -import useCardFeedsForActivePolicies from '@hooks/useCardFeedsForActivePolicies'; -import useLocalize from '@hooks/useLocalize'; -import useOnyx from '@hooks/useOnyx'; -import usePrimaryContactMethod from '@hooks/usePrimaryContactMethod'; -import {getFeedInfo} from '@libs/CardFeedUtils'; -import {getCardFeedWithDomainID} from '@libs/CardUtils'; -import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; -import Navigation from '@navigation/Navigation'; -import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types'; -import type {SettingsNavigatorParamList} from '@navigation/types'; -import {updateSelectedFeed} from '@userActions/Card'; -import {linkCardFeedToPolicy} from '@userActions/CompanyCards'; -import {clearGetAccessiblePoliciesErrors, getAccessiblePolicies} from '@userActions/Policy/Policy'; -import {resendValidateCode} from '@userActions/User'; -import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type SCREENS from '@src/SCREENS'; -import type {CompanyCardFeedWithDomainID, CompanyCardFeedWithNumber} from '@src/types/onyx/CardFeeds'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; - -type WorkspaceVerifyWorkAccountPageProps = PlatformStackScreenProps; - -function WorkspaceVerifyWorkAccountPage({route}: WorkspaceVerifyWorkAccountPageProps) { - const {policyID, feed} = route.params; - const {translate} = useLocalize(); - const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); - const workEmail = usePrimaryContactMethod(); - - const [getAccessiblePoliciesAction] = useOnyx(ONYXKEYS.VALIDATE_USER_AND_GET_ACCESSIBLE_POLICIES); - const {cardFeedsByPolicy} = useCardFeedsForActivePolicies(); - const isWorkEmailValidated = workEmail ? !!loginList?.[workEmail]?.validatedDate : false; - const feedInfo = getFeedInfo(feed, cardFeedsByPolicy); - const [feedWithError, setFeedWithError] = useState<{error?: Errors} | undefined>(undefined); - const [loading, setLoading] = useState(false); - - const sendValidateCode = () => { - if (!workEmail) { - return; - } - resendValidateCode(workEmail); - }; - - const validateAccountAndMerge = (validateCode: string) => { - getAccessiblePolicies(validateCode); - }; - - const onDismissError = () => { - setFeedWithError(undefined); - }; - - useEffect(() => { - if (!feedInfo) { - return; - } - if (isWorkEmailValidated) { - setLoading(true); - const feedValue = getCardFeedWithDomainID(feedInfo.feed, feedInfo.fundID) as CompanyCardFeedWithDomainID; - linkCardFeedToPolicy(Number(feedInfo.fundID), policyID, CONST.COMPANY_CARD.LINK_FEED_TYPE.COMPANY_CARD, feedInfo?.country, feedInfo.feed as CompanyCardFeedWithNumber) - .then(() => { - updateSelectedFeed(feedValue, policyID); - Navigation.closeRHPFlow(); - }) - .catch((error: TranslationPaths) => { - setFeedWithError({ - error: getMicroSecondOnyxErrorWithTranslationKey(error), - }); - }) - .finally(() => { - setLoading(false); - }); - } - }, [feed, feedInfo, isWorkEmailValidated, policyID]); - - return ( - { - Navigation.goBack(); - }} - /> - ); -} - -export default WorkspaceVerifyWorkAccountPage; diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 046bf1d7fe220..e4d7a0473f6b6 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -55,8 +55,6 @@ type PolicyRouteName = | typeof SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW | typeof SCREENS.WORKSPACE.COMPANY_CARDS_BROKEN_CARD_FEED_CONNECTION | typeof SCREENS.WORKSPACE.COMPANY_CARDS_REFRESH_CARD_FEED_CONNECTION - | typeof SCREENS.WORKSPACE.COMPANY_CARD_ADD_WORK_EMAIL - | typeof SCREENS.WORKSPACE.COMPANY_CARD_VERIFY_WORK_EMAIL | typeof SCREENS.WORKSPACE.ACCOUNTING.CLAIM_OFFER | typeof SCREENS.WORKSPACE.TIME_TRACKING; diff --git a/src/types/form/AddWorkEmailForm.ts b/src/types/form/AddWorkEmailForm.ts deleted file mode 100644 index 31f9a9b1bec20..0000000000000 --- a/src/types/form/AddWorkEmailForm.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type {ValueOf} from 'type-fest'; -import type Form from './Form'; - -const INPUT_IDS = { - EMAIL: 'email', -} as const; - -type InputID = ValueOf; - -type AddWorkEmailForm = Form< - InputID, - { - [INPUT_IDS.EMAIL]: string; - } ->; - -export type {AddWorkEmailForm}; -export default INPUT_IDS; diff --git a/src/types/form/index.ts b/src/types/form/index.ts index 72b9146ee875a..0147f8d4fedc6 100644 --- a/src/types/form/index.ts +++ b/src/types/form/index.ts @@ -118,4 +118,3 @@ export type {MerchantRuleForm} from './MerchantRuleForm'; export type {AddDomainMemberForm} from './AddDomainMemberForm'; export type {WorkspaceTimeTrackingDefaultRateForm} from './WorkspaceTimeTrackingDefaultRateForm'; export type {EditExpensifyCardLimitTypeForm} from './EditExpensifyCardLimitTypeForm'; -export type {AddWorkEmailForm} from './AddWorkEmailForm'; diff --git a/src/types/onyx/CardFeeds.ts b/src/types/onyx/CardFeeds.ts index 21516fd27ce74..5cc9ab100ce93 100644 --- a/src/types/onyx/CardFeeds.ts +++ b/src/types/onyx/CardFeeds.ts @@ -99,9 +99,6 @@ type CustomCardFeedData = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** Preferred policy */ preferredPolicy?: string; - /** Linked policy IDs */ - linkedPolicyIDs?: string[]; - /** Country associated with this feed (ISO 3166-1 alpha-2 code) */ country?: string; diff --git a/tests/unit/CardFeedUtilsTest.ts b/tests/unit/CardFeedUtilsTest.ts index a7f9cfe59c3f1..2cdc5d8c3494c 100644 --- a/tests/unit/CardFeedUtilsTest.ts +++ b/tests/unit/CardFeedUtilsTest.ts @@ -1,13 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type {OnyxCollection} from 'react-native-onyx'; -import { - getCardFeedNamesWithType, - getCardFeedsForDisplay, - getCardFeedsForDisplayPerPolicy, - getExpensifyCardFeedsForDisplay, - getFeedInfo, - getSelectedCardsFromFeeds, -} from '@libs/CardFeedUtils'; +import {getCardFeedNamesWithType, getCardFeedsForDisplay, getCardFeedsForDisplayPerPolicy, getExpensifyCardFeedsForDisplay, getSelectedCardsFromFeeds} from '@libs/CardFeedUtils'; import CONST from '@src/CONST'; import IntlStore from '@src/languages/IntlStore'; import type {CardFeeds, CardList, CompanyCardFeed, WorkspaceCardsList} from '@src/types/onyx'; @@ -158,105 +151,12 @@ describe('Card Feed Utils', () => { it('returns card feeds grouped per policy', () => { const cardFeedsForDisplayPerPolicy = getCardFeedsForDisplayPerPolicy(cardFeedsMock, translateLocal); expect(cardFeedsForDisplayPerPolicy).toEqual({ - '': [ - {id: '1234_oauth.americanexpressfdx.com 1001', fundID: '1234', feed: 'oauth.americanexpressfdx.com 1001', name: 'American Express', linkedPolicyIDs: undefined, country: ''}, - ], + '': [{id: '1234_oauth.americanexpressfdx.com 1001', fundID: '1234', feed: 'oauth.americanexpressfdx.com 1001', name: 'American Express'}], AA1BB2CC3: [ - {id: '1234_vcf', fundID: '1234', feed: 'vcf', name: 'Custom feed name', linkedPolicyIDs: undefined, country: ''}, - {id: '1234_oauth.citibank.com', fundID: '1234', feed: 'oauth.citibank.com', name: 'Citibank', linkedPolicyIDs: undefined, country: ''}, + {id: '1234_vcf', fundID: '1234', feed: 'vcf', name: 'Custom feed name'}, + {id: '1234_oauth.citibank.com', fundID: '1234', feed: 'oauth.citibank.com', name: 'Citibank'}, ], - XX1YY2ZZ3: [{id: '1234_stripe', fundID: '1234', feed: 'stripe', name: 'Stripe', linkedPolicyIDs: undefined, country: ''}], - }); - }); - - it('returns card feeds with country when feed has country in company cards settings', () => { - const cardFeedsWithCountry: OnyxCollection = { - sharedNVP_private_domain_member_1234: { - settings: { - companyCardNicknames: {}, - companyCards: { - [cardFeedVisaMock]: {preferredPolicy: 'POL1', country: 'US'}, - }, - }, - }, - }; - const result = getCardFeedsForDisplayPerPolicy(cardFeedsWithCountry, translateLocal); - expect(result.POL1).toHaveLength(1); - expect(result.POL1?.at(0)?.country).toBe('US'); - expect(result.POL1?.at(0)?.id).toBe('1234_vcf'); - }); - - it('returns card feeds with linkedPolicyIDs when feed has linkedPolicyIDs in company cards settings', () => { - const linkedPolicyIDs = ['POLICY_A', 'POLICY_B']; - const cardFeedsWithLinkedPolicies: OnyxCollection = { - sharedNVP_private_domain_member_1234: { - settings: { - companyCardNicknames: {}, - companyCards: { - [cardFeedStripeMock]: {preferredPolicy: 'POL2', linkedPolicyIDs}, - }, - }, - }, - }; - const result = getCardFeedsForDisplayPerPolicy(cardFeedsWithLinkedPolicies, translateLocal); - expect(result.POL2).toHaveLength(1); - expect(result.POL2?.at(0)?.linkedPolicyIDs).toEqual(linkedPolicyIDs); - expect(result.POL2?.at(0)?.id).toBe('1234_stripe'); - }); -}); - -describe('getFeedInfo', () => { - const cardFeedsByPolicy = getCardFeedsForDisplayPerPolicy(cardFeedsMock, translateLocal); - - it('returns undefined when feedId is empty', () => { - expect(getFeedInfo('', cardFeedsByPolicy)).toBeUndefined(); - }); - - it('returns undefined when cardFeedsByPolicy is undefined', () => { - expect(getFeedInfo('1234_vcf', undefined)).toBeUndefined(); - }); - - it('returns undefined when cardFeedsByPolicy is empty', () => { - expect(getFeedInfo('1234_vcf', {})).toBeUndefined(); - }); - - it('returns undefined when feedId does not match any feed', () => { - expect(getFeedInfo('9999_nonexistent', cardFeedsByPolicy)).toBeUndefined(); - }); - - it('returns the feed when found in first policy', () => { - const result = getFeedInfo('1234_oauth.americanexpressfdx.com 1001', cardFeedsByPolicy); - expect(result).toEqual({ - id: '1234_oauth.americanexpressfdx.com 1001', - fundID: '1234', - feed: 'oauth.americanexpressfdx.com 1001', - name: 'American Express', - linkedPolicyIDs: undefined, - country: '', - }); - }); - - it('returns the feed when found in another policy', () => { - const result = getFeedInfo('1234_vcf', cardFeedsByPolicy); - expect(result).toEqual({ - id: '1234_vcf', - fundID: '1234', - feed: 'vcf', - name: 'Custom feed name', - linkedPolicyIDs: undefined, - country: '', - }); - }); - - it('returns the feed when id matches in policy with multiple feeds', () => { - const result = getFeedInfo('1234_stripe', cardFeedsByPolicy); - expect(result).toEqual({ - id: '1234_stripe', - fundID: '1234', - feed: 'stripe', - name: 'Stripe', - linkedPolicyIDs: undefined, - country: '', + XX1YY2ZZ3: [{id: '1234_stripe', fundID: '1234', feed: 'stripe', name: 'Stripe'}], }); }); }); diff --git a/tests/unit/hooks/useOtherFeedsForFeedSelector.test.tsx b/tests/unit/hooks/useOtherFeedsForFeedSelector.test.tsx deleted file mode 100644 index c481d90608084..0000000000000 --- a/tests/unit/hooks/useOtherFeedsForFeedSelector.test.tsx +++ /dev/null @@ -1,250 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import {renderHook} from '@testing-library/react-native'; -import React from 'react'; -import useCardFeedErrors from '@hooks/useCardFeedErrors'; -import useCardFeedsForActivePolicies from '@hooks/useCardFeedsForActivePolicies'; -import {useCompanyCardFeedIcons} from '@hooks/useCompanyCardIcons'; -import useCompanyCards from '@hooks/useCompanyCards'; -import useLocalize from '@hooks/useLocalize'; -import useOtherFeedsForFeedSelector from '@hooks/useOtherFeedsForFeedSelector'; -import useThemeIllustrations from '@hooks/useThemeIllustrations'; -import useThemeStyles from '@hooks/useThemeStyles'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; - -const currentPolicyID = 'policy_current'; -const otherPolicyID = 'policy_other'; - -const mockDomainCollection = { - [`${ONYXKEYS.COLLECTION.DOMAIN}999`]: {email: 'admin@acme.corp'}, -}; - -const mockPolicyCollection = { - [`${ONYXKEYS.COLLECTION.POLICY}${otherPolicyID}`]: {name: 'Other workspace'}, -}; - -const mockUseOnyx = jest.fn(); - -jest.mock('@hooks/useOnyx', () => ({ - __esModule: true, - default: (...args: unknown[]): [unknown, {status?: string}] => mockUseOnyx(...args) as [unknown, {status?: string}], -})); - -jest.mock('@hooks/useCardFeedsForActivePolicies', () => ({ - __esModule: true, - default: jest.fn(), -})); - -jest.mock('@hooks/useCompanyCards', () => ({ - __esModule: true, - default: jest.fn(), -})); - -jest.mock('@hooks/useCardFeedErrors', () => ({ - __esModule: true, - default: jest.fn(), -})); - -jest.mock('@hooks/useLocalize', () => ({ - __esModule: true, - default: jest.fn(), -})); - -jest.mock('@hooks/useThemeStyles', () => ({ - __esModule: true, - default: jest.fn(), -})); - -jest.mock('@hooks/useThemeIllustrations', () => ({ - __esModule: true, - default: jest.fn(), -})); - -jest.mock('@hooks/useCompanyCardIcons', () => ({ - __esModule: true, - useCompanyCardFeedIcons: jest.fn(), -})); - -describe('useOtherFeedsForFeedSelector', () => { - beforeEach(() => { - jest.clearAllMocks(); - - mockUseOnyx.mockImplementation((key: string) => { - if (key === ONYXKEYS.COLLECTION.DOMAIN) { - return [mockDomainCollection, {status: 'loaded'}]; - } - if (key === ONYXKEYS.COLLECTION.POLICY) { - return [mockPolicyCollection, {status: 'loaded'}]; - } - return [undefined, {}]; - }); - - (useLocalize as jest.Mock).mockReturnValue({translate: (phrase: string) => phrase}); - (useThemeStyles as jest.Mock).mockReturnValue({mr3: {marginRight: 12}, cardIcon: {}}); - (useThemeIllustrations as jest.Mock).mockReturnValue({}); - (useCompanyCardFeedIcons as jest.Mock).mockReturnValue({}); - (useCardFeedErrors as jest.Mock).mockReturnValue({shouldShowRbrForFeedNameWithDomainID: {}}); - (useCompanyCards as jest.Mock).mockReturnValue({feedName: undefined}); - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({cardFeedsByPolicy: {}}); - }); - - it('should return an empty list when cardFeedsByPolicy is empty', () => { - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current).toEqual([]); - }); - - it('should exclude feeds already linked to the current policy', () => { - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({ - cardFeedsByPolicy: { - [otherPolicyID]: [ - { - id: '999_oauth.chase.com', - feed: 'oauth.chase.com', - fundID: '999', - name: 'Chase feed', - linkedPolicyIDs: [currentPolicyID], - country: 'US', - }, - ], - }, - }); - - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current).toHaveLength(0); - }); - - it('should include feeds from other policies that are not linked to the current policy', () => { - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({ - cardFeedsByPolicy: { - [otherPolicyID]: [ - { - id: '999_oauth.chase.com', - feed: 'oauth.chase.com', - fundID: '999', - name: 'Chase feed', - linkedPolicyIDs: ['policy_unrelated'], - country: 'US', - }, - ], - }, - }); - - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current).toHaveLength(1); - expect(result.current.at(0)).toEqual( - expect.objectContaining({ - value: '999_oauth.chase.com', - feed: 'oauth.chase.com', - fundID: 999, - country: 'US', - keyForList: '999_oauth.chase.com', - isSelected: false, - }), - ); - expect(React.isValidElement(result.current.at(0)?.leftElement)).toBe(true); - }); - - it('should set isSelected when feed id matches the selected feed from useCompanyCards', () => { - const feedId = '999_oauth.chase.com'; - (useCompanyCards as jest.Mock).mockReturnValue({feedName: feedId}); - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({ - cardFeedsByPolicy: { - [otherPolicyID]: [ - { - id: feedId, - feed: 'oauth.chase.com', - fundID: '999', - name: 'Chase feed', - linkedPolicyIDs: ['policy_unrelated'], - }, - ], - }, - }); - - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current.at(0)?.isSelected).toBe(true); - }); - - it('should surface RBR when shouldShowRbrForFeedNameWithDomainID is true for the feed id', () => { - const feedId = '999_visa'; - (useCardFeedErrors as jest.Mock).mockReturnValue({ - shouldShowRbrForFeedNameWithDomainID: {[feedId]: true}, - }); - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({ - cardFeedsByPolicy: { - [otherPolicyID]: [ - { - id: feedId, - feed: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA, - fundID: '999', - name: 'Visa feed', - linkedPolicyIDs: ['policy_unrelated'], - }, - ], - }, - }); - - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current.at(0)).toEqual( - expect.objectContaining({ - brickRoadIndicator: CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, - canShowSeveralIndicators: true, - }), - ); - }); - - it('should use domain email domain for alternateText when domain data exists', () => { - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({ - cardFeedsByPolicy: { - [otherPolicyID]: [ - { - id: '999_visa', - feed: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA, - fundID: '999', - name: 'Visa feed', - linkedPolicyIDs: ['policy_unrelated'], - }, - ], - }, - }); - - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current.at(0)?.alternateText).toBe('acme.corp'); - }); - - it('should use linked policy name for alternateText when domain email is missing', () => { - mockUseOnyx.mockImplementation((key: string) => { - if (key === ONYXKEYS.COLLECTION.DOMAIN) { - return [{}, {status: 'loaded'}]; - } - if (key === ONYXKEYS.COLLECTION.POLICY) { - return [mockPolicyCollection, {status: 'loaded'}]; - } - return [undefined, {}]; - }); - - (useCardFeedsForActivePolicies as jest.Mock).mockReturnValue({ - cardFeedsByPolicy: { - [otherPolicyID]: [ - { - id: '888_visa', - feed: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA, - fundID: '888', - name: 'Visa feed', - linkedPolicyIDs: [otherPolicyID], - }, - ], - }, - }); - - const {result} = renderHook(() => useOtherFeedsForFeedSelector(currentPolicyID)); - - expect(result.current.at(0)?.alternateText).toBe('Other workspace'); - }); -}); diff --git a/tests/unit/hooks/usePrimaryContactMethod.test.ts b/tests/unit/hooks/usePrimaryContactMethod.test.ts deleted file mode 100644 index f8f181ea07a44..0000000000000 --- a/tests/unit/hooks/usePrimaryContactMethod.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {act, renderHook} from '@testing-library/react-native'; -import Onyx from 'react-native-onyx'; -import usePrimaryContactMethod from '@hooks/usePrimaryContactMethod'; -import ONYXKEYS from '@src/ONYXKEYS'; -import waitForBatchedUpdates from '../../utils/waitForBatchedUpdates'; - -describe('usePrimaryContactMethod', () => { - beforeAll(() => { - Onyx.init({keys: ONYXKEYS}); - }); - - beforeEach(async () => { - await act(async () => { - await Onyx.clear(); - await waitForBatchedUpdates(); - }); - }); - - afterEach(async () => { - await act(async () => { - await Onyx.clear(); - await waitForBatchedUpdates(); - }); - }); - - it('should return account primaryLogin when set', async () => { - await act(async () => { - await Onyx.merge(ONYXKEYS.ACCOUNT, {primaryLogin: 'primary@expensify.com'}); - await Onyx.merge(ONYXKEYS.SESSION, {email: 'session@expensify.com'}); - await waitForBatchedUpdates(); - }); - - const {result} = renderHook(() => usePrimaryContactMethod()); - - expect(result.current).toBe('primary@expensify.com'); - }); - - it('should fall back to session email when primaryLogin is absent', async () => { - await act(async () => { - await Onyx.merge(ONYXKEYS.ACCOUNT, {}); - await Onyx.merge(ONYXKEYS.SESSION, {email: 'session-only@expensify.com'}); - await waitForBatchedUpdates(); - }); - - const {result} = renderHook(() => usePrimaryContactMethod()); - - expect(result.current).toBe('session-only@expensify.com'); - }); - - it('should return empty string when neither primaryLogin nor session email exist', async () => { - await act(async () => { - await Onyx.merge(ONYXKEYS.ACCOUNT, {}); - await Onyx.merge(ONYXKEYS.SESSION, {}); - await waitForBatchedUpdates(); - }); - - const {result} = renderHook(() => usePrimaryContactMethod()); - - expect(result.current).toBe(''); - }); - - it('should return empty string when account and session are unset', async () => { - const {result} = renderHook(() => usePrimaryContactMethod()); - - expect(result.current).toBe(''); - }); -});