diff --git a/src/languages/de.ts b/src/languages/de.ts index 457bd54531c5..7f0ce695acb5 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6670,8 +6670,6 @@ Der Control-Tarif beginnt bei 9 $ pro aktivem Mitglied und Monat.`, peopleAdmins: 'Personaladministratoren', paymentsAdmins: 'Zahlungsadmins', members: 'Mitglieder', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `Sie können ${memberName} nicht aus diesem Workspace entfernen, solange diese Person eine Expensify Karte hat. Bitte deaktivieren Sie die Karte unter Workspace > Expensify Karte und versuchen Sie es dann erneut.`, }, card: { getStartedIssuing: 'Beginne, indem du deine erste virtuelle oder physische Karte ausstellst.', diff --git a/src/languages/en.ts b/src/languages/en.ts index 50cad54d7e0f..0ba06c98eb8e 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6768,8 +6768,6 @@ const translations = { `${memberName} has outstanding expense reports to approve. Please ask them to approve, or take control of their reports before removing them from the workspace.`, removeMemberPromptReimburser: ({memberName}: {memberName: string}) => `You can't remove ${memberName} from this workspace. Please set a new reimburser in Workflows > Make or track payments, then try again.`, - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `You can't remove ${memberName} from this workspace while they have an Expensify Card. Please deactivate their card in Workspace > Expensify Card, then try again.`, removeMemberPromptExporter: ({memberName, workspaceOwner}: {memberName: string; workspaceOwner: string}) => `If you remove ${memberName} from this workspace, we'll replace them as the preferred exporter with ${workspaceOwner}, the workspace owner.`, removeMemberPromptTechContact: ({memberName, workspaceOwner}: {memberName: string; workspaceOwner: string}) => diff --git a/src/languages/es.ts b/src/languages/es.ts index 41a3a30c24e9..c8e3506b0a54 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6512,8 +6512,6 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`, peopleAdmins: 'Administradores de personas', paymentsAdmins: 'Administradores de pagos', members: 'Miembros', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `No puedes eliminar a ${memberName} de este espacio de trabajo mientras tenga una Tarjeta Expensify. Desactiva su tarjeta en Espacio de trabajo > Tarjeta Expensify y vuelve a intentarlo.`, }, accounting: { settings: 'configuración', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index e246c48104e2..6cc611c60e2b 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6695,8 +6695,6 @@ Le forfait Control commence à 9 $ par Membre actif et par mois.`, peopleAdmins: 'Administrateurs des personnes', paymentsAdmins: 'Administrateurs des paiements', members: 'Membres', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `Vous ne pouvez pas supprimer ${memberName} de cet espace de travail tant qu’iel possède une Carte Expensify. Veuillez désactiver sa carte dans Espace de travail > Carte Expensify, puis réessayer.`, }, card: { getStartedIssuing: 'Commencez par émettre votre première carte virtuelle ou physique.', diff --git a/src/languages/it.ts b/src/languages/it.ts index 795cecbd7832..f3f7053757fa 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6646,8 +6646,6 @@ Il piano Control parte da 9 $ al mese per ogni membro attivo.`, peopleAdmins: 'Amministratori persone', paymentsAdmins: 'Amministratori pagamenti', members: 'Membri', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `Non puoi rimuovere ${memberName} da questo spazio di lavoro finché ha una Carta Expensify. Disattiva prima la sua carta in Spazio di lavoro > Carta Expensify, quindi riprova.`, }, card: { getStartedIssuing: 'Inizia emettendo la tua prima carta virtuale o fisica.', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 49a993fabdc0..989b2a72bac8 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6566,8 +6566,6 @@ Control プランは、アクティブメンバー1人あたり月額 $9 から peopleAdmins: 'People 管理者', paymentsAdmins: '支払い管理者', members: 'メンバー', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `${memberName}さんはExpensify カードをお持ちの間、このワークスペースから削除できません。ワークスペース > Expensify カードでカードを無効化してから、もう一度お試しください。`, }, card: { getStartedIssuing: 'まずは最初のバーチャルカードまたは物理カードを発行しましょう。', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 67a53d6ca2e9..a2d65224aba6 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6632,8 +6632,6 @@ Het Control-abonnement begint bij $9 per actieve deelnemer per maand.`, peopleAdmins: 'People-beheerders', paymentsAdmins: 'Betalingsbeheerders', members: 'Leden', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `Je kunt ${memberName} niet uit deze werkruimte verwijderen zolang diegene een Expensify Kaart heeft. Deactiveer eerst hun kaart in Werkruimte > Expensify Kaart en probeer het daarna opnieuw.`, }, card: { getStartedIssuing: 'Begin met het uitgeven van je eerste virtuele of fysieke kaart.', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index d331e83895e3..dc54a747f85f 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6613,8 +6613,6 @@ Plan Control zaczyna się od 9 USD za aktywnego członka miesięcznie.`, peopleAdmins: 'Administratorzy osób', paymentsAdmins: 'Administratorzy płatności', members: 'Członkowie', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `Nie możesz usunąć użytkownika ${memberName} z tego workspace, dopóki ma Kartę Expensify. Dezaktywuj jego kartę w Workspace > Karta Expensify, a następnie spróbuj ponownie.`, }, card: { getStartedIssuing: 'Zacznij od wydania swojej pierwszej wirtualnej lub fizycznej karty.', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 83961d99247d..05321b48ece5 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6630,8 +6630,6 @@ O plano Control começa em US$ 9 por membro ativo por mês.`, peopleAdmins: 'Administradores de pessoas', paymentsAdmins: 'Administradores de pagamentos', members: 'Membros', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `Você não pode remover ${memberName} deste workspace enquanto essa pessoa tiver um Cartão Expensify. Desative o cartão em Workspace > Cartão Expensify e tente novamente.`, }, card: { getStartedIssuing: 'Comece emitindo seu primeiro cartão virtual ou físico.', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 798328f37cb8..a2442f05aa36 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6417,8 +6417,6 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM peopleAdmins: '人员管理员', paymentsAdmins: '付款管理员', members: '成员', - removeMemberPromptExpensifyCard: ({memberName}: {memberName: string}) => - `在 ${memberName} 仍持有 Expensify 卡时,您无法将其从此工作区中移除。请在“工作区 > Expensify 卡”中停用其卡片后重试。`, }, card: { getStartedIssuing: '从发放您的第一张虚拟卡或实体卡开始使用。', diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 3619415ecda9..1621f1241225 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -1293,13 +1293,6 @@ function isSmartLimitEnabled(cardsList: CardList) { return hasAssignedCardMatching(cardsList, (card) => card.nameValuePairs?.limitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART); } -function hasActiveExpensifyCardAssigned(workspaceCards: CardList | undefined, accountID: number): boolean { - return hasAssignedCardMatching( - workspaceCards, - (card) => card.accountID === accountID && card.bank === CONST.EXPENSIFY_CARD.BANK && !isTravelCard(card) && card.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, - ); -} - const CUSTOM_FEEDS = [CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD, CONST.COMPANY_CARD.FEED_BANK_NAME.VISA, CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX, CONST.COMPANY_CARD.FEED_BANK_NAME.CSV]; function collectUsedCSVFeedSlotNumbersFromCompanyCards(companyCards: CompanyFeeds | undefined, csvPrefix: string): number[] { @@ -2147,7 +2140,6 @@ export { getDomainByFundID, isPolicyIDInLinkedExpensifyCardPolicyList, filterAllInactiveCards, - hasActiveExpensifyCardAssigned, hasAssignedCardMatching, forEachAssignedCard, isActiveCard, diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index da88775c9cdc..cafa5b984e40 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -13,10 +13,8 @@ import Text from '@components/Text'; import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; import TextLink from '@components/TextLink'; -import useCardFeeds from '@hooks/useCardFeeds'; import useConfirmModal from '@hooks/useConfirmModal'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import useExpensifyCardFeeds from '@hooks/useExpensifyCardFeeds'; import useHRSyncResultsModal from '@hooks/useHRSyncResultsModal'; import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; @@ -46,7 +44,6 @@ import { } from '@libs/actions/Policy/Member'; import {removeApprovalWorkflow as removeApprovalWorkflowAction, updateApprovalWorkflow} from '@libs/actions/Workflow'; import {isRuleBotEnforcingRules} from '@libs/AgentRulesUtils'; -import {getAllCardsForWorkspace, hasActiveExpensifyCardAssigned} from '@libs/CardUtils'; import {getLatestErrorMessageField} from '@libs/ErrorUtils'; import {getConnectedHRProvider, showMergeHRManualSyncLimitModalIfReached} from '@libs/HRUtils'; import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; @@ -145,13 +142,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers const isFocused = useIsFocused(); const policyID = route.params.policyID; const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`); - const [cardFeeds] = useCardFeeds(policyID); - const [cardList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}`); - const expensifyCardSettings = useExpensifyCardFeeds(policyID); - const workspaceCards = useMemo( - () => getAllCardsForWorkspace(policy?.policyAccountID ?? CONST.DEFAULT_NUMBER_ID, cardList, cardFeeds, expensifyCardSettings), - [policy?.policyAccountID, cardList, cardFeeds, expensifyCardSettings], - ); const [invitedEmailsToAccountIDsDraft] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${policyID}`); const illustrations = useMemoizedLazyIllustrations(['ReceiptWrangler', 'EmptyShelves']); @@ -172,16 +162,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers const canSelectMultiple = canWriteMembers && (shouldUseNarrowLayout ? isMobileSelectionModeEnabled : true); - const blockedCardholderName = useMemo(() => { - const cardholderEmail = selectedEmployees.find((selectedEmployee) => hasActiveExpensifyCardAssigned(workspaceCards, policyMemberEmailsToAccountIDs[selectedEmployee])); - - if (!cardholderEmail) { - return; - } - - return getDisplayNameForParticipant({accountID: policyMemberEmailsToAccountIDs[cardholderEmail], formatPhoneNumber, translate}); - }, [selectedEmployees, workspaceCards, policyMemberEmailsToAccountIDs, formatPhoneNumber, translate]); - const confirmModalPrompt = useMemo(() => { const approverEmail = selectedEmployees.find((selectedEmployee) => isPolicyApprover(policy, selectedEmployee)); @@ -295,17 +275,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers showRuleBotGuardModal('remove', policyID); return; } - if (blockedCardholderName) { - showConfirmModal({ - shouldShowCancelButton: false, - success: true, - title: translate('workspace.people.removeMembersTitle', {count: selectedEmployees.length}), - prompt: translate('workspace.people.removeMemberPromptExpensifyCard', {memberName: blockedCardholderName}), - confirmText: translate('common.buttonConfirm'), - cancelText: translate('common.cancel'), - }); - return; - } showConfirmModal({ danger: true, @@ -326,7 +295,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers removeUsers(); }); - }, [blockedCardholderName, confirmModalPrompt, removeUsers, selectedEmployees, policyMemberEmailsToAccountIDs, policy, policyID, showConfirmModal, showRuleBotGuardModal, translate]); + }, [confirmModalPrompt, removeUsers, selectedEmployees, policyMemberEmailsToAccountIDs, policy, policyID, showConfirmModal, showRuleBotGuardModal, translate]); /** Opens the member details page */ const openMemberDetails = useCallback( diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index e502b7e3770d..35f4a5fea0da 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -30,15 +30,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {setPolicyPreventSelfApproval} from '@libs/actions/Policy/Policy'; import {removeApprovalWorkflow as removeApprovalWorkflowAction, updateApprovalWorkflow} from '@libs/actions/Workflow'; import {isRuleBotEnforcingRules} from '@libs/AgentRulesUtils'; -import { - getAllCardsForWorkspace, - getCardFeedIcon, - getCardFeedWithDomainID, - getPlaidInstitutionIconUrl, - hasActiveExpensifyCardAssigned, - lastFourNumbersFromCardName, - maskCardNumber, -} from '@libs/CardUtils'; +import {getAllCardsForWorkspace, getCardFeedIcon, getCardFeedWithDomainID, getPlaidInstitutionIconUrl, lastFourNumbersFromCardName, maskCardNumber} from '@libs/CardUtils'; import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import {getPersonalDetailByEmail, getPhoneNumber, temporaryGetDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; @@ -155,7 +147,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const phoneNumber = getPhoneNumber(details); const reimburserEmail = getReimburserEmail(policy); const isReimburser = !!reimburserEmail && reimburserEmail === memberLogin; - const hasActiveExpensifyCard = hasActiveExpensifyCardAssigned(workspaceCards, accountID); const {isAccountLocked} = useLockedAccountState(); const {showLockedAccountModal} = useLockedAccountActions(); @@ -189,11 +180,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM let confirmModalPrompt = translate('workspace.people.removeMembersWarningPrompt', displayName, policyOwnerDisplayName); - if (hasActiveExpensifyCard) { - confirmModalPrompt = translate('workspace.people.removeMemberPromptExpensifyCard', { - memberName: displayName, - }); - } else if (isTechnicalContact) { + if (isTechnicalContact) { confirmModalPrompt = translate('workspace.people.removeMemberPromptTechContact', { memberName: displayName, workspaceOwner: policyOwnerDisplayName, @@ -282,7 +269,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM showRuleBotGuardModal('remove', policyID); return; } - if (hasActiveExpensifyCard || isReimburser) { + if (isReimburser) { showConfirmModal({ shouldShowCancelButton: false, success: true, diff --git a/tests/unit/CardUtilsTest.ts b/tests/unit/CardUtilsTest.ts index 7136f2f722b4..7c7fc5078d4d 100644 --- a/tests/unit/CardUtilsTest.ts +++ b/tests/unit/CardUtilsTest.ts @@ -54,7 +54,6 @@ import { getSelectedFeed, getTranslationKeyForCardStatus, getYearFromExpirationDateString, - hasActiveExpensifyCardAssigned, hasAssignedCardMatching, hasIssuedExpensifyCard, hasOnlyOneCardToAssign, @@ -2235,56 +2234,6 @@ describe('CardUtils', () => { }); }); - describe('hasActiveExpensifyCardAssigned', () => { - const cardholderAccountID = 11; - - it('returns true when the member holds an Expensify Card on the workspace', () => { - const cards = createMock({ - '1': {cardID: 1, accountID: cardholderAccountID, bank: CONST.EXPENSIFY_CARD.BANK}, - }); - expect(hasActiveExpensifyCardAssigned(cards, cardholderAccountID)).toBe(true); - }); - - it('returns false for an undefined card list', () => { - expect(hasActiveExpensifyCardAssigned(undefined, cardholderAccountID)).toBe(false); - }); - - it('returns false when the Expensify Card belongs to another member', () => { - const cards = createMock({ - '1': {cardID: 1, accountID: 22, bank: CONST.EXPENSIFY_CARD.BANK}, - }); - expect(hasActiveExpensifyCardAssigned(cards, cardholderAccountID)).toBe(false); - }); - - it('returns false when the member only holds a company card', () => { - const cards = createMock({ - '1': {cardID: 1, accountID: cardholderAccountID, bank: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA}, - }); - expect(hasActiveExpensifyCardAssigned(cards, cardholderAccountID)).toBe(false); - }); - - it('returns false when the member only holds a travel card', () => { - const cards = createMock({ - '1': {cardID: 1, accountID: cardholderAccountID, bank: CONST.EXPENSIFY_CARD.BANK, nameValuePairs: {feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US}}, - }); - expect(hasActiveExpensifyCardAssigned(cards, cardholderAccountID)).toBe(false); - }); - - it('returns false when the Expensify Card is already pending removal', () => { - const cards = createMock({ - '1': {cardID: 1, accountID: cardholderAccountID, bank: CONST.EXPENSIFY_CARD.BANK, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}, - }); - expect(hasActiveExpensifyCardAssigned(cards, cardholderAccountID)).toBe(false); - }); - - it('skips the cardList bucket of cards still available to assign', () => { - const cards = createMock({ - cardList: {'CREDIT CARD...1234': 'encrypted-value'} as Record, - }); - expect(hasActiveExpensifyCardAssigned(cards, cardholderAccountID)).toBe(false); - }); - }); - describe('forEachAssignedCard', () => { const cardsList = createMock({ '1': {cardID: 1, state: CONST.EXPENSIFY_CARD.STATE.OPEN},