From aae910efed678a01cbb1c0fca36c0564266511c4 Mon Sep 17 00:00:00 2001 From: mhawryluk Date: Thu, 27 Nov 2025 13:57:39 +0100 Subject: [PATCH 01/32] Implement new AddDomain, DomainAdded, AccessRestricted and VerifyAccount pages --- src/CONST/index.ts | 2 +- src/ONYXKEYS.ts | 3 + src/ROUTES.ts | 10 ++ src/SCREENS.ts | 4 + src/components/Domain/DomainMenuItem.tsx | 3 +- src/languages/en.ts | 18 ++++ src/libs/API/types.ts | 2 + .../ModalStackNavigators/index.tsx | 4 + .../RELATIONS/WORKSPACES_LIST_TO_RHP.ts | 11 +- src/libs/Navigation/linkingConfig/config.ts | 10 ++ src/libs/Navigation/types.ts | 8 ++ src/libs/actions/Domain.ts | 25 ++++- src/pages/domain/AddDomainPage.tsx | 102 ++++++++++++++++++ .../domain/AddDomainVerifyAccountPage.tsx | 15 +++ src/pages/domain/BaseVerifyDomainPage.tsx | 9 +- .../domain/DomainAccessRestrictedPage.tsx | 100 +++++++++++++++++ src/pages/domain/DomainAddedPage.tsx | 37 +++++++ src/pages/workspace/WorkspacesListPage.tsx | 36 ++++++- src/types/form/CreateDomainForm.ts | 21 ++++ src/types/form/index.ts | 1 + src/types/onyx/Domain.ts | 3 + 21 files changed, 409 insertions(+), 15 deletions(-) create mode 100644 src/pages/domain/AddDomainPage.tsx create mode 100644 src/pages/domain/AddDomainVerifyAccountPage.tsx create mode 100644 src/pages/domain/DomainAccessRestrictedPage.tsx create mode 100644 src/pages/domain/DomainAddedPage.tsx create mode 100644 src/types/form/CreateDomainForm.ts diff --git a/src/CONST/index.ts b/src/CONST/index.ts index da2b20e50bd55..856ffe035261a 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1028,7 +1028,7 @@ const CONST = { COLLECT_UPGRADE_HELP_URL: 'https://help.expensify.com/Hidden/collect-upgrade', MERGE_ACCOUNT_HELP_URL: 'https://help.expensify.com/articles/new-expensify/settings/Merge-Accounts', CONNECT_A_BUSINESS_BANK_ACCOUNT_HELP_URL: 'https://help.expensify.com/articles/new-expensify/expenses-&-payments/Connect-a-Business-Bank-Account', - DOMAIN_VERIFICATION_HELP_URL: 'https://help.expensify.com/articles/expensify-classic/domains/Claim-And-Verify-A-Domain', + DOMAIN_VERIFICATION_HELP_URL: 'https://help.expensify.com/articles/new-expensify/workspaces/Verify-a-Domain', SAML_HELP_URL: 'https://help.expensify.com/articles/expensify-classic/domains/Managing-Single-Sign-On-(SSO)-in-Expensify', REGISTER_FOR_WEBINAR_URL: 'https://events.zoom.us/eo/Aif1I8qCi1GZ7KnLnd1vwGPmeukSRoPjFpyFAZ2udQWn0-B86e1Z~AggLXsr32QYFjq8BlYLZ5I06Dg', TEST_RECEIPT_URL: `${CLOUDFRONT_URL}/images/fake-receipt__tacotodds.png`, diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 57adfe5351159..ec9101b822efc 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -923,6 +923,8 @@ const ONYXKEYS = { WORKSPACE_PER_DIEM_FORM_DRAFT: 'workspacePerDiemFormDraft', ENABLE_GLOBAL_REIMBURSEMENTS: 'enableGlobalReimbursementsForm', ENABLE_GLOBAL_REIMBURSEMENTS_DRAFT: 'enableGlobalReimbursementsFormDraft', + CREATE_DOMAIN_FORM: 'createDomainForm', + CREATE_DOMAIN_FORM_DRAFT: 'createDomainFormDraft', }, DERIVED: { REPORT_ATTRIBUTES: 'reportAttributes', @@ -1037,6 +1039,7 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.INTERNATIONAL_BANK_ACCOUNT_FORM]: FormTypes.InternationalBankAccountForm; [ONYXKEYS.FORMS.WORKSPACE_PER_DIEM_FORM]: FormTypes.WorkspacePerDiemForm; [ONYXKEYS.FORMS.ENABLE_GLOBAL_REIMBURSEMENTS]: FormTypes.EnableGlobalReimbursementsForm; + [ONYXKEYS.FORMS.CREATE_DOMAIN_FORM]: FormTypes.AddDomainForm; }; type OnyxFormDraftValuesMapping = { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 5c9b2faacd532..a05aa14a243bc 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -3375,6 +3375,16 @@ const ROUTES = { route: 'workspaces/domain-verified/:accountID', getRoute: (accountID: number) => `workspaces/domain-verified/${accountID}` as const, }, + WORKSPACES_ADD_DOMAIN: 'workspaces/add-domain', + WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT: `workspaces/add-domain/${VERIFY_ACCOUNT}`, + WORKSPACES_DOMAIN_ADDED: { + route: 'workspaces/domain-added/:accountID', + getRoute: (accountID: number) => `workspaces/domain-added/${accountID}` as const, + }, + WORKSPACES_DOMAIN_ACCESS_RESTRICTED: { + route: 'workspaces/domain-access-restricted/:accountID', + getRoute: (accountID: number) => `workspaces/domain-access-restricted/${accountID}` as const, + }, DOMAIN_INITIAL: { route: 'domain/:accountID', getRoute: (accountID: number) => `domain/${accountID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index a713e3e51cef3..aac272728c00a 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -827,6 +827,10 @@ const SCREENS = { }, WORKSPACES_VERIFY_DOMAIN: 'Workspaces_Verify_Domain', WORKSPACES_DOMAIN_VERIFIED: 'Workspaces_Domain_Verified', + WORKSPACES_ADD_DOMAIN: 'Workspaces_Add_Domain', + WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT: 'Workspaces_Add_Domain_VerifyAccount', + WORKSPACES_DOMAIN_ADDED: 'Workspaces_Domain_Added', + WORKSPACES_DOMAIN_ACCESS_RESTRICTED: 'Workspaces_Domain_Access_Restricted', DOMAIN: { VERIFY: 'Domain_Verify', VERIFIED: 'Domain_Verified', diff --git a/src/components/Domain/DomainMenuItem.tsx b/src/components/Domain/DomainMenuItem.tsx index 1c191445dec19..005fe6a2ff91f 100644 --- a/src/components/Domain/DomainMenuItem.tsx +++ b/src/components/Domain/DomainMenuItem.tsx @@ -74,8 +74,7 @@ function DomainMenuItem({item, index}: DomainMenuItemProps) { role={CONST.ROLE.BUTTON} accessibilityLabel="row" style={styles.mh5} - onPress={action} - disabled={!isAdmin} + onPress={item.action} > {({hovered}) => ( `Please verify yourself as an authorized company administrator for ${domainName} if you need control over:`, + companyCardManagement: 'Company card management', + accountCreationAndDeletion: 'Account creation and deletion', + workspaceCreation: 'Workspace creation', + samlSSO: 'SAML SSO', + }, + addDomain: { + title: 'Add domain', + subtitle: 'Enter the name of the private domain you want to access (e.g. expensify.com)', + domainName: 'Domain name', + }, + domainAdded: { + title: 'Domain added', + description: "Next, you'll need to verify ownership of the domain and adjust your security settings.", + configure: 'Configure', + }, }, }; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 9deecea130b84..bf99c861c4d81 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -521,6 +521,7 @@ const WRITE_COMMANDS = { SET_SAML_IDENTITY: 'SetSAMLIdentity', UPDATE_SAML_ENABLED: 'UpdateSAMLEnabled', UPDATE_SAML_REQUIRED: 'UpdateSAMLRequired', + CREATE_DOMAIN: 'CreateDomain', } as const; type WriteCommand = ValueOf; @@ -1063,6 +1064,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.SET_SAML_IDENTITY]: Parameters.SetSamlIdentityParams; [WRITE_COMMANDS.UPDATE_SAML_ENABLED]: Parameters.UpdateSamlEnabledParams; [WRITE_COMMANDS.UPDATE_SAML_REQUIRED]: Parameters.UpdateSamlRequiredParams; + [WRITE_COMMANDS.CREATE_DOMAIN]: Parameters.DomainParams; }; const READ_COMMANDS = { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 1b55a8080a8e5..88c9f573b2507 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -939,6 +939,10 @@ const ScheduleCallModalStackNavigator = createModalStackNavigator({ [SCREENS.WORKSPACES_VERIFY_DOMAIN]: () => require('../../../../pages/domain/WorkspacesVerifyDomainPage').default, [SCREENS.WORKSPACES_DOMAIN_VERIFIED]: () => require('../../../../pages/domain/WorkspacesDomainVerifiedPage').default, + [SCREENS.WORKSPACES_ADD_DOMAIN]: () => require('../../../../pages/domain/AddDomainPage').default, + [SCREENS.WORKSPACES_DOMAIN_ADDED]: () => require('../../../../pages/domain/DomainAddedPage').default, + [SCREENS.WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT]: () => require('../../../../pages/domain/AddDomainVerifyAccountPage').default, + [SCREENS.WORKSPACES_DOMAIN_ACCESS_RESTRICTED]: () => require('../../../../pages/domain/DomainAccessRestrictedPage').default, }); export { diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts index 40eebe61d4be7..a40fab3fc8194 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACES_LIST_TO_RHP.ts @@ -1,7 +1,16 @@ import SCREENS from '@src/SCREENS'; const WORKSPACES_LIST_TO_RHP: Record = { - [SCREENS.WORKSPACES_LIST]: [SCREENS.WORKSPACE_DUPLICATE.SELECT_FEATURES, SCREENS.WORKSPACE_DUPLICATE.ROOT, SCREENS.WORKSPACES_VERIFY_DOMAIN, SCREENS.WORKSPACES_DOMAIN_VERIFIED], + [SCREENS.WORKSPACES_LIST]: [ + SCREENS.WORKSPACE_DUPLICATE.SELECT_FEATURES, + SCREENS.WORKSPACE_DUPLICATE.ROOT, + SCREENS.WORKSPACES_VERIFY_DOMAIN, + SCREENS.WORKSPACES_DOMAIN_VERIFIED, + SCREENS.WORKSPACES_ADD_DOMAIN, + SCREENS.WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT, + SCREENS.WORKSPACES_DOMAIN_ADDED, + SCREENS.WORKSPACES_DOMAIN_ACCESS_RESTRICTED, + ], }; export default WORKSPACES_LIST_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 79eeb87850d55..8e8371a3c03e9 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1760,6 +1760,16 @@ const config: LinkingOptions['config'] = { path: ROUTES.WORKSPACES_DOMAIN_VERIFIED.route, exact: true, }, + [SCREENS.WORKSPACES_ADD_DOMAIN]: ROUTES.WORKSPACES_ADD_DOMAIN, + [SCREENS.WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT]: ROUTES.WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT, + [SCREENS.WORKSPACES_DOMAIN_ADDED]: { + path: ROUTES.WORKSPACES_DOMAIN_ADDED.route, + exact: true, + }, + [SCREENS.WORKSPACES_DOMAIN_ACCESS_RESTRICTED]: { + path: ROUTES.WORKSPACES_DOMAIN_ACCESS_RESTRICTED.route, + exact: true, + }, }, }, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 962dcff253ce5..dc1cb74780ad8 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2078,6 +2078,14 @@ type WorkspacesDomainModalNavigatorParamList = { [SCREENS.WORKSPACES_DOMAIN_VERIFIED]: { accountID: number; }; + [SCREENS.WORKSPACES_ADD_DOMAIN]: undefined; + [SCREENS.WORKSPACES_ADD_DOMAIN_VERIFY_ACCOUNT]: undefined; + [SCREENS.WORKSPACES_DOMAIN_ADDED]: { + accountID: number; + }; + [SCREENS.WORKSPACES_DOMAIN_ACCESS_RESTRICTED]: { + accountID: number; + }; }; type RightModalNavigatorParamList = { diff --git a/src/libs/actions/Domain.ts b/src/libs/actions/Domain.ts index 1ae75a17d01fc..431335191f2ab 100644 --- a/src/libs/actions/Domain.ts +++ b/src/libs/actions/Domain.ts @@ -49,7 +49,7 @@ function validateDomain(accountID: number, domainName: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.DOMAIN}${accountID}`, - value: {isValidationPending: true, domainValidationError: null}, + value: {isValidationPending: true, domainValidationError: null, hasValidationSucceeded: null}, }, ]; @@ -57,7 +57,7 @@ function validateDomain(accountID: number, domainName: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.DOMAIN}${accountID}`, - value: {isValidationPending: null}, + value: {isValidationPending: null, hasValidationSucceeded: true}, }, ]; @@ -304,6 +304,26 @@ async function getScimToken(domainName: string): Promise { } } +/** Sends request for claiming a domain */ +function createDomain(domainName: string) { + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.CREATE_DOMAIN_FORM, + value: {hasCreationSucceeded: null}, + }, + ]; + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.CREATE_DOMAIN_FORM, + value: {hasCreationSucceeded: true}, + }, + ]; + + API.write(WRITE_COMMANDS.CREATE_DOMAIN, {domainName}, {optimisticData, successData}); +} + export { getDomainValidationCode, validateDomain, @@ -316,4 +336,5 @@ export { resetSamlRequiredError, setSamlIdentity, getScimToken, + createDomain, }; diff --git a/src/pages/domain/AddDomainPage.tsx b/src/pages/domain/AddDomainPage.tsx new file mode 100644 index 0000000000000..b3afc9f2a456b --- /dev/null +++ b/src/pages/domain/AddDomainPage.tsx @@ -0,0 +1,102 @@ +import {Str} from 'expensify-common'; +import React, {useCallback, useEffect, useRef} from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +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 ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; +import TextInput from '@components/TextInput'; +import useAutoFocusInput from '@hooks/useAutoFocusInput'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {createDomain} from '@libs/actions/Domain'; +import Navigation from '@libs/Navigation/Navigation'; +import {getFieldRequiredErrors} from '@libs/ValidationUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type {CreateDomainForm} from '@src/types/form/CreateDomainForm'; +import INPUT_IDS from '@src/types/form/CreateDomainForm'; + +const hasCreationSucceededSelector = (form: OnyxEntry) => form?.hasCreationSucceeded; + +function AddDomainPage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {inputCallbackRef} = useAutoFocusInput(); + + const [hasCreationSucceeded] = useOnyx(ONYXKEYS.FORMS.CREATE_DOMAIN_FORM, {canBeMissing: true, selector: hasCreationSucceededSelector}); + const [allDomains] = useOnyx(ONYXKEYS.COLLECTION.DOMAIN, {canBeMissing: false}); + + const validate = useCallback((values: FormOnyxValues) => { + return getFieldRequiredErrors(values, [INPUT_IDS.DOMAIN_NAME]); + }, []); + + const domainNameSubmitted = useRef(undefined); + + useEffect(() => { + if (!hasCreationSucceeded) { + return; + } + + // Find the newly created domain + const accountID = Object.values(allDomains ?? {})?.find((domain) => domain && Str.extractEmailDomain(domain.email) === domainNameSubmitted.current)?.accountID; + if (accountID) { + Navigation.navigate(ROUTES.WORKSPACES_DOMAIN_ADDED.getRoute(accountID), {forceReplace: true}); + } + }, [hasCreationSucceeded, allDomains]); + + return ( + + Navigation.goBack(ROUTES.WORKSPACES_LIST.getRoute())} + /> + + + {translate('domain.addDomain.subtitle')} + + { + domainNameSubmitted.current = domainName; + createDomain(domainName); + }} + addBottomSafeAreaPadding + shouldRenderFooterAboveSubmit + > + + + + + + + ); +} + +AddDomainPage.displayName = 'AddDomainPage'; +export default AddDomainPage; diff --git a/src/pages/domain/AddDomainVerifyAccountPage.tsx b/src/pages/domain/AddDomainVerifyAccountPage.tsx new file mode 100644 index 0000000000000..da30a563096a1 --- /dev/null +++ b/src/pages/domain/AddDomainVerifyAccountPage.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import VerifyAccountPageBase from '@pages/settings/VerifyAccountPageBase'; +import ROUTES from '@src/ROUTES'; + +function AddDomainVerifyAccountPage() { + return ( + + ); +} + +AddDomainVerifyAccountPage.displayName = 'AddDomainVerifyAccountPage'; +export default AddDomainVerifyAccountPage; diff --git a/src/pages/domain/BaseVerifyDomainPage.tsx b/src/pages/domain/BaseVerifyDomainPage.tsx index 5dfb3d9576d87..e073f23a9d8c9 100644 --- a/src/pages/domain/BaseVerifyDomainPage.tsx +++ b/src/pages/domain/BaseVerifyDomainPage.tsx @@ -51,17 +51,16 @@ function BaseVerifyDomainPage({accountID, forwardTo}: BaseVerifyDomainPageProps) const [domain, domainMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${accountID}`, {canBeMissing: true}); const domainName = domain ? Str.extractEmailDomain(domain.email) : ''; - const [isAdmin, isAdminMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_ADMIN_ACCESS}${accountID}`, {canBeMissing: false}); const doesDomainExist = !!domain; const {asset: Exclamation} = useMemoizedLazyAsset(() => loadExpensifyIcon('Exclamation')); useEffect(() => { - if (!domain?.validated) { + if (!domain?.hasValidationSucceeded) { return; } Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(forwardTo, {forceReplace: true})); - }, [accountID, domain?.validated, forwardTo]); + }, [accountID, domain?.hasValidationSucceeded, forwardTo]); useEffect(() => { if (!doesDomainExist) { @@ -77,11 +76,11 @@ function BaseVerifyDomainPage({accountID, forwardTo}: BaseVerifyDomainPageProps) resetDomainValidationError(accountID); }, [accountID, doesDomainExist]); - if (isLoadingOnyxValue(domainMetadata, isAdminMetadata)) { + if (isLoadingOnyxValue(domainMetadata)) { return ; } - if (!domain || !isAdmin) { + if (!domain) { return Navigation.dismissModal()} />; } diff --git a/src/pages/domain/DomainAccessRestrictedPage.tsx b/src/pages/domain/DomainAccessRestrictedPage.tsx new file mode 100644 index 0000000000000..c1169bd60fb57 --- /dev/null +++ b/src/pages/domain/DomainAccessRestrictedPage.tsx @@ -0,0 +1,100 @@ +import {Str} from 'expensify-common'; +import React from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import Button from '@components/Button'; +import FixedFooter from '@components/FixedFooter'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Icon from '@components/Icon'; +import {Checkmark} from '@components/Icon/Expensicons'; +import RenderHTML from '@components/RenderHTML'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {WorkspacesDomainModalNavigatorParamList} from '@libs/Navigation/types'; +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 {Domain} from '@src/types/onyx'; + +type DomainAccessRestrictedPageProps = PlatformStackScreenProps; + +const domainNameSelector = (domain: OnyxEntry) => (domain?.email ? Str.extractEmailDomain(domain.email) : undefined); + +const FEATURES: TranslationPaths[] = [ + 'domain.accessRestricted.companyCardManagement', + 'domain.accessRestricted.accountCreationAndDeletion', + 'domain.accessRestricted.workspaceCreation', + 'domain.accessRestricted.samlSSO', +]; + +function DomainAccessRestrictedPage({route}: DomainAccessRestrictedPageProps) { + const styles = useThemeStyles(); + const theme = useTheme(); + const {translate} = useLocalize(); + + const accountID = route.params.accountID; + const [domainName] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${accountID}`, {canBeMissing: false, selector: domainNameSelector}); + + if (!domainName) { + return ; + } + + return ( + + Navigation.goBack()} + /> + + + + + + + + {FEATURES.map((featureTranslationPath) => ( + + + {translate(featureTranslationPath)} + + ))} + + + + +