diff --git a/assets/images/integrationicons/circle-slash.svg b/assets/images/integrationicons/circle-slash.svg deleted file mode 100644 index ff09f67d3a88..000000000000 --- a/assets/images/integrationicons/circle-slash.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/assets/images/integrationicons/microsoft-dynamics-icon-square.svg b/assets/images/integrationicons/microsoft-dynamics-icon-square.svg deleted file mode 100644 index 37dc57c5ae66..000000000000 --- a/assets/images/integrationicons/microsoft-dynamics-icon-square.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/images/integrationicons/oracle-icon-square.svg b/assets/images/integrationicons/oracle-icon-square.svg deleted file mode 100644 index 427e34ad2d69..000000000000 --- a/assets/images/integrationicons/oracle-icon-square.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/assets/images/integrationicons/sap-icon-square.svg b/assets/images/integrationicons/sap-icon-square.svg deleted file mode 100644 index 6043a3ae07b5..000000000000 --- a/assets/images/integrationicons/sap-icon-square.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/CONST.ts b/src/CONST.ts index 798e963df78d..ae0ae7b04bde 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -69,10 +69,6 @@ const ONBOARDING_ACCOUNTING_MAPPING = { netsuite: 'NetSuite', intacct: 'Sage Intacct', quickbooksDesktop: 'QuickBooks Desktop', - sap: 'SAP', - oracle: 'Oracle', - microsoftDynamics: 'Microsoft Dynamics', - other: 'Other', }; const connectionsVideoPaths = { @@ -277,7 +273,7 @@ type OnboardingPurpose = ValueOf; type OnboardingCompanySize = ValueOf; -type OnboardingAccounting = keyof typeof CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY | null; +type OnboardingAccounting = ValueOf | null; const onboardingInviteTypes = { IOU: 'iou', @@ -3019,10 +3015,6 @@ const CONST = { financialForce: 'FinancialForce', billCom: 'Bill.com', zenefits: 'Zenefits', - sap: 'SAP', - oracle: 'Oracle', - microsoftDynamics: 'Microsoft Dynamics', - other: 'Other', }, AUTH_HELP_LINKS: { intacct: diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index 4832e71ce248..cc3b7f71e826 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -137,7 +137,7 @@ function FeatureTrainingModal({ illustrationAspectRatio: illustrationAspectRatioProp, image, contentFitImage, - width = variables.featureTrainingModalWidth, + width = variables.onboardingModalWidth, title = '', description = '', secondaryDescription = '', diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 2d33d3d253f8..dda9a9f7ff7f 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -118,15 +118,11 @@ import ImageCropCircleMask from '@assets/images/image-crop-circle-mask.svg'; import ImageCropSquareMask from '@assets/images/image-crop-square-mask.svg'; import Inbox from '@assets/images/inbox.svg'; import Info from '@assets/images/info.svg'; -import CircleSlash from '@assets/images/integrationicons/circle-slash.svg'; -import MicrosoftDynamicsSquare from '@assets/images/integrationicons/microsoft-dynamics-icon-square.svg'; import NetSuiteSquare from '@assets/images/integrationicons/netsuite-icon-square.svg'; -import OracleSquare from '@assets/images/integrationicons/oracle-icon-square.svg'; import QBDSquare from '@assets/images/integrationicons/qbd-icon-square.svg'; import QBOCircle from '@assets/images/integrationicons/qbo-icon-circle.svg'; import QBOSquare from '@assets/images/integrationicons/qbo-icon-square.svg'; import SageIntacctSquare from '@assets/images/integrationicons/sage-intacct-icon-square.svg'; -import SapSquare from '@assets/images/integrationicons/sap-icon-square.svg'; import XeroCircle from '@assets/images/integrationicons/xero-icon-circle.svg'; import XeroSquare from '@assets/images/integrationicons/xero-icon-square.svg'; import InvoiceGeneric from '@assets/images/invoice-generic.svg'; @@ -281,7 +277,6 @@ export { CreditCard, CreditCardHourglass, CreditCardExclamation, - CircleSlash, DeletedRoomAvatar, Document, DocumentSlash, @@ -434,9 +429,6 @@ export { NetSuiteSquare, XeroCircle, QBOCircle, - MicrosoftDynamicsSquare, - OracleSquare, - SapSquare, Filters, CalendarSolid, Filter, diff --git a/src/components/RadioButtonWithLabel.tsx b/src/components/RadioButtonWithLabel.tsx index d51c8102b0b2..43f44065f5d9 100644 --- a/src/components/RadioButtonWithLabel.tsx +++ b/src/components/RadioButtonWithLabel.tsx @@ -1,4 +1,4 @@ -import type {ReactNode} from 'react'; +import type {ComponentType} from 'react'; import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; @@ -21,27 +21,24 @@ type RadioButtonWithLabelProps = { /** Text that appears next to check box */ label?: string; - /** React element to display for the label */ - labelElement?: ReactNode; + /** Component to display for label */ + LabelComponent?: ComponentType; - /** Should the input be styled for errors */ + /** Should the input be styled for errors */ hasError?: boolean; /** Error text to display */ errorText?: string; - - /** Additional styles to apply to the wrapper */ - wrapperStyle?: StyleProp; }; const PressableWithFeedback = Pressables.PressableWithFeedback; -function RadioButtonWithLabel({labelElement, style, label = '', hasError = false, errorText = '', isChecked, onPress, wrapperStyle}: RadioButtonWithLabelProps) { +function RadioButtonWithLabel({LabelComponent, style, label = '', hasError = false, errorText = '', isChecked, onPress}: RadioButtonWithLabelProps) { const styles = useThemeStyles(); const defaultStyles = [styles.flexRow, styles.alignItemsCenter]; - if (!label && !labelElement) { - throw new Error('Must provide at least label or labelComponent prop'); + if (!label && !LabelComponent) { + throw new Error('Must provide at least label or LabelComponent prop'); } return ( <> @@ -57,13 +54,13 @@ function RadioButtonWithLabel({labelElement, style, label = '', hasError = false accessible={false} onPress={onPress} style={[styles.flexRow, styles.flexWrap, styles.flexShrink1, styles.alignItemsCenter]} - wrapperStyle={[styles.flex1, styles.ml3, styles.pr2, wrapperStyle]} + wrapperStyle={[styles.flex1, styles.ml3, styles.pr2]} // disable hover style when disabled hoverDimmingValue={0.8} pressDimmingValue={0.5} > {!!label && {label}} - {!!labelElement && labelElement} + {!!LabelComponent && } diff --git a/src/languages/en.ts b/src/languages/en.ts index f7d16b0a552c..f4c56864cfd1 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2054,7 +2054,7 @@ const translations = { }, accounting: { title: 'Do you use any accounting software?', - none: 'None', + noneOfAbove: 'None of the above', }, error: { requiredFirstName: 'Please input your first name to continue', @@ -4355,9 +4355,6 @@ const translations = { xero: 'Xero', netsuite: 'NetSuite', intacct: 'Sage Intacct', - sap: 'SAP', - oracle: 'Oracle', - microsoftDynamics: 'Microsoft Dynamics', talkYourOnboardingSpecialist: 'Chat with your setup specialist.', talkYourAccountManager: 'Chat with your account manager.', talkToConcierge: 'Chat with Concierge.', @@ -4386,7 +4383,7 @@ const translations = { import: 'Import', export: 'Export', advanced: 'Advanced', - other: 'Other', + other: 'Other integrations', syncNow: 'Sync now', disconnect: 'Disconnect', reinstall: 'Reinstall connector', diff --git a/src/languages/es.ts b/src/languages/es.ts index 95ad439d4a16..4fbf4529d1f4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2055,7 +2055,7 @@ const translations = { }, accounting: { title: '¿Utilizas algún software de contabilidad?', - none: 'Ninguno', + noneOfAbove: 'Ninguno de los anteriores', }, error: { requiredFirstName: 'Introduce tu nombre para continuar', @@ -4363,9 +4363,6 @@ const translations = { xero: 'Xero', netsuite: 'NetSuite', intacct: 'Sage Intacct', - sap: 'SAP', - oracle: 'Oracle', - microsoftDynamics: 'Microsoft Dynamics', talkYourOnboardingSpecialist: 'Chatea con tu especialista asignado.', talkYourAccountManager: 'Chatea con tu gestor de cuenta.', talkToConcierge: 'Chatear con Concierge.', @@ -4394,7 +4391,7 @@ const translations = { import: 'Importar', export: 'Exportar', advanced: 'Avanzado', - other: 'Otro', + other: 'Otras integraciones', syncNow: 'Sincronizar ahora', disconnect: 'Desconectar', reinstall: 'Reinstalar el conector', diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 756b75f5a954..039cbc3a021a 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -9733,7 +9733,7 @@ function prepareOnboardingOnyxData( return; } - const integrationName = userReportedIntegration ? CONST.ONBOARDING_ACCOUNTING_MAPPING[userReportedIntegration as keyof typeof CONST.ONBOARDING_ACCOUNTING_MAPPING] : ''; + const integrationName = userReportedIntegration ? CONST.ONBOARDING_ACCOUNTING_MAPPING[userReportedIntegration] : ''; const assignedGuideEmail = getPolicy(targetChatPolicyID)?.assignedGuide?.email ?? 'Setup Specialist'; const assignedGuidePersonalDetail = Object.values(allPersonalDetails ?? {}).find((personalDetail) => personalDetail?.login === assignedGuideEmail); let assignedGuideAccountID: number; @@ -10122,7 +10122,7 @@ function prepareOnboardingOnyxData( key: `${ONYXKEYS.COLLECTION.POLICY}${onboardingPolicyID}`, value: { areConnectionsEnabled: true, - ...(requiresControlPlan.includes(userReportedIntegration as AllConnectionName) + ...(requiresControlPlan.includes(userReportedIntegration) ? { type: CONST.POLICY.TYPE.CORPORATE, } diff --git a/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx b/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx index c178947fac9e..25bd0b3a31c6 100644 --- a/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx +++ b/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx @@ -1,19 +1,16 @@ import HybridAppModule from '@expensify/react-native-hybrid-app'; -import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react'; -import {InteractionManager, View} from 'react-native'; +import React, {useContext, useEffect, useMemo, useState} from 'react'; +import {InteractionManager} from 'react-native'; import {useOnyx} from 'react-native-onyx'; -import type {SvgProps} from 'react-native-svg'; import Button from '@components/Button'; import CustomStatusBarAndBackgroundContext from '@components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; -import FixedFooter from '@components/FixedFooter'; import FormHelpMessage from '@components/FormHelpMessage'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; -import {PressableWithoutFeedback} from '@components/Pressable'; -import RadioButtonWithLabel from '@components/RadioButtonWithLabel'; import ScreenWrapper from '@components/ScreenWrapper'; -import ScrollView from '@components/ScrollView'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; import Text from '@components/Text'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; @@ -35,61 +32,12 @@ import Navigation from '@libs/Navigation/Navigation'; import {isPaidGroupPolicy, isPolicyAdmin} from '@libs/PolicyUtils'; import variables from '@styles/variables'; import CONFIG from '@src/CONFIG'; -import type {OnboardingAccounting} from '@src/CONST'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; +import type {OnboardingAccounting} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {} from '@src/types/onyx/Bank'; import type {BaseOnboardingAccountingProps} from './types'; -type Integration = { - key: OnboardingAccounting; - icon: React.FC; - translationKey: TranslationPaths; -}; - -const integrations: Integration[] = [ - { - key: 'quickbooksOnline', - icon: Expensicons.QBOCircle, - translationKey: 'workspace.accounting.qbo', - }, - { - key: 'quickbooksDesktop', - icon: Expensicons.QBDSquare, - translationKey: 'workspace.accounting.qbd', - }, - { - key: 'xero', - icon: Expensicons.XeroCircle, - translationKey: 'workspace.accounting.xero', - }, - { - key: 'netsuite', - icon: Expensicons.NetSuiteSquare, - translationKey: 'workspace.accounting.netsuite', - }, - { - key: 'intacct', - icon: Expensicons.IntacctSquare, - translationKey: 'workspace.accounting.intacct', - }, - { - key: 'sap', - icon: Expensicons.SapSquare, - translationKey: 'workspace.accounting.sap', - }, - { - key: 'oracle', - icon: Expensicons.OracleSquare, - translationKey: 'workspace.accounting.oracle', - }, - { - key: 'microsoftDynamics', - icon: Expensicons.MicrosoftDynamicsSquare, - translationKey: 'workspace.accounting.microsoftDynamics', - }, -]; - type OnboardingListItem = ListItem & { keyForList: OnboardingAccounting; }; @@ -141,208 +89,177 @@ function BaseOnboardingAccounting({shouldUseNativeStyles}: BaseOnboardingAccount }, [isLoading, prevIsLoading, setRootStatusBarEnabled]); const accountingOptions: OnboardingListItem[] = useMemo(() => { - const createAccountingOption = (integration: Integration): OnboardingListItem => ({ - keyForList: integration.key, - text: translate(integration.translationKey), - leftElement: ( - - ), - isSelected: userReportedIntegration === integration.key, - }); - + const policyAccountingOptions = Object.values(CONST.POLICY.CONNECTIONS.NAME) + .map((connectionName): OnboardingListItem | undefined => { + let text; + let accountingIcon; + switch (connectionName) { + case CONST.POLICY.CONNECTIONS.NAME.QBO: { + text = translate('workspace.accounting.qbo'); + accountingIcon = Expensicons.QBOCircle; + break; + } + case CONST.POLICY.CONNECTIONS.NAME.QBD: { + text = translate('workspace.accounting.qbd'); + accountingIcon = Expensicons.QBDSquare; + break; + } + case CONST.POLICY.CONNECTIONS.NAME.XERO: { + text = translate('workspace.accounting.xero'); + accountingIcon = Expensicons.XeroCircle; + break; + } + case CONST.POLICY.CONNECTIONS.NAME.NETSUITE: { + text = translate('workspace.accounting.netsuite'); + accountingIcon = Expensicons.NetSuiteSquare; + break; + } + case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT: { + text = translate('workspace.accounting.intacct'); + accountingIcon = Expensicons.IntacctSquare; + break; + } + default: { + return; + } + } + return { + keyForList: connectionName, + text, + leftElement: ( + + ), + isSelected: userReportedIntegration === connectionName, + }; + }) + .filter((item): item is OnboardingListItem => !!item); const noneAccountingOption: OnboardingListItem = { keyForList: null, - text: translate('onboarding.accounting.none'), + text: translate('onboarding.accounting.noneOfAbove'), leftElement: ( ), isSelected: userReportedIntegration === null, }; + return [...policyAccountingOptions, noneAccountingOption]; + }, [StyleUtils, styles.mr3, styles.onboardingSmallIcon, theme.success, translate, userReportedIntegration]); - const othersAccountingOption: OnboardingListItem = { - keyForList: 'other', - text: translate('workspace.accounting.other'), - leftElement: ( - + {!!error && ( + - ), - isSelected: userReportedIntegration === 'other', - }; - - return [...integrations.map(createAccountingOption), othersAccountingOption, noneAccountingOption]; - }, [StyleUtils, styles.mr3, styles.onboardingSmallIcon, theme.icon, translate, userReportedIntegration]); - - const supportedIntegrationsInNewDot = useMemo(() => ['quickbooksOnline', 'quickbooksDesktop', 'xero', 'netsuite', 'intacct', 'other'] as OnboardingAccounting[], []); - - const handleContinue = useCallback(() => { - if (userReportedIntegration === undefined) { - setError(translate('onboarding.errorSelection')); - return; - } - - if (!onboardingPurposeSelected || !onboardingCompanySize) { - return; - } - - const shouldCreateWorkspace = !onboardingPolicyID && !paidGroupPolicy; - - // We need `adminsChatReportID` for `completeOnboarding`, but at the same time, we don't want to call `createWorkspace` more than once. - // If we have already created a workspace, we want to reuse the `onboardingAdminsChatReportID` and `onboardingPolicyID`. - const {adminsChatReportID, policyID} = shouldCreateWorkspace - ? createWorkspace(undefined, true, '', generatePolicyID(), CONST.ONBOARDING_CHOICES.MANAGE_TEAM, '', undefined, false, onboardingCompanySize) - : {adminsChatReportID: onboardingAdminsChatReportID, policyID: onboardingPolicyID}; - - if (shouldCreateWorkspace) { - setOnboardingAdminsChatReportID(adminsChatReportID); - setOnboardingPolicyID(policyID); - } + )} +