diff --git a/assets/images/user-minus.svg b/assets/images/user-minus.svg
new file mode 100644
index 000000000000..f819734464a8
--- /dev/null
+++ b/assets/images/user-minus.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/cspell.json b/cspell.json
index 1c61490d481e..b0c8c5baaa54 100644
--- a/cspell.json
+++ b/cspell.json
@@ -737,6 +737,8 @@
"Venmo",
"viewability",
"viewport",
+ "Unsharing",
+ "unsharing",
"viewports",
"VMPD",
"voidings",
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 91b60f5acff8..5bf1bcf1f2c0 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -125,6 +125,9 @@ const ONYXKEYS = {
/* Contains meta data for the call to the API to get the joinable policies */
VALIDATE_USER_AND_GET_ACCESSIBLE_POLICIES: 'validateUserAndGetAccessiblePolicies',
+ /** Stores details relating to unsharing a given bank account */
+ UNSHARE_BANK_ACCOUNT: 'unshareBankAccount',
+
/** Information about the current session (authToken, accountID, email, loading, error) */
SESSION: 'session',
STASHED_SESSION: 'stashedSession',
@@ -1258,6 +1261,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.PURCHASE_LIST]: OnyxTypes.PurchaseList;
[ONYXKEYS.PERSONAL_BANK_ACCOUNT]: OnyxTypes.PersonalBankAccount;
[ONYXKEYS.SHARE_BANK_ACCOUNT]: OnyxTypes.ShareBankAccount;
+ [ONYXKEYS.UNSHARE_BANK_ACCOUNT]: OnyxTypes.UnshareBankAccount;
[ONYXKEYS.REIMBURSEMENT_ACCOUNT]: OnyxTypes.ReimbursementAccount;
[ONYXKEYS.REIMBURSEMENT_ACCOUNT_OPTION_PRESSED]: ValueOf;
[ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE]: number;
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 87cf0b33472d..1a2fe9651178 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -344,6 +344,10 @@ const ROUTES = {
SETTINGS_ADD_US_BANK_ACCOUNT: 'settings/wallet/add-us-bank-account',
SETTINGS_ADD_BANK_ACCOUNT_SELECT_COUNTRY_VERIFY_ACCOUNT: `settings/wallet/add-bank-account/select-country/${VERIFY_ACCOUNT}`,
SETTINGS_ENABLE_PAYMENTS: 'settings/wallet/enable-payments',
+ SETTINGS_WALLET_UNSHARE_BANK_ACCOUNT: {
+ route: 'settings/wallet/:bankAccountID/unshare-bank-account',
+ getRoute: (bankAccountID: number | undefined) => `settings/wallet/${bankAccountID}/unshare-bank-account` as const,
+ },
SETTINGS_WALLET_ENABLE_GLOBAL_REIMBURSEMENTS: {
route: 'settings/wallet/:bankAccountID/enable-global-reimbursements',
getRoute: (bankAccountID: number | undefined) => `settings/wallet/${bankAccountID}/enable-global-reimbursements` as const,
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 1393fcf63841..85c9b8346785 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -166,6 +166,7 @@ const SCREENS = {
REPORT_VIRTUAL_CARD_FRAUD_CONFIRM_MAGIC_CODE: 'Settings_Wallet_ReportVirtualCardFraud_ConfirmMagicCode',
REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION: 'Settings_Wallet_ReportVirtualCardFraudConfirmation',
CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS: 'Settings_Wallet_Cards_Digital_Details_Update_Address',
+ UNSHARE_BANK_ACCOUNT: 'Settings_Wallet_Unshare_Bank_Account',
ENABLE_GLOBAL_REIMBURSEMENTS: 'Settings_Wallet_Enable_Global_Reimbursements',
SHARE_BANK_ACCOUNT: 'Settings_Wallet_Share_Bank_Account',
},
diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts
index 3c2e66df07a6..71447b27039c 100644
--- a/src/components/Icon/chunks/expensify-icons.chunk.ts
+++ b/src/components/Icon/chunks/expensify-icons.chunk.ts
@@ -222,6 +222,7 @@ import Upload from '@assets/images/upload.svg';
import UserCheck from '@assets/images/user-check.svg';
import UserEye from '@assets/images/user-eye.svg';
import UserLock from '@assets/images/user-lock.svg';
+import UserMinus from '@assets/images/user-minus.svg';
import UserPlus from '@assets/images/user-plus.svg';
import User from '@assets/images/user.svg';
import Users from '@assets/images/users.svg';
@@ -342,6 +343,7 @@ const Expensicons = {
LinkCopy,
Location,
Lock,
+ UserMinus,
Luggage,
MagnifyingGlass,
Mail,
diff --git a/src/languages/de.ts b/src/languages/de.ts
index e8c7b7d93eb9..587618929151 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: 'Schließen',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Fortfahren',
+ unshare: 'Nicht teilen',
yes: 'Ja',
no: 'Nein',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2115,6 +2116,12 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'Keine Administratoren verfügbar',
shareBankAccountEmptyDescription: 'Es gibt keine Workspace-Administratoren, mit denen Sie dieses Bankkonto teilen können.',
shareBankAccountNoAdminsSelected: 'Bitte wählen Sie einen Administrator aus, bevor Sie fortfahren',
+ unshareBankAccount: 'Bankkonto freigeben',
+ unshareBankAccountDescription:
+ 'Alle unten aufgeführten Personen haben Zugriff auf dieses Bankkonto. Sie können den Zugriff jederzeit entfernen. Laufende Zahlungen werden weiterhin ausgeführt.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} verliert den Zugriff auf dieses Geschäftskonto. Laufende Zahlungen werden weiterhin ausgeführt.`,
+ reachOutForHelp: 'Dieses Konto wird mit der Expensify Card verwendet. Wenden Sie sich an den Concierge, wenn Sie die Freigabe aufheben möchten.',
+ unshareErrorModalTitle: 'Bankkonto kann nicht freigegeben werden',
},
cardPage: {
expensifyCard: 'Expensify Card',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 877231521b32..108885fde5f1 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -245,6 +245,7 @@ const translations = {
dismiss: 'Dismiss',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Proceed',
+ unshare: 'Unshare',
yes: 'Yes',
no: 'No',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2103,6 +2104,11 @@ const translations = {
shareBankAccountEmptyTitle: 'No admins available',
shareBankAccountEmptyDescription: 'There are no workspace admins you can share this bank account with.',
shareBankAccountNoAdminsSelected: 'Please select an admin before continuing',
+ unshareBankAccount: 'Unshare bank account',
+ unshareBankAccountDescription: 'Everyone below has access to this bank account. You can remove access at any point. We’ll still complete any payments in process.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} will lose access to this business bank account. We’ll still complete any payments in process.`,
+ reachOutForHelp: 'It’s being used with the Expensify Card. Reach out to Concierge if you need to unshare it.',
+ unshareErrorModalTitle: 'Can’t unshare bank account',
},
cardPage: {
expensifyCard: 'Expensify Card',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 6f3276c0078c..f7239e05feb6 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -12,6 +12,7 @@ const translations: TranslationDeepObject = {
cancel: 'Cancelar',
dismiss: 'Descartar',
proceed: 'Proceder',
+ unshare: 'Dejar de compartir',
yes: 'Sí',
no: 'No',
ok: 'OK',
@@ -1811,6 +1812,12 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'No hay administradores disponibles',
shareBankAccountEmptyDescription: 'No hay administradores del espacio de trabajo con los que puedas compartir esta cuenta bancaria',
shareBankAccountNoAdminsSelected: 'Seleccione un administrador antes de continuar',
+ unshareBankAccount: 'Dejar de compartir la cuenta bancaria',
+ unshareBankAccountDescription:
+ 'Todas las personas a continuación tienen acceso a esta cuenta bancaria. Puede retirar el acceso en cualquier momento. Seguiremos completando los pagos en proceso.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} perderá el acceso a esta cuenta bancaria comercial. Seguiremos completando los pagos en proceso.`,
+ reachOutForHelp: 'Se está usando con la tarjeta Expensify. Contacte con Concierge si necesita dejar de compartirla.',
+ unshareErrorModalTitle: 'No se puede dejar de compartir la cuenta bancaria',
},
cardPage: {
expensifyCard: 'Tarjeta Expensify',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 148731c79798..bda734c4fc40 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: 'Fermer',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Continuer',
+ unshare: 'Partager',
yes: 'Oui',
no: 'Non',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2120,6 +2121,11 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'Aucun administrateur disponible',
shareBankAccountEmptyDescription: "Aucun administrateur d'espace de travail n'est disponible pour partager ce compte bancaire.",
shareBankAccountNoAdminsSelected: 'Veuillez sélectionner un administrateur avant de continuer',
+ unshareBankAccount: 'Retirer le partage du compte bancaire',
+ unshareBankAccountDescription: 'Toutes les personnes ci-dessous ont accès à ce compte bancaire. Vous pouvez révoquer l’accès à tout moment. Les paiements en cours seront honorés.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} perdra l’accès à ce compte bancaire professionnel. Les paiements en cours seront honorés.`,
+ reachOutForHelp: 'Ce compte est utilisé avec la carte Expensify. Contactez le service de conciergerie si vous souhaitez le retirer du partage.',
+ unshareErrorModalTitle: 'Impossible de retirer le partage du compte bancaire',
},
cardPage: {
expensifyCard: 'Carte Expensify',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 4cba9c8c0fa7..b0d5ae6ee457 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: 'Chiudi',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Continua',
+ unshare: 'Non condividere',
yes: 'Sì',
no: 'No',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2110,6 +2111,12 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'Nessun amministratore disponibile',
shareBankAccountEmptyDescription: "Non ci sono amministratori dell'area di lavoro con cui puoi condividere questo conto bancario.",
shareBankAccountNoAdminsSelected: 'Seleziona un amministratore prima di continuare',
+ unshareBankAccount: 'Annulla condivisione conto bancario',
+ unshareBankAccountDescription:
+ "Tutti i seguenti hanno accesso a questo conto bancario. Puoi revocare l'accesso in qualsiasi momento. Completeremo comunque tutti i pagamenti in corso.",
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} perderà l'accesso a questo conto bancario aziendale. Completeremo comunque tutti i pagamenti in corso.`,
+ reachOutForHelp: 'È in uso con la carta Expensify. Contatta il Concierge se devi revocare la condivisione.',
+ unshareErrorModalTitle: 'Impossibile revocare la condivisione del conto bancario',
},
cardPage: {
expensifyCard: 'Carta Expensify',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index f59de15ab3da..980f0686df3a 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: '閉じる',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: '続行',
+ unshare: '共有解除',
yes: 'はい',
no: 'いいえ',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2107,6 +2108,11 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: '管理者がいません',
shareBankAccountEmptyDescription: 'この銀行口座を共有できるワークスペース管理者がいません',
shareBankAccountNoAdminsSelected: '続行する前に管理者を選択してください',
+ unshareBankAccount: '銀行口座の共有を解除してください',
+ unshareBankAccountDescription: '以下の全員がこの銀行口座にアクセスできます。いつでもアクセスを削除できます。処理中のお支払いは引き続き完了します。',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} はこのビジネス銀行口座にアクセスできなくなります。処理中のお支払いは引き続き完了します。`,
+ reachOutForHelp: 'この口座は Expensify カードで使用されています。共有を解除する必要がある場合は、コンシェルジュまでお問い合わせください。',
+ unshareErrorModalTitle: '銀行口座の共有を解除できません',
},
cardPage: {
expensifyCard: 'Expensify Card',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 900be1b8e3f4..4e1dab33b6f6 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: 'Sluiten',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Doorgaan',
+ unshare: 'Niet meer delen',
yes: 'Ja',
no: 'Nee',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2108,6 +2109,13 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'Geen beheerders beschikbaar',
shareBankAccountEmptyDescription: 'Er zijn geen werkruimtebeheerders waarmee u deze bankrekening kunt delen.',
shareBankAccountNoAdminsSelected: 'Selecteer een beheerder voordat u verdergaat',
+ unshareBankAccount: 'Deelname bankrekening ongedaan maken',
+ unshareBankAccountDescription:
+ 'Iedereen hieronder heeft toegang tot deze bankrekening. U kunt de toegang op elk moment intrekken. We zullen alle betalingen die in behandeling zijn nog steeds voltooien.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) =>
+ `${admin} verliest de toegang tot deze zakelijke bankrekening. We zullen alle betalingen die in behandeling zijn nog steeds voltooien.`,
+ reachOutForHelp: 'Deze wordt gebruikt met de Expensify Card. Neem contact op met Concierge als u de deling ongedaan wilt maken.',
+ unshareErrorModalTitle: 'Deling bankrekening kan niet ongedaan worden gemaakt',
},
cardPage: {
expensifyCard: 'Expensify Card',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 9f7e9a85d497..f76e4623ee5f 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: 'Zamknij',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Kontynuuj',
+ unshare: 'Cofnij udostępnianie',
yes: 'Tak',
no: 'Nie',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2105,6 +2106,11 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'Brak dostępnych administratorów',
shareBankAccountEmptyDescription: 'Brak administratorów obszaru roboczego, z którymi można udostępnić to konto bankowe.',
shareBankAccountNoAdminsSelected: 'Wybierz administratora przed kontynuowaniem',
+ unshareBankAccount: 'Anuluj udostępnianie konta bankowego',
+ unshareBankAccountDescription: 'Wszyscy poniżej mają dostęp do tego konta bankowego. Możesz go usunąć w dowolnym momencie. Nadal będziemy realizować wszystkie płatności w toku.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} utraci dostęp do tego firmowego konta bankowego. Nadal będziemy realizować wszystkie płatności w toku.`,
+ reachOutForHelp: 'Jest ono używane z kartą Expensify. Skontaktuj się z Concierge, jeśli chcesz je anulować.',
+ unshareErrorModalTitle: 'Nie można anulować udostępniania konta bankowego',
},
cardPage: {
expensifyCard: 'Karta Expensify',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index f3c9bb6255be..5773fb99d947 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -254,6 +254,7 @@ const translations: TranslationDeepObject = {
dismiss: 'Fechar',
// @context Used on a button to continue an action or workflow, not the formal or procedural sense of “to proceed.”
proceed: 'Prosseguir',
+ unshare: 'Deixar de compartilhar',
yes: 'Sim',
no: 'Não',
// @context Universal confirmation button. Keep the UI-standard term “OK” unless the locale strongly prefers an alternative.
@@ -2105,6 +2106,11 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: 'Nenhum administrador disponível',
shareBankAccountEmptyDescription: 'Não há administradores de espaço de trabalho com quem você possa compartilhar esta conta bancária.',
shareBankAccountNoAdminsSelected: 'Selecione um administrador antes de continuar',
+ unshareBankAccount: 'Descompartilhar conta bancária',
+ unshareBankAccountDescription: 'Todos abaixo têm acesso a esta conta bancária. Você pode remover o acesso a qualquer momento. Ainda concluiremos quaisquer pagamentos em andamento.',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} perderá o acesso a esta conta bancária comercial. Ainda concluiremos quaisquer pagamentos em andamento.`,
+ reachOutForHelp: 'Está sendo usada com o Cartão Expensify. Entre em contato com o Concierge se precisar descompartilhar.',
+ unshareErrorModalTitle: 'Não foi possível descompartilhar a conta bancária',
},
cardPage: {
expensifyCard: 'Cartão Expensify',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index faf82a4c4e3d..0dc7382cd4fa 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -260,6 +260,7 @@ const translations: TranslationDeepObject = {
ok: 'OK',
notNow: '现在不要',
noThanks: '不用,谢谢',
+ unshare: '取消分享',
learnMore: '了解更多',
buttonConfirm: '明白了',
name: '名称',
@@ -2078,6 +2079,11 @@ const translations: TranslationDeepObject = {
shareBankAccountEmptyTitle: '暂无管理员可用',
shareBankAccountEmptyDescription: '没有可与您共享此银行账户的工作区管理员。',
shareBankAccountNoAdminsSelected: '请先选择一位管理员再继续',
+ unshareBankAccount: '取消共享银行账户',
+ unshareBankAccountDescription: '以下所有用户均可访问此银行账户。您可以随时取消访问权限。我们仍将完成所有正在进行的付款。',
+ unshareBankAccountWarning: ({admin}: {admin?: string | null}) => `${admin} 将失去对此企业银行账户的访问权限。我们仍将完成所有正在进行的付款。`,
+ reachOutForHelp: '此账户正在与 Expensify 卡一起使用。如果您需要取消共享,请联系礼宾部。',
+ unshareErrorModalTitle: '无法取消共享银行账户',
},
cardPage: {
expensifyCard: 'Expensify Card',
diff --git a/src/libs/API/parameters/UnshareBankAccountParams.ts b/src/libs/API/parameters/UnshareBankAccountParams.ts
new file mode 100644
index 000000000000..ef5f938b6fa4
--- /dev/null
+++ b/src/libs/API/parameters/UnshareBankAccountParams.ts
@@ -0,0 +1,6 @@
+type UnshareBankAccountParams = {
+ bankAccountID: number;
+ ownerEmail: string;
+};
+
+export default UnshareBankAccountParams;
diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts
index b63e384818b2..3db225ba1ef7 100644
--- a/src/libs/API/parameters/index.ts
+++ b/src/libs/API/parameters/index.ts
@@ -137,6 +137,7 @@ export type {default as TogglePolicyUberAutoRemovePageParams} from './TogglePoli
export type {default as InviteToRoomParams} from './InviteToRoomParams';
export type {default as InviteToGroupChatParams} from './InviteToGroupChatParams';
export type {default as InviteWorkspaceEmployeesToUberParams} from './InviteWorkspaceEmployeesToUberParams';
+export type {default as UnshareBankAccountParams} from './UnshareBankAccountParams';
export type {default as RemoveFromRoomParams} from './RemoveFromRoomParams';
export type {default as RemoveFromGroupChatParams} from './RemoveFromGroupChatParams';
export type {default as FlagCommentParams} from './FlagCommentParams';
diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts
index a0a92b0bfe58..d0bb988e9c3d 100644
--- a/src/libs/API/types.ts
+++ b/src/libs/API/types.ts
@@ -100,6 +100,7 @@ const WRITE_COMMANDS = {
SIGN_IN_USER: 'SigninUser',
SIGN_IN_USER_WITH_LINK: 'SigninUserWithLink',
REQUEST_UNLINK_VALIDATION_LINK: 'RequestUnlinkValidationLink',
+ UNSHARE_BANK_ACCOUNT: 'UnshareBankAccount',
UNLINK_LOGIN: 'UnlinkLogin',
ENABLE_TWO_FACTOR_AUTH: 'EnableTwoFactorAuth',
DISABLE_TWO_FACTOR_AUTH: 'DisableTwoFactorAuth',
@@ -889,6 +890,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams;
[WRITE_COMMANDS.MERGE_TRANSACTION]: Parameters.MergeTransactionParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
+ [WRITE_COMMANDS.UNSHARE_BANK_ACCOUNT]: Parameters.UnshareBankAccountParams;
[WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 74b9b20d7b44..0ccc117e8a9b 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -388,6 +388,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Wallet/TransferBalancePage').default,
[SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT]: () => require('../../../../pages/settings/Wallet/ChooseTransferAccountPage').default,
[SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: () => require('../../../../pages/EnablePayments/EnablePayments').default,
+ [SCREENS.SETTINGS.WALLET.UNSHARE_BANK_ACCOUNT]: () => require('../../../../pages/settings/Wallet/UnshareBankAccount/UnshareBankAccount').default,
[SCREENS.SETTINGS.WALLET.ENABLE_GLOBAL_REIMBURSEMENTS]: () => require('../../../../pages/settings/Wallet/EnableGlobalReimbursements').default,
[SCREENS.SETTINGS.WALLET.SHARE_BANK_ACCOUNT]: () => require('../../../../pages/settings/Wallet/ShareBankAccount/ShareBankAccount').default,
[SCREENS.SETTINGS.ADD_DEBIT_CARD]: () => require('../../../../pages/settings/Wallet/AddDebitCardPage').default,
diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts
index f4ffc0191c74..95e867346e8a 100755
--- a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts
+++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts
@@ -38,6 +38,7 @@ const SETTINGS_TO_RHP: Partial['config'] = {
path: ROUTES.SETTINGS_ENABLE_PAYMENTS,
exact: true,
},
+ [SCREENS.SETTINGS.WALLET.UNSHARE_BANK_ACCOUNT]: {
+ path: ROUTES.SETTINGS_WALLET_UNSHARE_BANK_ACCOUNT.route,
+ exact: true,
+ },
[SCREENS.SETTINGS.WALLET.ENABLE_GLOBAL_REIMBURSEMENTS]: {
path: ROUTES.SETTINGS_WALLET_ENABLE_GLOBAL_REIMBURSEMENTS.route,
exact: true,
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 30eaaae910ff..58e320b05a4f 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -201,6 +201,9 @@ type SettingsNavigatorParamList = {
[SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE]: undefined;
[SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT]: undefined;
[SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: undefined;
+ [SCREENS.SETTINGS.WALLET.UNSHARE_BANK_ACCOUNT]: {
+ bankAccountID: string;
+ };
[SCREENS.SETTINGS.WALLET.ENABLE_GLOBAL_REIMBURSEMENTS]: {
bankAccountID: string;
};
diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts
index 4d033fae568d..1fbdcaf9292f 100644
--- a/src/libs/actions/BankAccounts.ts
+++ b/src/libs/actions/BankAccounts.ts
@@ -15,6 +15,7 @@ import type {
SaveCorpayOnboardingBeneficialOwnerParams,
SendReminderForCorpaySignerInformationParams,
ShareBankAccountParams,
+ UnshareBankAccountParams,
ValidateBankAccountWithTransactionsParams,
VerifyIdentityForBankAccountParams,
} from '@libs/API/parameters';
@@ -1220,6 +1221,56 @@ function fetchCorpayFields(bankCountry: string, bankCurrency?: string, isWithdra
);
}
+function clearUnshareBankAccountErrors(bankAccountID: number) {
+ Onyx.merge(ONYXKEYS.UNSHARE_BANK_ACCOUNT, {errors: null});
+ Onyx.merge(ONYXKEYS.BANK_ACCOUNT_LIST, {[bankAccountID]: {errors: null}});
+}
+
+function unshareBankAccount(bankAccountID: number, ownerEmail: string) {
+ const parameters: UnshareBankAccountParams = {
+ bankAccountID,
+ ownerEmail,
+ };
+
+ const onyxData: OnyxData = {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.UNSHARE_BANK_ACCOUNT,
+ value: {
+ isLoading: true,
+ errors: null,
+ email: ownerEmail,
+ },
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.UNSHARE_BANK_ACCOUNT,
+ value: {
+ isLoading: false,
+ errors: null,
+ shouldShowSuccess: true,
+ email: null,
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.UNSHARE_BANK_ACCOUNT,
+ value: {
+ isLoading: false,
+ errors: getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'),
+ },
+ },
+ ],
+ };
+
+ API.write(WRITE_COMMANDS.UNSHARE_BANK_ACCOUNT, parameters, onyxData);
+}
+
function createCorpayBankAccountForWalletFlow(data: InternationalBankAccountForm, classification: string, destinationCountry: string, preferredMethod: string) {
const inputData = {
...data,
@@ -1410,6 +1461,8 @@ export {
createCorpayBankAccountForWalletFlow,
getCorpayOnboardingFields,
saveCorpayOnboardingCompanyDetails,
+ unshareBankAccount,
+ clearUnshareBankAccountErrors,
clearReimbursementAccountSaveCorpayOnboardingCompanyDetails,
saveCorpayOnboardingBeneficialOwners,
saveCorpayOnboardingDirectorInformation,
diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx
index 2c9432845785..d3be766079bf 100755
--- a/src/pages/settings/InitialSettingsPage.tsx
+++ b/src/pages/settings/InitialSettingsPage.tsx
@@ -132,6 +132,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr
const hasActivatedWallet = ([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM] as string[]).includes(userWallet?.tierName ?? '');
const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL, {canBeMissing: true});
const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL, {canBeMissing: true});
+ const [unsharedBankAccount] = useOnyx(ONYXKEYS.UNSHARE_BANK_ACCOUNT, {canBeMissing: true});
const privateSubscription = usePrivateSubscription();
const subscriptionPlan = useSubscriptionPlan();
const previousUserPersonalDetails = usePrevious(currentUserPersonalDetails);
@@ -146,7 +147,13 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr
const hasBrokenFeedConnection = checkIfFeedConnectionIsBroken(allCards, CONST.EXPENSIFY_CARD.BANK);
const hasPendingCardAction = hasPendingExpensifyCardAction(allCards, privatePersonalDetails);
const walletBrickRoadIndicator = useMemo(() => {
- if (hasPaymentMethodError(bankAccountList, fundList, allCards) || !isEmptyObject(userWallet?.errors) || !isEmptyObject(walletTerms?.errors) || hasBrokenFeedConnection) {
+ if (
+ hasPaymentMethodError(bankAccountList, fundList, allCards) ||
+ !isEmptyObject(userWallet?.errors) ||
+ !isEmptyObject(walletTerms?.errors) ||
+ !isEmptyObject(unsharedBankAccount?.errors) ||
+ hasBrokenFeedConnection
+ ) {
return CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
}
if (hasPartiallySetupBankAccount(bankAccountList)) {
@@ -156,7 +163,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr
return CONST.BRICK_ROAD_INDICATOR_STATUS.INFO;
}
return undefined;
- }, [allCards, bankAccountList, fundList, hasBrokenFeedConnection, hasPendingCardAction, userWallet?.errors, walletTerms?.errors]);
+ }, [allCards, bankAccountList, fundList, hasBrokenFeedConnection, hasPendingCardAction, unsharedBankAccount?.errors, userWallet?.errors, walletTerms?.errors]);
const [shouldShowSignoutConfirmModal, setShouldShowSignoutConfirmModal] = useState(false);
diff --git a/src/pages/settings/Wallet/UnshareBankAccount/UnshareBankAccount.tsx b/src/pages/settings/Wallet/UnshareBankAccount/UnshareBankAccount.tsx
new file mode 100644
index 000000000000..acbbad521004
--- /dev/null
+++ b/src/pages/settings/Wallet/UnshareBankAccount/UnshareBankAccount.tsx
@@ -0,0 +1,189 @@
+import React, {useEffect, useState} from 'react';
+import {View} from 'react-native';
+import Button from '@components/Button';
+import ConfirmModal from '@components/ConfirmModal';
+import ErrorMessageRow from '@components/ErrorMessageRow';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import RenderHTML from '@components/RenderHTML';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import UserListItem from '@components/SelectionList/ListItem/UserListItem';
+import type {ListItem} from '@components/SelectionList/types';
+import Text from '@components/Text';
+import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
+import useDebouncedState from '@hooks/useDebouncedState';
+import useLocalize from '@hooks/useLocalize';
+import useOnyx from '@hooks/useOnyx';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {formatMemberForList, getHeaderMessage, getSearchValueForPhoneOrEmail} from '@libs/OptionsListUtils';
+import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils';
+import tokenizedSearch from '@libs/tokenizedSearch';
+import Navigation from '@navigation/Navigation';
+import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types';
+import type {SettingsNavigatorParamList} from '@navigation/types';
+import {clearUnshareBankAccountErrors, unshareBankAccount} from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import type SCREENS from '@src/SCREENS';
+
+type ShareBankAccountProps = PlatformStackScreenProps;
+
+function UnshareBankAccount({route}: ShareBankAccountProps) {
+ const bankAccountID = route.params?.bankAccountID;
+ const styles = useThemeStyles();
+ const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST, {canBeMissing: true});
+ const [showExpensifyCardErrorModal, setShowExpensifyCardErrorModal] = useState(false);
+ const currentUserPersonalDetails = useCurrentUserPersonalDetails();
+ const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false});
+ const [unsharedBankAccountData] = useOnyx(ONYXKEYS.UNSHARE_BANK_ACCOUNT, {canBeMissing: true});
+ const [unshareUser, setUnshareUser] = useState<{login?: string | null; text?: string | null} | undefined>(undefined);
+ const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
+ const {translate} = useLocalize();
+ const admins = bankAccountList?.[bankAccountID]?.accountData?.sharees;
+ const totalAdmins = bankAccountList?.[bankAccountID]?.accountData?.sharees?.length;
+ const isExpensifyCardSettlementAccount = bankAccountList?.[bankAccountID]?.isExpensifyCardSettlementAccount ?? false;
+ const shouldShowTextInput = Number(totalAdmins) >= CONST.STANDARD_LIST_ITEM_LIMIT;
+ const textInputLabel = shouldShowTextInput ? translate('common.search') : undefined;
+ const isLoading = unsharedBankAccountData?.isLoading ?? false;
+ const shouldShowSuccess = unsharedBankAccountData?.shouldShowSuccess ?? false;
+
+ useEffect(() => {
+ if (!shouldShowSuccess) {
+ return;
+ }
+ if (!totalAdmins) {
+ Navigation.goBack();
+ }
+ }, [totalAdmins, shouldShowSuccess]);
+
+ const handleUnshare = () => {
+ if (!bankAccountID || !unshareUser?.login) {
+ return;
+ }
+
+ // Unsharing a bank account isn’t possible if the selected user’s copy of the bank account is set as an Expensify Card settlement account.
+ if (isExpensifyCardSettlementAccount) {
+ setUnshareUser(undefined);
+ setShowExpensifyCardErrorModal(true);
+ return;
+ }
+ unshareBankAccount(Number(bankAccountID), unshareUser.login);
+ setUnshareUser(undefined);
+ };
+
+ const getAdminsList = () => {
+ if (admins?.length === 0) {
+ return [];
+ }
+ const adminsWithInfo =
+ admins
+ ?.filter((admin) => admin !== currentUserPersonalDetails?.email)
+ .map((admin) => {
+ const personalDetails = getPersonalDetailByEmail(admin);
+ const formattedAdmin = formatMemberForList({
+ text: personalDetails?.displayName,
+ alternateText: personalDetails?.login,
+ keyForList: personalDetails?.login,
+ accountID: personalDetails?.accountID,
+ login: personalDetails?.login,
+ pendingAction: personalDetails?.pendingAction,
+ reportID: '',
+ });
+ return {...formattedAdmin, isInteractive: false};
+ }) ?? [];
+
+ let adminsToDisplay = [...adminsWithInfo];
+ if (debouncedSearchTerm) {
+ const searchValue = getSearchValueForPhoneOrEmail(debouncedSearchTerm, countryCode).toLowerCase();
+ adminsToDisplay = tokenizedSearch(adminsWithInfo, searchValue, (option) => [option.text ?? '', option.alternateText ?? '']);
+ }
+ return adminsToDisplay;
+ };
+
+ const hideUnshareErrorModal = () => setShowExpensifyCardErrorModal(false);
+
+ const itemRightSideComponent = (item: ListItem) => {
+ return (
+