From 96635abc692056842858efcdfaa276615380f802 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Fri, 15 Mar 2024 16:37:35 +0200 Subject: [PATCH 01/78] QBO import main page --- ios/Podfile.lock | 4 +- src/ROUTES.ts | 8 ++ src/SCREENS.ts | 2 + src/languages/en.ts | 13 +++ src/languages/es.ts | 13 +++ .../AppNavigator/ModalStackNavigators.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/libs/Navigation/types.ts | 9 ++ .../qbo/PolicyQuickbooksImportPage.tsx | 92 +++++++++++++++++++ src/types/onyx/Policy.ts | 4 +- 10 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d0007ec51668..b8ebda2a875b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1913,8 +1913,8 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: 13c8ef87792450193e117976337b8527b49e8c03 + Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 PODFILE CHECKSUM: a431c146e1501391834a2f299a74093bac53b530 -COCOAPODS: 1.13.0 +COCOAPODS: 1.11.3 diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 680c5bced9a9..c3a2898782cd 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -615,6 +615,14 @@ const ROUTES = { route: 'r/:reportID/transaction/:transactionID/receipt', getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const, }, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_IMPORT: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import', + getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_OPTION: { + route: 'workspace/:policyID/accounting/quickbooks-online/import/:option', + getRoute: (policyID: string, option: string) => `workspace/${policyID}/connections/quickbooks-online/import/${option}` as const, + }, } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 7ccb24aa19e5..4827514e3c5e 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -238,6 +238,8 @@ const SCREENS = { MEMBER_DETAILS: 'Workspace_Member_Details', MEMBER_DETAILS_ROLE_SELECTION: 'Workspace_Member_Details_Role_Selection', DISTANCE_RATES: 'Distance_Rates', + ACCOUNTING: 'Policy_Accounting', + QUICKBOOKSONLINE_IMPORT: 'Policy_Accounting_QuickbooksOnline_Import', }, EDIT_REQUEST: { diff --git a/src/languages/en.ts b/src/languages/en.ts index eecd81c54123..1188e72138df 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1769,6 +1769,19 @@ export default { requested: 'Requested', distanceRates: 'Distance rates', }, + qbo: { + import: 'Import', + importDescription: 'Choose which coding configurations are imported from QuickBooks Online to Expensify', + classes: 'Classes', + accounts: 'Chart of Accounts', + locations: 'Locations', + taxes: 'Taxes', + customers: 'Customers/Projects', + imported: 'Imported', + notImported: 'Not imported', + importedAsTags: 'Imported, displayed as tags', + importedAsReportFields: 'Imported, displayed as categories', + }, type: { free: 'Free', control: 'Control', diff --git a/src/languages/es.ts b/src/languages/es.ts index cd36f9071de6..88043e0c44e9 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1793,6 +1793,19 @@ export default { requested: 'Solicitado', distanceRates: 'Tasas de distancia', }, + qbo: { + import: 'Importación', + importDescription: 'Elija qué configuraciones de codificación se importan de QuickBooks Online a Expensify', + classes: 'Clases', + locations: 'Ubicaciones', + accounts: 'Catálogo de cuentas', + customers: 'Clientes/Proyectos', + imported: 'Importado', + taxes: 'Impuestos', + notImported: 'No importado', + importedAsTags: 'Importado, mostrado como etiquetas', + importedAsReportFields: 'Importado, mostrado como categorías', + }, type: { free: 'Gratis', control: 'Control', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 2e55593ddd01..17ae9f3470d5 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -267,6 +267,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/tags/WorkspaceTagsSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAG_CREATE]: () => require('../../../pages/workspace/tags/WorkspaceCreateTagPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: () => require('../../../pages/workspace/qbo/PolicyQuickbooksImportPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 56734e3c7242..2d279dc91bdd 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -232,6 +232,7 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CURRENCY]: { path: ROUTES.WORKSPACE_PROFILE_CURRENCY.route, }, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_IMPORT.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 939841279eed..cb0e454720f3 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -199,6 +199,9 @@ type SettingsNavigatorParamList = { accountID: string; backTo: Routes; }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; @@ -550,6 +553,12 @@ type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.DISTANCE_RATES]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING]: { + policyID: string; + }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: { + policyID: string; + }; }; type FullScreenNavigatorParamList = { diff --git a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx b/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx new file mode 100644 index 000000000000..552b49b8c8b7 --- /dev/null +++ b/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx @@ -0,0 +1,92 @@ +import React, {useCallback} from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; + +function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const quickbooksOnlineConfigTitles = { + DEFAULT: translate('workspace.qbo.imported'), + NONE: translate('workspace.qbo.notImported'), + TAG: translate('workspace.qbo.importedAsTags'), + REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), + }; + const {syncClasses, syncCustomers, syncLocations, syncAccounts, syncTaxes} = policy?.connections?.quickbooksOnline?.config ?? {}; + + const onPressConfigOption = useCallback((option: string) => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_OPTION.getRoute(policy?.id ?? '', option)), [policy?.id]); + + const sections = [ + { + description: translate('workspace.qbo.accounts'), + navigationKey: 'accounts', + errorIndicator: !!policy?.errors?.syncAccounts, + title: syncAccounts, + }, + { + description: translate('workspace.qbo.classes'), + navigationKey: 'classes', + errorIndicator: !!policy?.errors?.syncClasses, + title: syncClasses, + }, + { + description: translate('workspace.qbo.customers'), + navigationKey: 'customers', + errorIndicator: !!policy?.errors?.syncCustomers, + title: syncCustomers, + }, + { + description: translate('workspace.qbo.locations'), + navigationKey: 'locations', + errorIndicator: !!policy?.errors?.syncLocations, + title: syncLocations, + }, + { + description: translate('workspace.qbo.taxes'), + navigationKey: 'taxes', + errorIndicator: !!policy?.errors?.syncTaxes, + title: syncTaxes, + }, + ]; + + return ( + + + + {translate('workspace.qbo.importDescription')} + {sections.map((section) => ( + + onPressConfigOption(section.navigationKey)} + brickRoadIndicator={section.errorIndicator ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + /> + + ))} + + + ); +} + +PolicyQuickbooksImportPage.displayName = 'PolicyQuickbooksImportPage'; + +export default withPolicy(PolicyQuickbooksImportPage); diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 688300933a5e..3ed2e5c963ff 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -151,6 +151,8 @@ type QBOConnectionConfig = { syncClasses: IntegrationEntityMap; syncCustomers: IntegrationEntityMap; syncLocations: IntegrationEntityMap; + syncAccounts: IntegrationEntityMap; + syncTaxes: IntegrationEntityMap; exportDate: string; lastConfigurationTime: number; syncTax: boolean; @@ -357,4 +359,4 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< export default Policy; -export type {Unit, CustomUnit, Attributes, Rate, TaxRate, TaxRates, TaxRatesWithDefault, PendingJoinRequestPolicy}; +export type {Unit, CustomUnit, Attributes, Rate, TaxRate, TaxRates, TaxRatesWithDefault, PendingJoinRequestPolicy, IntegrationEntityMap}; From b9670c99d1a73168ff3fc5a278a2d80c96a0b392 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Fri, 15 Mar 2024 16:39:46 +0200 Subject: [PATCH 02/78] lock --- ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index b8ebda2a875b..d0007ec51668 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1913,8 +1913,8 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 + Yoga: 13c8ef87792450193e117976337b8527b49e8c03 PODFILE CHECKSUM: a431c146e1501391834a2f299a74093bac53b530 -COCOAPODS: 1.11.3 +COCOAPODS: 1.13.0 From 8e78317eae55798c4db5db9e53d12973ab8b4ace Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 19 Mar 2024 16:38:15 +0200 Subject: [PATCH 03/78] Add Chart of account sub page + new routes and Policy api --- src/ROUTES.ts | 22 +++++- src/SCREENS.ts | 5 ++ src/languages/en.ts | 3 + src/languages/es.ts | 3 + src/libs/API/types.ts | 1 + .../AppNavigator/ModalStackNavigators.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 5 ++ src/libs/actions/Policy.ts | 65 +++++++++++++++++ .../qbo/PolicyQuickbooksImportPage.tsx | 48 +++++++++++-- ...kbooksChartOfAccountsConfigurationPage.tsx | 72 +++++++++++++++++++ 10 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index bbb92351d244..332c9c959b64 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -634,9 +634,25 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import', getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_OPTION: { - route: 'workspace/:policyID/accounting/quickbooks-online/import/:option', - getRoute: (policyID: string, option: string) => `workspace/${policyID}/connections/quickbooks-online/import/${option}` as const, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/accounts', + getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/accounts` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/classes', + getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/classes` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/customers', + getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/customers` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/locations', + getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/locations` as const, + }, + POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES: { + route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/taxes', + getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/taxes` as const, }, } as const; diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 32c8c06933b5..ed7fd7e02cf7 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -243,6 +243,11 @@ const SCREENS = { CREATE_DISTANCE_RATE: 'Create_Distance_Rate', ACCOUNTING: 'Policy_Accounting', QUICKBOOKSONLINE_IMPORT: 'Policy_Accounting_QuickbooksOnline_Import', + QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: 'Policy_Accounting_QuickbooksOnline_Import_Chart_Of_Accounts', + QUICKBOOKSONLINE_CLASSES: 'Policy_Accounting_QuickbooksOnline_Import_Classes', + QUICKBOOKSONLINE_CUSTOMER: 'Policy_Accounting_QuickbooksOnline_Import_Customer', + QUICKBOOKSONLINE_LOCATIONS: 'Policy_Accounting_QuickbooksOnline_Import_Locations', + QUICKBOOKSONLINE_TAXES: 'Policy_Accounting_QuickbooksOnline_Import_Taxes', }, EDIT_REQUEST: { diff --git a/src/languages/en.ts b/src/languages/en.ts index 2170606d8241..696c635e33b8 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1781,6 +1781,9 @@ export default { notImported: 'Not imported', importedAsTags: 'Imported, displayed as tags', importedAsReportFields: 'Imported, displayed as categories', + accountsDescription: 'Chart of Accounts import as categories when connected to an accounting integration, this cannot be disabled.', + accountsSwitchTitle: 'Enable newly imported Chart of Accounts.', + accountsSwitchDescription: 'New categories imported from QuickBooks Online to Expensify will be either enabled or disabled by default.', }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 0a0e94b3fadd..2e95f7082f98 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1805,6 +1805,9 @@ export default { notImported: 'No importado', importedAsTags: 'Importado, mostrado como etiquetas', importedAsReportFields: 'Importado, mostrado como categorías', + accountsDescription: 'El plan de cuentas se importa como categorías cuando se conecta a una integración contable; esto no se puede desactivar.', + accountsSwitchTitle: 'Habilite el plan de cuentas recién importado.', + accountsSwitchDescription: 'Las nuevas categorías importadas de QuickBooks Online a Expensify estarán habilitadas o deshabilitadas de forma predeterminada.', }, type: { free: 'Gratis', diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 396aefa01a8e..8a36fed8903a 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -180,6 +180,7 @@ const WRITE_COMMANDS = { ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest', DECLINE_JOIN_REQUEST: 'DeclineJoinRequest', CREATE_POLICY_TAX: 'CreatePolicyTax', + UPDATE_POLICY_CONNECTIONS_CONFIGURATION: 'UpdatePolicyConnectionsConfiguration', CREATE_POLICY_DISTANCE_RATE: 'CreatePolicyDistanceRate', } as const; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index ebc0fbf19607..66e4e522e363 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -273,6 +273,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsForeignCurrency').default as React.ComponentType, [SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsWorkspaceCurrency').default as React.ComponentType, [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: () => require('../../../pages/workspace/qbo/PolicyQuickbooksImportPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: () => require('../../../pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index aef64cb0a843..ec533b4cff9b 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -233,6 +233,11 @@ const config: LinkingOptions['config'] = { path: ROUTES.WORKSPACE_PROFILE_CURRENCY.route, }, [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_IMPORT.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMER]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 2cb4801e09c6..73847ae8472e 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3258,6 +3258,70 @@ function openPolicyDistanceRatesPage(policyID?: string) { API.read(READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE, params); } +function updatePolicyConnectionConfig(policyID: string, connectionName: string, settingName: string, settingValue: string | boolean) { + const parameters = {policyID, connectionName, settingName, settingValue, idempotencyKey: settingName}; + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + pendingFields: { + [settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE + }, + connections: { + quickbooksOnline: { + config: { + [settingName]: settingValue, + }, + }, + }, + }, + }, + ]; + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + errorFields: { + [settingName]: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage') + }, + pendingFields: { + [settingName]: null + }, + connections: { + quickbooksOnline: { + config: { + [settingName]: settingValue, + }, + }, + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + pendingFields: { + [settingName]: null + }, + connections: { + quickbooksOnline: { + config: { + [settingName]: settingValue, + }, + }, + }, + }, + }, + ]; + + API.write(WRITE_COMMANDS.UPDATE_POLICY_CONNECTIONS_CONFIGURATION, parameters, {optimisticData, failureData, successData}); +} + function navigateWhenEnableFeature(policyID: string, featureRoute: Route) { const isNarrowLayout = getIsNarrowLayout(); @@ -4066,5 +4130,6 @@ export { setWorkspaceTagEnabled, setWorkspaceCurrencyDefault, setForeignCurrencyDefault, + updatePolicyConnectionConfig, setPolicyCustomTaxName, }; diff --git a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx b/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx index 552b49b8c8b7..46a3a2bec1ec 100644 --- a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx +++ b/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx @@ -13,47 +13,81 @@ import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +const NAVIGATION_KEYS = { + ACCOUNTS: 'accounts', + CLASSES: 'classes', + CUSTOMERS: 'customers', + LOCATIONS: 'locations', + TAXES: 'taxes', +}; + function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const quickbooksOnlineConfigTitles = { DEFAULT: translate('workspace.qbo.imported'), + true: translate('workspace.qbo.imported'), + false: translate('workspace.qbo.notImported'), NONE: translate('workspace.qbo.notImported'), TAG: translate('workspace.qbo.importedAsTags'), REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), }; - const {syncClasses, syncCustomers, syncLocations, syncAccounts, syncTaxes} = policy?.connections?.quickbooksOnline?.config ?? {}; + const {syncClasses, syncCustomers, syncLocations, syncTaxes, syncAccounts} = policy?.connections?.quickbooksOnline?.config ?? {}; - const onPressConfigOption = useCallback((option: string) => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_OPTION.getRoute(policy?.id ?? '', option)), [policy?.id]); + const onPressConfigOption = useCallback( + (option: string) => { + const policyID = policy?.id ?? ''; + switch (option) { + case NAVIGATION_KEYS.ACCOUNTS: + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)); + break; + case NAVIGATION_KEYS.CLASSES: + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)); + break; + case NAVIGATION_KEYS.CUSTOMERS: + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER.getRoute(policyID)); + break; + case NAVIGATION_KEYS.LOCATIONS: + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)); + break; + case NAVIGATION_KEYS.TAXES: + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)); + break; + default: + break; + } + }, + [policy?.id], + ); const sections = [ { description: translate('workspace.qbo.accounts'), - navigationKey: 'accounts', + navigationKey: NAVIGATION_KEYS.ACCOUNTS, errorIndicator: !!policy?.errors?.syncAccounts, title: syncAccounts, }, { description: translate('workspace.qbo.classes'), - navigationKey: 'classes', + navigationKey: NAVIGATION_KEYS.CLASSES, errorIndicator: !!policy?.errors?.syncClasses, title: syncClasses, }, { description: translate('workspace.qbo.customers'), - navigationKey: 'customers', + navigationKey: NAVIGATION_KEYS.CUSTOMERS, errorIndicator: !!policy?.errors?.syncCustomers, title: syncCustomers, }, { description: translate('workspace.qbo.locations'), - navigationKey: 'locations', + navigationKey: NAVIGATION_KEYS.LOCATIONS, errorIndicator: !!policy?.errors?.syncLocations, title: syncLocations, }, { description: translate('workspace.qbo.taxes'), - navigationKey: 'taxes', + navigationKey: NAVIGATION_KEYS.TAXES, errorIndicator: !!policy?.errors?.syncTaxes, title: syncTaxes, }, diff --git a/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx b/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx new file mode 100644 index 000000000000..e97bce1b4cbc --- /dev/null +++ b/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import {View} from 'react-native'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Switch from '@components/Switch'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import variables from '@styles/variables'; +import * as Policy from '@userActions/Policy'; + +function QuickbooksChartOfAccountsConfigurationPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const {enableNewCategories} = policy?.connections?.quickbooksOnline?.config ?? {}; + + return ( + + + + + {translate('workspace.qbo.accountsDescription')} + + + + {translate('workspace.qbo.accountsSwitchTitle')} + + {translate('workspace.qbo.accountsSwitchDescription')} + + + + + Policy.updatePolicyConnectionConfig( + policyID, + 'quickbooksOnline', + 'enableNewCategories', + !enableNewCategories, + )} + /> + + + + + + ); +} + +QuickbooksChartOfAccountsConfigurationPage.displayName = 'QuickbooksChartOfAccountsConfigurationPage'; + +export default withPolicy(QuickbooksChartOfAccountsConfigurationPage); From c0fe32b14f19a7e55b4cfc4f8ba134ac6c45e480 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 19 Mar 2024 16:50:59 +0200 Subject: [PATCH 04/78] prettier --- src/libs/actions/Policy.ts | 8 ++++---- .../qbo/QuickbooksChartOfAccountsConfigurationPage.tsx | 7 +------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 73847ae8472e..bace18b54d80 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3266,7 +3266,7 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { pendingFields: { - [settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE + [settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, connections: { quickbooksOnline: { @@ -3284,10 +3284,10 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { errorFields: { - [settingName]: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage') + [settingName]: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), }, pendingFields: { - [settingName]: null + [settingName]: null, }, connections: { quickbooksOnline: { @@ -3306,7 +3306,7 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { pendingFields: { - [settingName]: null + [settingName]: null, }, connections: { quickbooksOnline: { diff --git a/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx b/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx index e97bce1b4cbc..5c0f8806ab1d 100644 --- a/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx +++ b/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx @@ -52,12 +52,7 @@ function QuickbooksChartOfAccountsConfigurationPage({policy}: WithPolicyProps) { Policy.updatePolicyConnectionConfig( - policyID, - 'quickbooksOnline', - 'enableNewCategories', - !enableNewCategories, - )} + onToggle={() => Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'enableNewCategories', !enableNewCategories)} /> From f85ce0d9c7a595517112e275f05e0993cabbced8 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Wed, 20 Mar 2024 11:29:28 +0200 Subject: [PATCH 05/78] resolve suggested comments --- src/ROUTES.ts | 12 ++-- .../qbo/PolicyQuickbooksImportPage.tsx | 63 +++++-------------- 2 files changed, 21 insertions(+), 54 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 332c9c959b64..28605edfb2c6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -632,27 +632,27 @@ const ROUTES = { }, POLICY_ACCOUNTING_QUICKBOOKSONLINE_IMPORT: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import', - getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import` as const, + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import` as const, }, POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/accounts', - getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/accounts` as const, + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/accounts` as const, }, POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/classes', - getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/classes` as const, + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/classes` as const, }, POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/customers', - getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/customers` as const, + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/customers` as const, }, POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/locations', - getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/locations` as const, + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/locations` as const, }, POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/taxes', - getRoute: (policyID: string) => `workspace/${policyID}/connections/quickbooks-online/import/taxes` as const, + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/taxes` as const, }, } as const; diff --git a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx b/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx index 46a3a2bec1ec..5e7d8cd48522 100644 --- a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx +++ b/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react'; +import React from 'react'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -13,14 +13,6 @@ import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -const NAVIGATION_KEYS = { - ACCOUNTS: 'accounts', - CLASSES: 'classes', - CUSTOMERS: 'customers', - LOCATIONS: 'locations', - TAXES: 'taxes', -}; - function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -32,63 +24,38 @@ function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { TAG: translate('workspace.qbo.importedAsTags'), REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), }; + const policyID = policy?.id ?? ''; const {syncClasses, syncCustomers, syncLocations, syncTaxes, syncAccounts} = policy?.connections?.quickbooksOnline?.config ?? {}; - const onPressConfigOption = useCallback( - (option: string) => { - const policyID = policy?.id ?? ''; - switch (option) { - case NAVIGATION_KEYS.ACCOUNTS: - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)); - break; - case NAVIGATION_KEYS.CLASSES: - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)); - break; - case NAVIGATION_KEYS.CUSTOMERS: - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER.getRoute(policyID)); - break; - case NAVIGATION_KEYS.LOCATIONS: - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)); - break; - case NAVIGATION_KEYS.TAXES: - Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)); - break; - default: - break; - } - }, - [policy?.id], - ); - const sections = [ { description: translate('workspace.qbo.accounts'), - navigationKey: NAVIGATION_KEYS.ACCOUNTS, - errorIndicator: !!policy?.errors?.syncAccounts, + action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), + hasError: Boolean(policy?.errors?.syncAccounts), title: syncAccounts, }, { description: translate('workspace.qbo.classes'), - navigationKey: NAVIGATION_KEYS.CLASSES, - errorIndicator: !!policy?.errors?.syncClasses, + action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)), + hasError: Boolean(policy?.errors?.syncClasses), title: syncClasses, }, { description: translate('workspace.qbo.customers'), - navigationKey: NAVIGATION_KEYS.CUSTOMERS, - errorIndicator: !!policy?.errors?.syncCustomers, + action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER.getRoute(policyID)), + hasError: Boolean(policy?.errors?.syncCustomers), title: syncCustomers, }, { description: translate('workspace.qbo.locations'), - navigationKey: NAVIGATION_KEYS.LOCATIONS, - errorIndicator: !!policy?.errors?.syncLocations, + action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)), + hasError: Boolean(policy?.errors?.syncLocations), title: syncLocations, }, { description: translate('workspace.qbo.taxes'), - navigationKey: NAVIGATION_KEYS.TAXES, - errorIndicator: !!policy?.errors?.syncTaxes, + action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)), + hasError: Boolean(policy?.errors?.syncTaxes), title: syncTaxes, }, ]; @@ -108,11 +75,11 @@ function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { {sections.map((section) => ( onPressConfigOption(section.navigationKey)} - brickRoadIndicator={section.errorIndicator ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + onPress={section.action} + brickRoadIndicator={section.hasError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} /> ))} From 7b90e68609c1ab7368d84799b4f6c458c9ad5ca8 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Wed, 20 Mar 2024 15:39:16 +0200 Subject: [PATCH 06/78] update naming, add mock pages, and correct routing --- src/ROUTES.ts | 16 ++++++++------ src/SCREENS.ts | 14 ++++++------- .../AppNavigator/ModalStackNavigators.tsx | 9 ++++++-- .../FULL_SCREEN_TO_RHP_MAPPING.ts | 8 +++++++ src/libs/Navigation/linkingConfig/config.ts | 15 +++++++------ src/libs/Navigation/types.ts | 21 +++++++++++++++++++ .../accounting/WorkspaceAccountingPage.tsx | 21 +++++++++++++++++++ .../qbo/QuickbooksChartOfAccountsPage.tsx} | 10 ++++----- .../accounting/qbo/QuickbooksClassesPage.tsx | 21 +++++++++++++++++++ .../qbo/QuickbooksCustomersPage.tsx | 21 +++++++++++++++++++ .../qbo/QuickbooksImportPage.tsx} | 20 +++++++++--------- .../qbo/QuickbooksLocationsPage.tsx | 21 +++++++++++++++++++ .../accounting/qbo/QuickbooksTaxesPage.tsx | 21 +++++++++++++++++++ 13 files changed, 182 insertions(+), 36 deletions(-) create mode 100644 src/pages/workspace/accounting/WorkspaceAccountingPage.tsx rename src/pages/workspace/{qbo/QuickbooksChartOfAccountsConfigurationPage.tsx => accounting/qbo/QuickbooksChartOfAccountsPage.tsx} (87%) create mode 100644 src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx create mode 100644 src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx rename src/pages/workspace/{qbo/PolicyQuickbooksImportPage.tsx => accounting/qbo/QuickbooksImportPage.tsx} (78%) create mode 100644 src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx create mode 100644 src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 8d2a128c1681..fd64cb4085ac 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -536,6 +536,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/members', getRoute: (policyID: string) => `settings/workspaces/${policyID}/members` as const, }, + WORKSPACE_ACCOUNTING: { + route: 'settings/workspaces/:policyID/accounting', + getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting` as const, + }, WORKSPACE_CATEGORIES: { route: 'settings/workspaces/:policyID/categories', getRoute: (policyID: string) => `settings/workspaces/${policyID}/categories` as const, @@ -638,27 +642,27 @@ const ROUTES = { route: 'r/:reportID/transaction/:transactionID/receipt', getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_IMPORT: { + WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_IMPORT: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: { + WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/accounts', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/accounts` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES: { + WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/classes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/classes` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER: { + WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/customers', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/customers` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS: { + WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/locations', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/locations` as const, }, - POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES: { + WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/taxes` as const, }, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index c510a628fc9d..684efb5ecbb1 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -209,6 +209,7 @@ const SCREENS = { INVOICES: 'Workspace_Invoices', TRAVEL: 'Workspace_Travel', MEMBERS: 'Workspace_Members', + ACCOUNTING: 'Workspace_Accounting', INVITE: 'Workspace_Invite', INVITE_MESSAGE: 'Workspace_Invite_Message', CATEGORIES: 'Workspace_Categories', @@ -243,13 +244,12 @@ const SCREENS = { DISTANCE_RATES: 'Distance_Rates', CREATE_DISTANCE_RATE: 'Create_Distance_Rate', DISTANCE_RATES_SETTINGS: 'Distance_Rates_Settings', - ACCOUNTING: 'Policy_Accounting', - QUICKBOOKSONLINE_IMPORT: 'Policy_Accounting_QuickbooksOnline_Import', - QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: 'Policy_Accounting_QuickbooksOnline_Import_Chart_Of_Accounts', - QUICKBOOKSONLINE_CLASSES: 'Policy_Accounting_QuickbooksOnline_Import_Classes', - QUICKBOOKSONLINE_CUSTOMER: 'Policy_Accounting_QuickbooksOnline_Import_Customer', - QUICKBOOKSONLINE_LOCATIONS: 'Policy_Accounting_QuickbooksOnline_Import_Locations', - QUICKBOOKSONLINE_TAXES: 'Policy_Accounting_QuickbooksOnline_Import_Taxes', + QUICKBOOKSONLINE_IMPORT: 'Workspace_Accounting_QuickbooksOnline_Import', + QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: 'Workspace_Accounting_QuickbooksOnline_Import_Chart_Of_Accounts', + QUICKBOOKSONLINE_CLASSES: 'Workspace_Accounting_QuickbooksOnline_Import_Classes', + QUICKBOOKSONLINE_CUSTOMERS: 'Workspace_Accounting_QuickbooksOnline_Import_Customers', + QUICKBOOKSONLINE_LOCATIONS: 'Workspace_Accounting_QuickbooksOnline_Import_Locations', + QUICKBOOKSONLINE_TAXES: 'Workspace_Accounting_QuickbooksOnline_Import_Taxes', }, EDIT_REQUEST: { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 7c27f66bc218..188a7ec39cfa 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -195,6 +195,7 @@ const WorkspaceSettingsModalStackNavigator = createModalStackNavigator( [SCREENS.WORKSPACE.INVOICES]: () => require('../../../pages/workspace/invoices/WorkspaceInvoicesPage').default as React.ComponentType, [SCREENS.WORKSPACE.TRAVEL]: () => require('../../../pages/workspace/travel/WorkspaceTravelPage').default as React.ComponentType, [SCREENS.WORKSPACE.MEMBERS]: () => require('../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ACCOUNTING]: () => require('@pages/workspace/accounting/WorkspaceAccountingPage').default as React.ComponentType, [SCREENS.WORKSPACE.CATEGORIES]: () => require('../../../pages/workspace/categories/WorkspaceCategoriesPage').default as React.ComponentType, [SCREENS.WORKSPACE.MORE_FEATURES]: () => require('../../../pages/workspace/WorkspaceMoreFeaturesPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS]: () => require('../../../pages/workspace/tags/WorkspaceTagsPage').default as React.ComponentType, @@ -274,8 +275,12 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName').default as React.ComponentType, [SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsForeignCurrency').default as React.ComponentType, [SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT]: () => require('../../../pages/workspace/taxes/WorkspaceTaxesSettingsWorkspaceCurrency').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: () => require('../../../pages/workspace/qbo/PolicyQuickbooksImportPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: () => require('../../../pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: () => require('../../../pages/workspace/accounting/qbo/QuickbooksImportPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: () => require('@pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: () => require('../../../pages/workspace/accounting/qbo/QuickbooksCustomersPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: () => require('../../../pages/workspace/accounting/qbo/QuickbooksTaxesPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: () => require('../../../pages/workspace/accounting/qbo/QuickbooksLocationsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: () => require('../../../pages/workspace/accounting/qbo/QuickbooksClassesPage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, [SCREENS.GET_ASSISTANCE]: () => require('../../../pages/GetAssistancePage').default as React.ComponentType, [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: () => require('../../../pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index 7388d6447ffa..d76b3aa96302 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -11,6 +11,14 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, SCREENS.WORKSPACE.WORKFLOWS_PAYER, ], + [SCREENS.WORKSPACE.ACCOUNTING]: [ + SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT, + SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES, + SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES, + SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS, + SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS, + ], [SCREENS.WORKSPACE.TAXES]: [ SCREENS.WORKSPACE.TAXES_SETTINGS, SCREENS.WORKSPACE.TAX_CREATE, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 4806fdf99778..f77cef23e454 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -232,12 +232,12 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CURRENCY]: { path: ROUTES.WORKSPACE_PROFILE_CURRENCY.route, }, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_IMPORT.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMER]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: {path: ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_IMPORT.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.route}, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, @@ -594,6 +594,9 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.INVOICES]: { path: ROUTES.WORKSPACE_INVOICES.route, }, + [SCREENS.WORKSPACE.ACCOUNTING]: { + path: ROUTES.WORKSPACE_ACCOUNTING.route, + }, [SCREENS.WORKSPACE.TRAVEL]: { path: ROUTES.WORKSPACE_TRAVEL.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 32be4695e20a..e7af967deec8 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -228,6 +228,21 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: { policyID: string; }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: { + policyID: string; + }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: { + policyID: string; + }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: { + policyID: string; + }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: { + policyID: string; + }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: { + policyID: string; + }; [SCREENS.GET_ASSISTANCE]: { backTo: Routes; }; @@ -562,6 +577,9 @@ type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.TRAVEL]: { policyID: string; }; + [SCREENS.WORKSPACE.ACCOUNTING]: { + policyID: string; + }; [SCREENS.WORKSPACE.MEMBERS]: { policyID: string; }; @@ -587,6 +605,9 @@ type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: { policyID: string; }; + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: { + policyID: string; + }; }; type FullScreenNavigatorParamList = { diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx new file mode 100644 index 000000000000..7c2245514839 --- /dev/null +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import {View} from 'react-native'; +import ScreenWrapper from '@components/ScreenWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; + +// Fake page will be removed after normal on will be merged +function WorkspaceAccountingPage() { + return ( + + + + ); +} + +WorkspaceAccountingPage.displayName = 'WorkspaceAccountingPage'; + +export default withPolicy(WorkspaceAccountingPage); diff --git a/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx similarity index 87% rename from src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx rename to src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index 5c0f8806ab1d..fc0e215947d6 100644 --- a/src/pages/workspace/qbo/QuickbooksChartOfAccountsConfigurationPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -8,13 +8,13 @@ import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -function QuickbooksChartOfAccountsConfigurationPage({policy}: WithPolicyProps) { +function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? ''; @@ -24,7 +24,7 @@ function QuickbooksChartOfAccountsConfigurationPage({policy}: WithPolicyProps) { + + + ); +} + +QuickbooksClassesPage.displayName = 'QuickbooksClassesPage'; + +export default withPolicy(QuickbooksClassesPage); diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx new file mode 100644 index 000000000000..92eb1444face --- /dev/null +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import {View} from 'react-native'; +import ScreenWrapper from '@components/ScreenWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; + +// Fake page will be removed after normal on will be implemented +function QuickbooksCustomersPage() { + return ( + + + + ); +} + +QuickbooksCustomersPage.displayName = 'QuickbooksCustomersPage'; + +export default withPolicy(QuickbooksCustomersPage); diff --git a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx similarity index 78% rename from src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx rename to src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 5e7d8cd48522..06a6f46ace1a 100644 --- a/src/pages/workspace/qbo/PolicyQuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -7,13 +7,13 @@ import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { +function QuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const quickbooksOnlineConfigTitles = { @@ -30,31 +30,31 @@ function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { const sections = [ { description: translate('workspace.qbo.accounts'), - action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncAccounts), title: syncAccounts, }, { description: translate('workspace.qbo.classes'), - action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncClasses), title: syncClasses, }, { description: translate('workspace.qbo.customers'), - action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMER.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncCustomers), title: syncCustomers, }, { description: translate('workspace.qbo.locations'), - action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncLocations), title: syncLocations, }, { description: translate('workspace.qbo.taxes'), - action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncTaxes), title: syncTaxes, }, @@ -64,7 +64,7 @@ function PolicyQuickbooksImportPage({policy}: WithPolicyProps) { + + + ); +} + +QuickbooksLocationsPage.displayName = 'QuickbooksLocationsPage'; + +export default withPolicy(QuickbooksLocationsPage); diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx new file mode 100644 index 000000000000..aafd34bb3df2 --- /dev/null +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import {View} from 'react-native'; +import ScreenWrapper from '@components/ScreenWrapper'; +import withPolicy from '@pages/workspace/withPolicy'; + +// Fake page will be removed after normal on will be implemented +function QuickbooksTaxesPage() { + return ( + + + + ); +} + +QuickbooksTaxesPage.displayName = 'QuickbooksTaxesPage'; + +export default withPolicy(QuickbooksTaxesPage); From 758a77b9ef3cc424a5f859108380ded0447004e6 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Wed, 20 Mar 2024 15:47:42 +0200 Subject: [PATCH 07/78] fix ts --- .../UpdateWorkspaceAccountingChartOfAccounts.ts | 9 +++++++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 3 ++- src/libs/actions/Policy.ts | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts diff --git a/src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts b/src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts new file mode 100644 index 000000000000..1f26f409fc34 --- /dev/null +++ b/src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts @@ -0,0 +1,9 @@ +type UpdateWorkspaceAccountingChartOfAccounts = { + policyID: string; + connectionName: string; + settingName: string; + settingValue: string | boolean; + idempotencyKey: string; +}; + +export default UpdateWorkspaceAccountingChartOfAccounts; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 84ace32d6261..fd8d2eb0cecc 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -189,3 +189,4 @@ export type {default as DeletePolicyTagsParams} from './DeletePolicyTagsParams'; export type {default as SetPolicyCustomTaxNameParams} from './SetPolicyCustomTaxNameParams'; export type {default as SetPolicyForeignCurrencyDefaultParams} from './SetPolicyForeignCurrencyDefaultParams'; export type {default as SetPolicyCurrencyDefaultParams} from './SetPolicyCurrencyDefaultParams'; +export type {default as UpdateWorkspaceAccountingChartOfAccounts} from './UpdateWorkspaceAccountingChartOfAccounts'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 74f6d2231ad9..267f09250fc3 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -182,7 +182,7 @@ const WRITE_COMMANDS = { ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest', DECLINE_JOIN_REQUEST: 'DeclineJoinRequest', CREATE_POLICY_TAX: 'CreatePolicyTax', - UPDATE_POLICY_CONNECTIONS_CONFIGURATION: 'UpdatePolicyConnectionsConfiguration', + UPDATE_WORKSPACE_CONNECTIONS_CONFIGURATION: 'UpdateWorkspaceConnectionsConfiguration', CREATE_POLICY_DISTANCE_RATE: 'CreatePolicyDistanceRate', SET_POLICY_DISTANCE_RATES_UNIT: 'SetPolicyDistanceRatesUnit', SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY: 'SetPolicyDistanceRatesDefaultCategory', @@ -369,6 +369,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CREATE_POLICY_DISTANCE_RATE]: Parameters.CreatePolicyDistanceRateParams; [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_UNIT]: Parameters.SetPolicyDistanceRatesUnitParams; [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY]: Parameters.SetPolicyDistanceRatesDefaultCategoryParams; + [WRITE_COMMANDS.UPDATE_WORKSPACE_CONNECTIONS_CONFIGURATION]: Parameters.UpdateWorkspaceAccountingChartOfAccounts; }; const READ_COMMANDS = { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 36ac333579a5..c1094d0f4bfd 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3456,7 +3456,7 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, }, ]; - API.write(WRITE_COMMANDS.UPDATE_POLICY_CONNECTIONS_CONFIGURATION, parameters, {optimisticData, failureData, successData}); + API.write(WRITE_COMMANDS.UPDATE_WORKSPACE_CONNECTIONS_CONFIGURATION, parameters, {optimisticData, failureData, successData}); } function navigateWhenEnableFeature(policyID: string, featureRoute: Route) { From 441bbf033c16de0f0837ef9b7873117d8f1ca79b Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 21 Mar 2024 16:37:57 +0200 Subject: [PATCH 08/78] add 2 more screen - classes and customer + pending actions, clean up code --- src/languages/en.ts | 6 ++- src/languages/es.ts | 7 ++- src/libs/actions/Policy.ts | 31 ++++++----- .../qbo/QuickbooksChartOfAccountsPage.tsx | 10 ++-- .../accounting/qbo/QuickbooksClassesPage.tsx | 53 +++++++++++++++++- .../qbo/QuickbooksCustomersPage.tsx | 54 +++++++++++++++++-- .../accounting/qbo/QuickbooksImportPage.tsx | 5 +- src/types/onyx/Policy.ts | 8 +-- 8 files changed, 141 insertions(+), 33 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index c85e535f61e6..1dde27b39773 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1740,6 +1740,7 @@ export default { reimburse: 'Reimbursements', categories: 'Categories', tags: 'Tags', + reportFields: 'Report Fields', taxes: 'Taxes', bills: 'Bills', invoices: 'Invoices', @@ -1779,12 +1780,15 @@ export default { taxes: 'Taxes', customers: 'Customers/Projects', imported: 'Imported', + displayedAs: 'Displayed as', notImported: 'Not imported', importedAsTags: 'Imported, displayed as tags', - importedAsReportFields: 'Imported, displayed as categories', + importedAsReportFields: 'Imported, displayed as report fields', accountsDescription: 'Chart of Accounts import as categories when connected to an accounting integration, this cannot be disabled.', accountsSwitchTitle: 'Enable newly imported Chart of Accounts.', accountsSwitchDescription: 'New categories imported from QuickBooks Online to Expensify will be either enabled or disabled by default.', + classesDescription: 'Choose whether to import classes, and see where classes are displayed.', + customersDescription: 'Choose whether to import Customers/Projects and see where customers/projects are displayed.' }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 0aa882381d17..0ec454c16338 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1764,6 +1764,7 @@ export default { reimburse: 'Reembolsos', categories: 'Categorías', tags: 'Etiquetas', + reportFields: 'Campos de informe', taxes: 'Impuestos', bills: 'Pagar facturas', invoices: 'Enviar facturas', @@ -1803,12 +1804,16 @@ export default { customers: 'Clientes/Proyectos', imported: 'Importado', taxes: 'Impuestos', + displayedAs: 'Mostrado como', notImported: 'No importado', importedAsTags: 'Importado, mostrado como etiquetas', - importedAsReportFields: 'Importado, mostrado como categorías', + importedAsReportFields: 'Importado, mostrado como campos de informe', accountsDescription: 'El plan de cuentas se importa como categorías cuando se conecta a una integración contable; esto no se puede desactivar.', accountsSwitchTitle: 'Habilite el plan de cuentas recién importado.', accountsSwitchDescription: 'Las nuevas categorías importadas de QuickBooks Online a Expensify estarán habilitadas o deshabilitadas de forma predeterminada.', + classesDescription: 'Elija si desea importar clases y vea dónde se muestran las clases.', + customersDescription: 'Elija si desea importar Clientes/Proyectos y ver dónde se muestran los clientes/proyectos.' + }, type: { free: 'Gratis', diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index c1094d0f4bfd..5d98868f6f47 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3402,34 +3402,38 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - pendingFields: { - [settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - }, connections: { quickbooksOnline: { config: { [settingName]: settingValue, + pendingFields: { + [settingName]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + errorFields: { + [settingName]: null, + }, }, }, }, }, }, ]; + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - errorFields: { - [settingName]: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), - }, - pendingFields: { - [settingName]: null, - }, connections: { quickbooksOnline: { config: { [settingName]: settingValue, + pendingFields: { + [settingName]: null, + }, + errorFields: { + [settingName]: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), + }, }, }, }, @@ -3442,13 +3446,16 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { - pendingFields: { - [settingName]: null, - }, connections: { quickbooksOnline: { config: { [settingName]: settingValue, + pendingFields: { + [settingName]: null, + }, + errorFields: { + [settingName]: null, + }, }, }, }, diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index fc0e215947d6..cf91db5f6d33 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -8,7 +8,6 @@ import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; @@ -18,7 +17,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const policyID = policy?.id ?? ''; - const {enableNewCategories} = policy?.connections?.quickbooksOnline?.config ?? {}; + const {enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; return ( - + - + - + + + + {translate('workspace.qbo.classesDescription')} + + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncClasses', isSwitchOn ? 'NONE' : 'TAG')} + /> + + + + {isSwitchOn && ( + + + + )} + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index 92eb1444face..aedcee58c942 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -1,17 +1,65 @@ import React from 'react'; import {View} from 'react-native'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Switch from '@components/Switch'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import variables from '@styles/variables'; +import * as Policy from '@userActions/Policy'; -// Fake page will be removed after normal on will be implemented -function QuickbooksCustomersPage() { +function QuickbooksCustomersPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const {syncCustomers, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; + const isSwitchOn = syncCustomers !== 'NONE' && syncCustomers !== false; + const isReportFieldsSelected = syncCustomers === 'REPORT_FIELD'; return ( - + + + + {translate('workspace.qbo.customersDescription')} + + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncCustomers', isSwitchOn ? 'NONE' : 'TAG')} + /> + + + + {isSwitchOn && ( + + + + )} + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 06a6f46ace1a..104d870cdd9a 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -66,10 +66,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { shouldEnableMaxHeight testID={QuickbooksImportPage.displayName} > - + {translate('workspace.qbo.importDescription')} {sections.map((section) => ( diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 751a53e5fd1d..e2449d6edff1 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -136,12 +136,12 @@ type QBOConnectionData = { vendors: Vendor[]; }; -type IntegrationEntityMap = 'NONE' | 'DEFAULT' | 'TAG' | 'REPORT_FIELD'; +type IntegrationEntityMap = 'NONE' | 'DEFAULT' | 'TAG' | 'REPORT_FIELD' | false | true; /** * User configuration for the QuickBooks Online accounting integration. */ -type QBOConnectionConfig = { +type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ realmId: string; companyName: string; autoSync: { @@ -167,10 +167,12 @@ type QBOConnectionConfig = { lastConfigurationTime: number; syncTax: boolean; enableNewCategories: boolean; + errors?: OnyxCommon.Errors; + errorFields?: OnyxCommon.ErrorFields; export: { exporter: string; }; -}; +}>; type Connection = { lastSync?: ConnectionLastSync; data: ConnectionData; From 6bc7a25ddfe49960f82194a52c095f699fbd55ee Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 21 Mar 2024 16:44:21 +0200 Subject: [PATCH 09/78] update after merge conflicts --- src/types/onyx/Policy.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 86d3be96cf1b..919294c191bf 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -426,4 +426,17 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< export default Policy; -export type {PolicyReportField, PolicyReportFieldType, Unit, CustomUnit, Attributes, Rate, TaxRate, TaxRates, TaxRatesWithDefault, PolicyFeatureName, IntegrationEntityMap, PendingJoinRequestPolicy}; +export type { + PolicyReportField, + PolicyReportFieldType, + Unit, + CustomUnit, + Attributes, + Rate, + TaxRate, + TaxRates, + TaxRatesWithDefault, + PolicyFeatureName, + IntegrationEntityMap, + PendingJoinRequestPolicy, +}; From 3a6113bf5b8e1ec1ab9e108e723dbcb5f44d59ad Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 21 Mar 2024 16:50:25 +0200 Subject: [PATCH 10/78] remove line --- src/languages/es.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index e1b1cc143114..3d9c6c696c38 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1834,7 +1834,6 @@ export default { accountsSwitchDescription: 'Las nuevas categorías importadas de QuickBooks Online a Expensify estarán habilitadas o deshabilitadas de forma predeterminada.', classesDescription: 'Elija si desea importar clases y vea dónde se muestran las clases.', customersDescription: 'Elija si desea importar Clientes/Proyectos y ver dónde se muestran los clientes/proyectos.' - }, type: { free: 'Gratis', From bcfa12a9f3c34d0cc7bde7ac1fc21f4442b58b6e Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 21 Mar 2024 16:52:51 +0200 Subject: [PATCH 11/78] lint --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 372bfa73fc27..8df3b04bdd2b 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1806,7 +1806,7 @@ export default { accountsSwitchTitle: 'Enable newly imported Chart of Accounts.', accountsSwitchDescription: 'New categories imported from QuickBooks Online to Expensify will be either enabled or disabled by default.', classesDescription: 'Choose whether to import classes, and see where classes are displayed.', - customersDescription: 'Choose whether to import Customers/Projects and see where customers/projects are displayed.' + customersDescription: 'Choose whether to import Customers/Projects and see where customers/projects are displayed.', }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 3d9c6c696c38..0f1773d24783 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1833,7 +1833,7 @@ export default { accountsSwitchTitle: 'Habilite el plan de cuentas recién importado.', accountsSwitchDescription: 'Las nuevas categorías importadas de QuickBooks Online a Expensify estarán habilitadas o deshabilitadas de forma predeterminada.', classesDescription: 'Elija si desea importar clases y vea dónde se muestran las clases.', - customersDescription: 'Elija si desea importar Clientes/Proyectos y ver dónde se muestran los clientes/proyectos.' + customersDescription: 'Elija si desea importar Clientes/Proyectos y ver dónde se muestran los clientes/proyectos.', }, type: { free: 'Gratis', From 3477c63b83d3eddf12b7a63577d8997d6c698654 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Fri, 22 Mar 2024 15:42:26 +0200 Subject: [PATCH 12/78] Taxes and Locations pages --- src/languages/en.ts | 4 ++ src/languages/es.ts | 4 ++ .../accounting/qbo/QuickbooksClassesPage.tsx | 1 - .../accounting/qbo/QuickbooksImportPage.tsx | 9 ++- .../qbo/QuickbooksLocationsPage.tsx | 66 ++++++++++++++++++- .../accounting/qbo/QuickbooksTaxesPage.tsx | 42 +++++++++++- 6 files changed, 117 insertions(+), 9 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 8df3b04bdd2b..61357e200cf6 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1807,6 +1807,10 @@ export default { accountsSwitchDescription: 'New categories imported from QuickBooks Online to Expensify will be either enabled or disabled by default.', classesDescription: 'Choose whether to import classes, and see where classes are displayed.', customersDescription: 'Choose whether to import Customers/Projects and see where customers/projects are displayed.', + locationsDescription: 'Choose whether to import locations, and see where locations are displayed.', + taxesDescription: 'Choose whether to import tax rates and tax defaults from your accounting integration.', + locationsAdditionalDescription: + 'Locations are imported as Tags. This limits exporting expense reports as Vendor Bills or Checks to QuickBooks Online. To unlock these export options, either disable. Locations import or upgrade to the Control Plan to export Locations encoded as a Report Field.', }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 0f1773d24783..ccafd0be0a9d 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1834,6 +1834,10 @@ export default { accountsSwitchDescription: 'Las nuevas categorías importadas de QuickBooks Online a Expensify estarán habilitadas o deshabilitadas de forma predeterminada.', classesDescription: 'Elija si desea importar clases y vea dónde se muestran las clases.', customersDescription: 'Elija si desea importar Clientes/Proyectos y ver dónde se muestran los clientes/proyectos.', + locationsDescription: 'Elija si desea importar ubicaciones y vea dónde se muestran las ubicaciones.', + taxesDescription: 'Elija si desea importar tasas impositivas y valores predeterminados de impuestos desde su integración contable.', + locationsAdditionalDescription: + 'Las ubicaciones se importan como etiquetas. Esto limita la exportación de informes de gastos como facturas de proveedores o cheques a QuickBooks Online. Para desbloquear estas opciones de exportación, deshabilite. Las ubicaciones se importan o actualizan al Plan de control para exportar ubicaciones codificadas como un campo de informe.', }, type: { free: 'Gratis', diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index 40e12e935439..28312260197b 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -14,7 +14,6 @@ import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -// Fake page will be removed after normal on will be implemented function QuickbooksClassesPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 104d870cdd9a..7b3b87850693 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -25,7 +25,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), }; const policyID = policy?.id ?? ''; - const {syncClasses, syncCustomers, syncLocations, syncTaxes, syncAccounts} = policy?.connections?.quickbooksOnline?.config ?? {}; + const {syncClasses, syncCustomers, syncLocations, syncTaxes, syncAccounts, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const sections = [ { @@ -33,30 +33,35 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncAccounts), title: syncAccounts, + pendingAction: pendingFields?.syncAccounts, }, { description: translate('workspace.qbo.classes'), action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncClasses), title: syncClasses, + pendingAction: pendingFields?.syncClasses, }, { description: translate('workspace.qbo.customers'), action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncCustomers), title: syncCustomers, + pendingAction: pendingFields?.syncCustomers, }, { description: translate('workspace.qbo.locations'), action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncLocations), title: syncLocations, + pendingAction: pendingFields?.syncLocations, }, { description: translate('workspace.qbo.taxes'), action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncTaxes), title: syncTaxes, + pendingAction: pendingFields?.syncTaxes, }, ]; @@ -70,7 +75,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { {translate('workspace.qbo.importDescription')} {sections.map((section) => ( - + - + + + + {translate('workspace.qbo.locationsDescription')} + + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncLocations', isSwitchOn ? 'NONE' : 'TAG')} + /> + + + + {isSwitchOn && ( + + + + )} + + + {translate('workspace.qbo.locationsAdditionalDescription')} + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index aafd34bb3df2..fe0447b3dd1b 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -1,17 +1,53 @@ import React from 'react'; import {View} from 'react-native'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; +import ScrollView from '@components/ScrollView'; +import Switch from '@components/Switch'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import withPolicy from '@pages/workspace/withPolicy'; +import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import variables from '@styles/variables'; +import * as Policy from '@userActions/Policy'; -// Fake page will be removed after normal on will be implemented -function QuickbooksTaxesPage() { +function QuickbooksTaxesPage({policy}: WithPolicyProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const policyID = policy?.id ?? ''; + const {syncTaxes, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; + const isSwitchOn = syncTaxes !== 'NONE' && syncTaxes !== false; return ( - + + + + {translate('workspace.qbo.taxesDescription')} + + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncTaxes', isSwitchOn ? 'NONE' : 'TAG')} + /> + + + + ); } From 9c170b43f9ef314833e3c187982e0fa6798ef770 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Fri, 22 Mar 2024 18:01:20 +0200 Subject: [PATCH 13/78] translations --- src/languages/en.ts | 8 ++++---- src/languages/es.ts | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 811a985aa356..32d61151ccd8 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1791,9 +1791,9 @@ export default { }, qbo: { import: 'Import', - importDescription: 'Choose which coding configurations are imported from QuickBooks Online to Expensify', + importDescription: 'Choose which coding configurations are imported from QuickBooks Online to Expensify.', classes: 'Classes', - accounts: 'Chart of Accounts', + accounts: 'Chart of accounts', locations: 'Locations', taxes: 'Taxes', customers: 'Customers/Projects', @@ -1806,11 +1806,11 @@ export default { accountsSwitchTitle: 'Enable newly imported Chart of Accounts.', accountsSwitchDescription: 'New categories imported from QuickBooks Online to Expensify will be either enabled or disabled by default.', classesDescription: 'Choose whether to import classes, and see where classes are displayed.', - customersDescription: 'Choose whether to import Customers/Projects and see where customers/projects are displayed.', + customersDescription: 'Choose whether to import customers/projects and see where customers/projects are displayed.', locationsDescription: 'Choose whether to import locations, and see where locations are displayed.', taxesDescription: 'Choose whether to import tax rates and tax defaults from your accounting integration.', locationsAdditionalDescription: - 'Locations are imported as Tags. This limits exporting expense reports as Vendor Bills or Checks to QuickBooks Online. To unlock these export options, either disable. Locations import or upgrade to the Control Plan to export Locations encoded as a Report Field.', + 'Locations are imported as Tags. This limits exporting expense reports as Vendor Bills or Checks to QuickBooks Online. To unlock these export options, either disable Locations import or upgrade to the Control Plan to export Locations encoded as a Report Field.', }, type: { free: 'Free', diff --git a/src/languages/es.ts b/src/languages/es.ts index 944067173c8a..beabab01f15d 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1818,26 +1818,26 @@ export default { }, qbo: { import: 'Importación', - importDescription: 'Elija qué configuraciones de codificación se importan de QuickBooks Online a Expensify', + importDescription: 'Elige que configuraciónes de codificación son importadas desde QuickBooks Online a Expensify.', classes: 'Clases', - locations: 'Ubicaciones', - accounts: 'Catálogo de cuentas', + accounts: 'Plan de cuentas', + locations: 'Lugares', + taxes: 'Impuestos', customers: 'Clientes/Proyectos', imported: 'Importado', - taxes: 'Impuestos', displayedAs: 'Mostrado como', notImported: 'No importado', - importedAsTags: 'Importado, mostrado como etiquetas', - importedAsReportFields: 'Importado, mostrado como campos de informe', - accountsDescription: 'El plan de cuentas se importa como categorías cuando se conecta a una integración contable; esto no se puede desactivar.', - accountsSwitchTitle: 'Habilite el plan de cuentas recién importado.', - accountsSwitchDescription: 'Las nuevas categorías importadas de QuickBooks Online a Expensify estarán habilitadas o deshabilitadas de forma predeterminada.', - classesDescription: 'Elija si desea importar clases y vea dónde se muestran las clases.', - customersDescription: 'Elija si desea importar Clientes/Proyectos y ver dónde se muestran los clientes/proyectos.', - locationsDescription: 'Elija si desea importar ubicaciones y vea dónde se muestran las ubicaciones.', - taxesDescription: 'Elija si desea importar tasas impositivas y valores predeterminados de impuestos desde su integración contable.', + importedAsTags: 'Importado, mostrado como etiqueta', + importedAsReportFields: 'Importado, mostrado como campo de informe', + accountsDescription: 'Los planes de cuentas se importan como categorías cuando está conectado con una integración de contaduría, esto no se puede desactivar.', + accountsSwitchTitle: 'Habilita el plan de cuentas recien importado', + accountsSwitchDescription: 'Las nuevas categorías importadas desde QuickBooks Online a Expensify serán activadas o desactivadas por defecto.', + classesDescription: 'Elige si quieres importar las clases y donde las clases son mostradas.', + customersDescription: 'Elige si queres importar clientes/proyectos y donde los clientes/proyectos son mostrados.', + locationsDescription: 'Elige si quieres importar lugares y donde los lugares son mostrados.', + taxesDescription: 'Elige si quires importar las tasas de impuestos y los impuestos por defecto de tu integración de contaduría.', locationsAdditionalDescription: - 'Las ubicaciones se importan como etiquetas. Esto limita la exportación de informes de gastos como facturas de proveedores o cheques a QuickBooks Online. Para desbloquear estas opciones de exportación, deshabilite. Las ubicaciones se importan o actualizan al Plan de control para exportar ubicaciones codificadas como un campo de informe.', + 'Los lugares son importados como Etiquegas. Esto limita a exportar los informes de gastos como Factura del Proveedor o Cheques a Quicbooks Online. Para desbloquear estas opciones de exportación desactiva la importación de Lugares o cambia al Plan Control para exportar Lugares como Campos de Informes.', }, type: { free: 'Gratis', From b4d845f242e599fb762809c0ad262cf4fef16d95 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 25 Mar 2024 14:39:40 +0200 Subject: [PATCH 14/78] updated booleans and rename methods to function execution --- ...fAccounts.ts => UpdatePolicyConnectionConfigParams.ts} | 4 ++-- src/libs/API/parameters/index.ts | 2 +- src/libs/API/types.ts | 4 ++-- src/libs/actions/Policy.ts | 2 +- .../workspace/accounting/qbo/QuickbooksClassesPage.tsx | 2 +- .../workspace/accounting/qbo/QuickbooksCustomersPage.tsx | 2 +- .../workspace/accounting/qbo/QuickbooksImportPage.tsx | 8 ++++---- .../workspace/accounting/qbo/QuickbooksLocationsPage.tsx | 2 +- .../workspace/accounting/qbo/QuickbooksTaxesPage.tsx | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) rename src/libs/API/parameters/{UpdateWorkspaceAccountingChartOfAccounts.ts => UpdatePolicyConnectionConfigParams.ts} (57%) diff --git a/src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts b/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts similarity index 57% rename from src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts rename to src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts index 1f26f409fc34..0e5475f1a27d 100644 --- a/src/libs/API/parameters/UpdateWorkspaceAccountingChartOfAccounts.ts +++ b/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts @@ -1,4 +1,4 @@ -type UpdateWorkspaceAccountingChartOfAccounts = { +type UpdatePolicyConnectionConfigParams = { policyID: string; connectionName: string; settingName: string; @@ -6,4 +6,4 @@ type UpdateWorkspaceAccountingChartOfAccounts = { idempotencyKey: string; }; -export default UpdateWorkspaceAccountingChartOfAccounts; +export default UpdatePolicyConnectionConfigParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index ca0fa5581ee8..667bbb588155 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -195,5 +195,5 @@ export type {default as DeletePolicyTagsParams} from './DeletePolicyTagsParams'; export type {default as SetPolicyCustomTaxNameParams} from './SetPolicyCustomTaxNameParams'; export type {default as SetPolicyForeignCurrencyDefaultParams} from './SetPolicyForeignCurrencyDefaultParams'; export type {default as SetPolicyCurrencyDefaultParams} from './SetPolicyCurrencyDefaultParams'; -export type {default as UpdateWorkspaceAccountingChartOfAccounts} from './UpdateWorkspaceAccountingChartOfAccounts'; +export type {default as UpdatePolicyConnectionConfigParams} from './UpdatePolicyConnectionConfigParams'; export type {default as RenamePolicyTaxParams} from './RenamePolicyTaxParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index f2156ce21973..477929a052b3 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -183,7 +183,7 @@ const WRITE_COMMANDS = { ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest', DECLINE_JOIN_REQUEST: 'DeclineJoinRequest', CREATE_POLICY_TAX: 'CreatePolicyTax', - UPDATE_WORKSPACE_CONNECTIONS_CONFIGURATION: 'UpdateWorkspaceConnectionsConfiguration', + UPDATE_POLICY_CONNECTION_CONFIG: 'UpdatePolicyConnectionConfig', SET_POLICY_TAXES_ENABLED: 'SetPolicyTaxesEnabled', DELETE_POLICY_TAXES: 'DeletePolicyTaxes', UPDATE_POLICY_TAX_VALUE: 'UpdatePolicyTaxValue', @@ -382,7 +382,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.RENAME_POLICY_TAX]: Parameters.RenamePolicyTaxParams; [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_UNIT]: Parameters.SetPolicyDistanceRatesUnitParams; [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY]: Parameters.SetPolicyDistanceRatesDefaultCategoryParams; - [WRITE_COMMANDS.UPDATE_WORKSPACE_CONNECTIONS_CONFIGURATION]: Parameters.UpdateWorkspaceAccountingChartOfAccounts; + [WRITE_COMMANDS.UPDATE_POLICY_CONNECTION_CONFIG]: Parameters.UpdatePolicyConnectionConfigParams; [WRITE_COMMANDS.UPDATE_POLICY_DISTANCE_RATE_VALUE]: Parameters.UpdatePolicyDistanceRateValueParams; [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_ENABLED]: Parameters.SetPolicyDistanceRatesEnabledParams; [WRITE_COMMANDS.DELETE_POLICY_DISTANCE_RATES]: Parameters.DeletePolicyDistanceRatesParams; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 167860c75100..462bec8917aa 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3485,7 +3485,7 @@ function updatePolicyConnectionConfig(policyID: string, connectionName: string, }, ]; - API.write(WRITE_COMMANDS.UPDATE_WORKSPACE_CONNECTIONS_CONFIGURATION, parameters, {optimisticData, failureData, successData}); + API.write(WRITE_COMMANDS.UPDATE_POLICY_CONNECTION_CONFIG, parameters, {optimisticData, failureData, successData}); } function navigateWhenEnableFeature(policyID: string, featureRoute: Route) { diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index 28312260197b..c61702a92d7e 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -19,7 +19,7 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { const styles = useThemeStyles(); const policyID = policy?.id ?? ''; const {syncClasses, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isSwitchOn = syncClasses !== 'NONE' && syncClasses !== false; + const isSwitchOn = Boolean(syncClasses && syncClasses !== 'NONE'); const isReportFieldsSelected = syncClasses === 'REPORT_FIELD'; return ( Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), - hasError: Boolean(policy?.errors?.syncAccounts), - title: syncAccounts, - pendingAction: pendingFields?.syncAccounts, + hasError: Boolean(policy?.errors?.enableNewCategories), + title: enableNewCategories, + pendingAction: pendingFields?.enableNewCategories, }, { description: translate('workspace.qbo.classes'), diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index eb44cf751196..baf54ef2bfe5 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -23,7 +23,7 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { const theme = useTheme(); const policyID = policy?.id ?? ''; const {syncLocations, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isSwitchOn = syncLocations !== 'NONE' && syncLocations !== false; + const isSwitchOn = Boolean(syncLocations && syncLocations !== 'NONE'); const isReportFieldsSelected = syncLocations === 'REPORT_FIELD'; return ( Date: Mon, 25 Mar 2024 15:01:26 +0200 Subject: [PATCH 15/78] fix native ui and warning --- src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 4c9ebe589201..cc2f44747a36 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -73,9 +73,9 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { > - {translate('workspace.qbo.importDescription')} + {translate('workspace.qbo.importDescription')} {sections.map((section) => ( - + Date: Mon, 25 Mar 2024 15:08:11 +0200 Subject: [PATCH 16/78] prettier --- src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index cc2f44747a36..da7229ded9ac 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -75,7 +75,10 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { {translate('workspace.qbo.importDescription')} {sections.map((section) => ( - + Date: Mon, 25 Mar 2024 16:24:01 +0100 Subject: [PATCH 17/78] migrate step screen wrapper --- ...ScreenWrapper.js => StepScreenWrapper.tsx} | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) rename src/pages/iou/request/step/{StepScreenWrapper.js => StepScreenWrapper.tsx} (60%) diff --git a/src/pages/iou/request/step/StepScreenWrapper.js b/src/pages/iou/request/step/StepScreenWrapper.tsx similarity index 60% rename from src/pages/iou/request/step/StepScreenWrapper.js rename to src/pages/iou/request/step/StepScreenWrapper.tsx index 3739cbbcc188..902122fa0dd4 100644 --- a/src/pages/iou/request/step/StepScreenWrapper.js +++ b/src/pages/iou/request/step/StepScreenWrapper.tsx @@ -1,46 +1,45 @@ -import PropTypes from 'prop-types'; -import React from 'react'; +import type {PropsWithChildren} from 'react'; import {View} from 'react-native'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import callOrReturn from '@src/types/utils/callOrReturn'; -const propTypes = { - /** The things to display inside the screenwrapper */ - children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, - +type StepScreenWrapperProps = { /** The title to show in the header (should be translated already) */ - headerTitle: PropTypes.string.isRequired, + headerTitle: string; /** A function triggered when the back button is pressed */ - onBackButtonPress: PropTypes.func.isRequired, + onBackButtonPress: () => void; /** A function triggered when the entry transition is ended. Useful for auto-focusing elements. */ - onEntryTransitionEnd: PropTypes.func, + onEntryTransitionEnd?: () => void; /** Whether or not the wrapper should be shown (sometimes screens can be embedded inside another screen that already is using a wrapper) */ - shouldShowWrapper: PropTypes.bool.isRequired, + shouldShowWrapper: boolean; /** Whether or not to display not found page */ - shouldShowNotFoundPage: PropTypes.bool, + shouldShowNotFoundPage?: boolean; /** An ID used for unit testing */ - testID: PropTypes.string.isRequired, + testID: string; /** Whether or not to include safe area padding */ - includeSafeAreaPaddingBottom: PropTypes.bool, -}; - -const defaultProps = { - onEntryTransitionEnd: () => {}, - includeSafeAreaPaddingBottom: false, - shouldShowNotFoundPage: false, + includeSafeAreaPaddingBottom: boolean; }; -function StepScreenWrapper({testID, headerTitle, onBackButtonPress, onEntryTransitionEnd, children, shouldShowWrapper, shouldShowNotFoundPage, includeSafeAreaPaddingBottom}) { +function StepScreenWrapper({ + testID, + headerTitle, + onBackButtonPress, + onEntryTransitionEnd, + children, + shouldShowWrapper, + shouldShowNotFoundPage, + includeSafeAreaPaddingBottom, +}: PropsWithChildren) { const styles = useThemeStyles(); if (!shouldShowWrapper) { @@ -62,14 +61,8 @@ function StepScreenWrapper({testID, headerTitle, onBackButtonPress, onEntryTrans onBackButtonPress={onBackButtonPress} /> { - // If props.children is a function, call it to provide the insets to the children. - _.isFunction(children) - ? children({ - insets, - safeAreaPaddingBottomStyle, - didScreenTransitionEnd, - }) - : children + // If props.children is a function, call it to provide the insets to the children + callOrReturn(children, {insets, safeAreaPaddingBottomStyle, didScreenTransitionEnd}) } @@ -79,7 +72,5 @@ function StepScreenWrapper({testID, headerTitle, onBackButtonPress, onEntryTrans } StepScreenWrapper.displayName = 'StepScreenWrapper'; -StepScreenWrapper.propTypes = propTypes; -StepScreenWrapper.defaultProps = defaultProps; export default StepScreenWrapper; From 7833b99f229256143fba1fddc489049bca1b1dff Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Mon, 25 Mar 2024 16:35:51 +0100 Subject: [PATCH 18/78] migrate step drag and drop wrapper --- ...er.js => StepScreenDragAndDropWrapper.tsx} | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) rename src/pages/iou/request/step/{StepScreenDragAndDropWrapper.js => StepScreenDragAndDropWrapper.tsx} (79%) diff --git a/src/pages/iou/request/step/StepScreenDragAndDropWrapper.js b/src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx similarity index 79% rename from src/pages/iou/request/step/StepScreenDragAndDropWrapper.js rename to src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx index ceb0d5a44351..39ac12b6bdcf 100644 --- a/src/pages/iou/request/step/StepScreenDragAndDropWrapper.js +++ b/src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx @@ -1,4 +1,4 @@ -import PropTypes from 'prop-types'; +import type {PropsWithChildren} from 'react'; import React, {useState} from 'react'; import {View} from 'react-native'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; @@ -7,31 +7,24 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; -const propTypes = { - /** The things to display inside the screenwrapper */ - children: PropTypes.node.isRequired, - +type StepScreenDragAndDropWrapperProps = { /** The title to show in the header (should be translated already) */ - headerTitle: PropTypes.string.isRequired, + headerTitle: string; /** A function triggered when the back button is pressed */ - onBackButtonPress: PropTypes.func.isRequired, + onBackButtonPress: () => void; /** A function triggered when the entry transition is ended. Useful for auto-focusing elements. */ - onEntryTransitionEnd: PropTypes.func, + onEntryTransitionEnd?: () => void; /** Whether or not the wrapper should be shown (sometimes screens can be embedded inside another screen that already is using a wrapper) */ - shouldShowWrapper: PropTypes.bool.isRequired, + shouldShowWrapper: boolean; /** An ID used for unit testing */ - testID: PropTypes.string.isRequired, -}; - -const defaultProps = { - onEntryTransitionEnd: () => {}, + testID: string; }; -function StepScreenDragAndDropWrapper({testID, headerTitle, onBackButtonPress, onEntryTransitionEnd, children, shouldShowWrapper}) { +function StepScreenDragAndDropWrapper({testID, headerTitle, onBackButtonPress, onEntryTransitionEnd, children, shouldShowWrapper}: PropsWithChildren) { const styles = useThemeStyles(); const [isDraggingOver, setIsDraggingOver] = useState(false); @@ -65,7 +58,5 @@ function StepScreenDragAndDropWrapper({testID, headerTitle, onBackButtonPress, o } StepScreenDragAndDropWrapper.displayName = 'StepScreenDragAndDropWrapper'; -StepScreenDragAndDropWrapper.propTypes = propTypes; -StepScreenDragAndDropWrapper.defaultProps = defaultProps; export default StepScreenDragAndDropWrapper; From a738e500a06dd49c1806dfa35efd1b7d00c77a45 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 26 Mar 2024 09:00:43 +0100 Subject: [PATCH 19/78] migrate iouRequest wip --- src/libs/Navigation/types.ts | 8 + .../step/IOURequestStepConfirmation.tsx | 558 ++++++++++++++++++ 2 files changed, 566 insertions(+) create mode 100644 src/pages/iou/request/step/IOURequestStepConfirmation.tsx diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 3f85aec3a560..a06503d9edf3 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -413,6 +413,14 @@ type MoneyRequestNavigatorParamList = { iouType: string; reportID: string; }; + [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: { + action: keyof typeof CONST.IOU.ACTION; + iouType: string; + transactionID: string; + reportID: string; + pageIndex?: string; + backTo?: string; + }; }; type NewTaskNavigatorParamList = { diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx new file mode 100644 index 000000000000..e1a842bf30f8 --- /dev/null +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -0,0 +1,558 @@ +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import categoryPropTypes from '@components/categoryPropTypes'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import * as Expensicons from '@components/Icon/Expensicons'; +import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; +import ScreenWrapper from '@components/ScreenWrapper'; +import tagPropTypes from '@components/tagPropTypes'; +import transactionPropTypes from '@components/transactionPropTypes'; +import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import compose from '@libs/compose'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import getCurrentPosition from '@libs/getCurrentPosition'; +import * as IOUUtils from '@libs/IOUUtils'; +import Log from '@libs/Log'; +import Navigation from '@libs/Navigation/Navigation'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as ReportUtils from '@libs/ReportUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; +import personalDetailsPropType from '@pages/personalDetailsPropType'; +import reportPropTypes from '@pages/reportPropTypes'; +import {policyPropTypes} from '@pages/workspace/withPolicy'; +import * as IOU from '@userActions/IOU'; +// import * as Policy from '@userActions/Policy'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import {Policy} from '@src/types/onyx'; +import type {PolicyCategories, PolicyTagList} from '@src/types/onyx'; +import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; +import withWritableReportOrNotFound from './withWritableReportOrNotFound'; + +type IOURequestStepConfirmationOnyxProps = { + policy: OnyxEntry; + policyCategories: OnyxEntry; + policyTags: OnyxEntry; +}; + +type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & { + someProp: string; +}; + +function IOURequestStepConfirmation({ + currentUserPersonalDetails, + personalDetails, + policy, + policyTags, + policyCategories, + report, + route: { + params: {iouType, reportID, transactionID}, + }, + transaction, +}) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {windowWidth} = useWindowDimensions(); + const {isOffline} = useNetwork(); + const [receiptFile, setReceiptFile] = useState(); + const receiptFilename = lodashGet(transaction, 'filename'); + const receiptPath = lodashGet(transaction, 'receipt.source'); + const receiptType = lodashGet(transaction, 'receipt.type'); + const transactionTaxCode = transaction.taxRate?.keyForList; + const transactionTaxAmount = transaction.taxAmount; + const requestType = TransactionUtils.getRequestType(transaction); + const headerTitle = useMemo(() => { + if (iouType === CONST.IOU.TYPE.SPLIT) { + return translate('iou.split'); + } + if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + return translate('iou.trackExpense'); + } + if (iouType === CONST.IOU.TYPE.SEND) { + return translate('common.send'); + } + return translate(TransactionUtils.getHeaderTitleTranslationKey(transaction)); + }, [iouType, transaction, translate]); + + const participants = useMemo( + () => + _.map(transaction.participants, (participant) => { + const participantAccountID = lodashGet(participant, 'accountID', 0); + return participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); + }), + [transaction.participants, personalDetails], + ); + const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); + const formHasBeenSubmitted = useRef(false); + + useEffect(() => { + if (!transaction?.originalCurrency) { + return; + } + // If user somehow lands on this page without the currency reset, then reset it here. + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, transaction.originalCurrency, true); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat); + if (policyExpenseChat) { + Policy.openDraftWorkspaceRequest(policyExpenseChat.policyID); + } + }, [isOffline, participants, transaction.billable, policy, transactionID]); + + const defaultBillable = lodashGet(policy, 'defaultBillable', false); + useEffect(() => { + IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, defaultBillable); + }, [transactionID, defaultBillable]); + + useEffect(() => { + if (!transaction.category) { + return; + } + if (policyCategories?.[transaction.category] && !policyCategories[transaction.category].enabled) { + IOU.setMoneyRequestCategory(transactionID, ''); + } + }, [policyCategories, transaction.category, transactionID]); + const defaultCategory = lodashGet( + _.find(lodashGet(policy, 'customUnits', {}), (customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE), + 'defaultCategory', + '', + ); + useEffect(() => { + if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !_.isEmpty(transaction.category)) { + return; + } + IOU.setMoneyRequestCategory(transactionID, defaultCategory); + // Prevent resetting to default when unselect category + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [transactionID, requestType, defaultCategory]); + + const navigateBack = useCallback(() => { + // If there is not a report attached to the IOU with a reportID, then the participants were manually selected and the user needs taken + // back to the participants step + if (!transaction.participantsAutoAssigned) { + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + return; + } + IOUUtils.navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID); + }, [transaction, iouType, requestType, transactionID, reportID]); + + const navigateToAddReceipt = useCallback(() => { + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams())); + }, [iouType, transactionID, reportID]); + + // When the component mounts, if there is a receipt, see if the image can be read from the disk. If not, redirect the user to the starting step of the flow. + // This is because until the request is saved, the receipt file is only stored in the browsers memory as a blob:// and if the browser is refreshed, then + // the image ceases to exist. The best way for the user to recover from this is to start over from the start of the request process. + useEffect(() => { + const onSuccess = (file) => { + const receipt = file; + receipt.state = file && requestType === CONST.IOU.REQUEST_TYPE.MANUAL ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY; + setReceiptFile(receipt); + }; + + IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID, receiptType); + }, [receiptType, receiptPath, receiptFilename, requestType, iouType, transactionID, reportID]); + + /** + * @param {Array} selectedParticipants + * @param {String} trimmedComment + * @param {File} [receiptObj] + */ + const requestMoney = useCallback( + (selectedParticipants, trimmedComment, receiptObj, gpsPoints) => { + IOU.requestMoney( + report, + transaction.amount, + transaction.currency, + transaction.created, + transaction.merchant, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + selectedParticipants[0], + trimmedComment, + receiptObj, + transaction.category, + transaction.tag, + transactionTaxCode, + transactionTaxAmount, + transaction.billable, + policy, + policyTags, + policyCategories, + gpsPoints, + ); + }, + [report, transaction, transactionTaxCode, transactionTaxAmount, currentUserPersonalDetails.login, currentUserPersonalDetails.accountID, policy, policyTags, policyCategories], + ); + + /** + * @param {Array} selectedParticipants + * @param {String} trimmedComment + * @param {File} [receiptObj] + */ + const trackExpense = useCallback( + (selectedParticipants, trimmedComment, receiptObj, gpsPoints) => { + IOU.trackExpense( + report, + transaction.amount, + transaction.currency, + transaction.created, + transaction.merchant, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + selectedParticipants[0], + trimmedComment, + receiptObj, + transaction.category, + transaction.tag, + transactionTaxCode, + transactionTaxAmount, + transaction.billable, + policy, + policyTags, + policyCategories, + gpsPoints, + ); + }, + [ + report, + transaction.amount, + transaction.currency, + transaction.created, + transaction.merchant, + transaction.category, + transaction.tag, + transaction.billable, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + transactionTaxCode, + transactionTaxAmount, + policy, + policyTags, + policyCategories, + ], + ); + + /** + * @param {Array} selectedParticipants + * @param {String} trimmedComment + */ + const createDistanceRequest = useCallback( + (selectedParticipants, trimmedComment) => { + IOU.createDistanceRequest( + report, + selectedParticipants[0], + trimmedComment, + transaction.created, + transaction.category, + transaction.tag, + transaction.amount, + transaction.currency, + transaction.merchant, + transaction.billable, + TransactionUtils.getValidWaypoints(transaction.comment.waypoints, true), + policy, + policyTags, + policyCategories, + ); + }, + [policy, policyCategories, policyTags, report, transaction], + ); + + const createTransaction = useCallback( + (selectedParticipants) => { + const trimmedComment = lodashGet(transaction, 'comment.comment', '').trim(); + + // Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page + if (formHasBeenSubmitted.current) { + return; + } + + formHasBeenSubmitted.current = true; + + // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed + if (iouType === CONST.IOU.TYPE.SPLIT && receiptFile) { + IOU.startSplitBill( + selectedParticipants, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + trimmedComment, + transaction.category, + transaction.tag, + receiptFile, + report.reportID, + transaction.billable, + ); + return; + } + + // IOUs created from a group report will have a reportID param in the route. + // Since the user is already viewing the report, we don't need to navigate them to the report + if (iouType === CONST.IOU.TYPE.SPLIT && !transaction.isFromGlobalCreate) { + IOU.splitBill( + selectedParticipants, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + transaction.amount, + trimmedComment, + transaction.currency, + transaction.merchant, + transaction.created, + transaction.category, + transaction.tag, + report.reportID, + transaction.billable, + transaction.iouRequestType, + ); + return; + } + + // If the request is created from the global create menu, we also navigate the user to the group report + if (iouType === CONST.IOU.TYPE.SPLIT) { + IOU.splitBillAndOpenReport( + selectedParticipants, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + transaction.amount, + trimmedComment, + transaction.currency, + transaction.merchant, + transaction.created, + transaction.category, + transaction.tag, + transaction.billable, + transaction.iouRequestType, + ); + return; + } + + if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + if (receiptFile) { + // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. + if (transaction.amount === 0) { + getCurrentPosition( + (successData) => { + trackExpense(selectedParticipants, trimmedComment, receiptFile, { + lat: successData.coords.latitude, + long: successData.coords.longitude, + }); + }, + (errorData) => { + Log.info('[IOURequestStepConfirmation] getCurrentPosition failed', false, errorData); + // When there is an error, the money can still be requested, it just won't include the GPS coordinates + trackExpense(selectedParticipants, trimmedComment, receiptFile); + }, + { + // It's OK to get a cached location that is up to an hour old because the only accuracy needed is the country the user is in + maximumAge: 1000 * 60 * 60, + + // 15 seconds, don't wait too long because the server can always fall back to using the IP address + timeout: 15000, + }, + ); + return; + } + + // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed. + trackExpense(selectedParticipants, trimmedComment, receiptFile); + return; + } + trackExpense(selectedParticipants, trimmedComment, receiptFile); + return; + } + + if (receiptFile) { + // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. + if (transaction.amount === 0) { + getCurrentPosition( + (successData) => { + requestMoney(selectedParticipants, trimmedComment, receiptFile, { + lat: successData.coords.latitude, + long: successData.coords.longitude, + }); + }, + (errorData) => { + Log.info('[IOURequestStepConfirmation] getCurrentPosition failed', false, errorData); + // When there is an error, the money can still be requested, it just won't include the GPS coordinates + requestMoney(selectedParticipants, trimmedComment, receiptFile); + }, + { + // It's OK to get a cached location that is up to an hour old because the only accuracy needed is the country the user is in + maximumAge: 1000 * 60 * 60, + + // 15 seconds, don't wait too long because the server can always fall back to using the IP address + timeout: 15000, + }, + ); + return; + } + + // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed. + requestMoney(selectedParticipants, trimmedComment, receiptFile); + return; + } + + if (requestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { + createDistanceRequest(selectedParticipants, trimmedComment); + return; + } + + requestMoney(selectedParticipants, trimmedComment); + }, + [ + transaction, + iouType, + receiptFile, + requestType, + requestMoney, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + report.reportID, + trackExpense, + createDistanceRequest, + ], + ); + + /** + * Checks if user has a GOLD wallet then creates a paid IOU report on the fly + * + * @param {String} paymentMethodType + */ + const sendMoney = useCallback( + (paymentMethodType) => { + const currency = transaction.currency; + + const trimmedComment = transaction.comment?.comment ? transaction.comment.comment.trim() : ''; + + const participant = participants[0]; + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { + IOU.sendMoneyElsewhere(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { + IOU.sendMoneyWithWallet(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); + } + }, + [transaction.amount, transaction.comment, transaction.currency, participants, currentUserPersonalDetails.accountID, report], + ); + + const addNewParticipant = (option) => { + const newParticipants = _.map(transaction.participants, (participant) => { + if (participant.accountID === option.accountID) { + return {...participant, selected: !participant.selected}; + } + return participant; + }); + IOU.setMoneyRequestParticipants_temporaryForRefactor(transactionID, newParticipants); + }; + + /** + * @param billable + */ + const setBillable = (billable) => { + IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, billable); + }; + + // This loading indicator is shown because the transaction originalCurrency is being updated later than the component mounts. + // To prevent the component from rendering with the wrong currency, we show a loading indicator until the correct currency is set. + const isLoading = !!transaction?.originalCurrency; + + return ( + + {({safeAreaPaddingBottomStyle}) => ( + + + {isLoading && } + + + + + )} + + ); +} + +IOURequestStepConfirmation.displayName = 'IOURequestStepConfirmation'; + +export default compose( + withCurrentUserPersonalDetails, + withWritableReportOrNotFound, + withFullTransactionOrNotFound, + withOnyx({ + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, + }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, + }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, + }, + }), +)(IOURequestStepConfirmation); From 860c8891ad83dc1e1d75999e163eedda96fa6d2d Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 26 Mar 2024 11:31:22 +0100 Subject: [PATCH 20/78] apply prop types, general types changes wip --- src/libs/TransactionUtils.ts | 6 +- .../step/IOURequestStepConfirmation.tsx | 63 ++++++++++--------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index bc94c8fee8fc..32356d56898a 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -3,6 +3,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {RecentWaypoint, Report, TaxRate, TaxRates, Transaction, TransactionViolation} from '@src/types/onyx'; import type {Comment, Receipt, TransactionChanges, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -416,12 +417,13 @@ function getCreated(transaction: OnyxEntry, dateFormat: string = CO /** * Returns the translation key to use for the header title */ -function getHeaderTitleTranslationKey(transaction: Transaction): string { - const headerTitles = { +function getHeaderTitleTranslationKey(transaction: Transaction): TranslationPaths { + const headerTitles: Record = { [CONST.IOU.REQUEST_TYPE.DISTANCE]: 'tabSelector.distance', [CONST.IOU.REQUEST_TYPE.MANUAL]: 'tabSelector.manual', [CONST.IOU.REQUEST_TYPE.SCAN]: 'tabSelector.scan', }; + return headerTitles[getRequestType(transaction)]; } diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index e1a842bf30f8..8ceb38a2c518 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,52 +1,54 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import categoryPropTypes from '@components/categoryPropTypes'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; import ScreenWrapper from '@components/ScreenWrapper'; -import tagPropTypes from '@components/tagPropTypes'; -import transactionPropTypes from '@components/transactionPropTypes'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; +import type {CurrentUserPersonalDetails} from '@components/withCurrentUserPersonalDetails'; +import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import {openDraftWorkspaceRequest} from '@libs/actions/Policy'; import compose from '@libs/compose'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; +import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import personalDetailsPropType from '@pages/personalDetailsPropType'; -import reportPropTypes from '@pages/reportPropTypes'; -import {policyPropTypes} from '@pages/workspace/withPolicy'; import * as IOU from '@userActions/IOU'; -// import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {Policy} from '@src/types/onyx'; -import type {PolicyCategories, PolicyTagList} from '@src/types/onyx'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import type SCREENS from '@src/SCREENS'; +import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Report, Transaction} from '@src/types/onyx'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; +type IOURequestStepConfirmationStackProps = StackScreenProps; + type IOURequestStepConfirmationOnyxProps = { policy: OnyxEntry; policyCategories: OnyxEntry; policyTags: OnyxEntry; }; -type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & { - someProp: string; -}; +type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & + IOURequestStepConfirmationStackProps & { + currentUserPersonalDetails: CurrentUserPersonalDetails; + personalDetails: PersonalDetailsList; + report: Report; + transaction: Transaction; + }; function IOURequestStepConfirmation({ currentUserPersonalDetails, @@ -59,15 +61,15 @@ function IOURequestStepConfirmation({ params: {iouType, reportID, transactionID}, }, transaction, -}) { +}: IOURequestStepConfirmationProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {windowWidth} = useWindowDimensions(); const {isOffline} = useNetwork(); const [receiptFile, setReceiptFile] = useState(); - const receiptFilename = lodashGet(transaction, 'filename'); - const receiptPath = lodashGet(transaction, 'receipt.source'); - const receiptType = lodashGet(transaction, 'receipt.type'); + const receiptFilename = transaction.filename; + const receiptPath = transaction.receipt?.source; + const receiptType = transaction.receipt?.type; const transactionTaxCode = transaction.taxRate?.keyForList; const transactionTaxAmount = transaction.taxAmount; const requestType = TransactionUtils.getRequestType(transaction); @@ -86,9 +88,9 @@ function IOURequestStepConfirmation({ const participants = useMemo( () => - _.map(transaction.participants, (participant) => { - const participantAccountID = lodashGet(participant, 'accountID', 0); - return participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); + transaction.participants?.map((participant) => { + const participantAccountID = participant.accountID ?? 0; + return participant && participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); }), [transaction.participants, personalDetails], ); @@ -105,13 +107,13 @@ function IOURequestStepConfirmation({ }, []); useEffect(() => { - const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat); - if (policyExpenseChat) { - Policy.openDraftWorkspaceRequest(policyExpenseChat.policyID); + const policyExpenseChat = participants?.find((participant) => participant.isPolicyExpenseChat); + if (policyExpenseChat?.policyID) { + openDraftWorkspaceRequest(policyExpenseChat.policyID); } }, [isOffline, participants, transaction.billable, policy, transactionID]); - const defaultBillable = lodashGet(policy, 'defaultBillable', false); + const defaultBillable = !!policy?.defaultBillable; useEffect(() => { IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, defaultBillable); }, [transactionID, defaultBillable]); @@ -124,11 +126,10 @@ function IOURequestStepConfirmation({ IOU.setMoneyRequestCategory(transactionID, ''); } }, [policyCategories, transaction.category, transactionID]); - const defaultCategory = lodashGet( - _.find(lodashGet(policy, 'customUnits', {}), (customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE), - 'defaultCategory', - '', - ); + + const policyDistance = Object.values(policy?.customUnits ?? {}).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); + const defaultCategory = policyDistance?.defaultCategory ?? ''; + useEffect(() => { if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !_.isEmpty(transaction.category)) { return; @@ -436,7 +437,7 @@ function IOURequestStepConfirmation({ const trimmedComment = transaction.comment?.comment ? transaction.comment.comment.trim() : ''; - const participant = participants[0]; + const participant = participants?.[0]; if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { IOU.sendMoneyElsewhere(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); From cb63fd64232791cbc2dd2f93e0e80279c6cff2df Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 26 Mar 2024 12:43:14 +0100 Subject: [PATCH 21/78] receipts types wip --- src/libs/Navigation/types.ts | 2 +- .../step/IOURequestStepConfirmation.tsx | 29 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index a06503d9edf3..4846251cac4a 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -415,7 +415,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: { action: keyof typeof CONST.IOU.ACTION; - iouType: string; + iouType: ValueOf; transactionID: string; reportID: string; pageIndex?: string; diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 8ceb38a2c518..9b1139757c11 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,27 +1,28 @@ -import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import type { StackScreenProps } from '@react-navigation/stack'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { View } from 'react-native'; +import type { OnyxEntry } from 'react-native-onyx'; +import { withOnyx } from 'react-native-onyx'; +import { ValueOf } from 'type-fest'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; import ScreenWrapper from '@components/ScreenWrapper'; -import type {CurrentUserPersonalDetails} from '@components/withCurrentUserPersonalDetails'; +import type { CurrentUserPersonalDetails } from '@components/withCurrentUserPersonalDetails'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import {openDraftWorkspaceRequest} from '@libs/actions/Policy'; +import { openDraftWorkspaceRequest } from '@libs/actions/Policy'; import compose from '@libs/compose'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; +import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -30,9 +31,11 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Report, Transaction} from '@src/types/onyx'; +import type { PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Report, Transaction } from '@src/types/onyx'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; +import { Receipt } from '@src/types/onyx/Transaction'; + type IOURequestStepConfirmationStackProps = StackScreenProps; @@ -131,7 +134,7 @@ function IOURequestStepConfirmation({ const defaultCategory = policyDistance?.defaultCategory ?? ''; useEffect(() => { - if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !_.isEmpty(transaction.category)) { + if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !!transaction.category) { return; } IOU.setMoneyRequestCategory(transactionID, defaultCategory); @@ -157,8 +160,8 @@ function IOURequestStepConfirmation({ // This is because until the request is saved, the receipt file is only stored in the browsers memory as a blob:// and if the browser is refreshed, then // the image ceases to exist. The best way for the user to recover from this is to start over from the start of the request process. useEffect(() => { - const onSuccess = (file) => { - const receipt = file; + const onSuccess = (file: File) => { + const receipt: Receipt = file; receipt.state = file && requestType === CONST.IOU.REQUEST_TYPE.MANUAL ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY; setReceiptFile(receipt); }; @@ -556,4 +559,4 @@ export default compose( key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, }, }), -)(IOURequestStepConfirmation); +)(IOURequestStepConfirmation); \ No newline at end of file From 83fa595fd46494333b64c0b146ac4f01f9097d19 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 26 Mar 2024 15:33:17 +0200 Subject: [PATCH 22/78] updates after design review --- .../qbo/QuickbooksChartOfAccountsPage.tsx | 23 ++++++++----------- .../accounting/qbo/QuickbooksClassesPage.tsx | 7 +----- .../qbo/QuickbooksCustomersPage.tsx | 7 +----- .../qbo/QuickbooksLocationsPage.tsx | 16 +------------ .../accounting/qbo/QuickbooksTaxesPage.tsx | 7 +----- 5 files changed, 14 insertions(+), 46 deletions(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index cf91db5f6d33..5d9c3c0dbc62 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -27,21 +27,10 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { > - - {translate('workspace.qbo.accountsDescription')} - - + {translate('workspace.qbo.accountsDescription')} + {translate('workspace.qbo.accountsSwitchTitle')} - - {translate('workspace.qbo.accountsSwitchDescription')} - @@ -53,6 +42,14 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { + + + {translate('workspace.qbo.accountsSwitchDescription')} + + ); diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index c61702a92d7e..b22e98252eb7 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -29,12 +29,7 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { > - - {translate('workspace.qbo.classesDescription')} - + {translate('workspace.qbo.classesDescription')} {translate('workspace.qbo.import')} diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index 693d84bc3808..078ea466b929 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -29,12 +29,7 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { > - - {translate('workspace.qbo.customersDescription')} - + {translate('workspace.qbo.customersDescription')} {translate('workspace.qbo.import')} diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index baf54ef2bfe5..07df8aa1a036 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -1,8 +1,6 @@ import React from 'react'; import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -10,7 +8,6 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; @@ -20,7 +17,6 @@ import * as Policy from '@userActions/Policy'; function QuickbooksLocationsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const theme = useTheme(); const policyID = policy?.id ?? ''; const {syncLocations, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncLocations && syncLocations !== 'NONE'); @@ -33,12 +29,7 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { > - - {translate('workspace.qbo.locationsDescription')} - + {translate('workspace.qbo.locationsDescription')} {translate('workspace.qbo.import')} @@ -64,11 +55,6 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { )} - {translate('workspace.qbo.locationsAdditionalDescription')} diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index 825c970ef5c8..8cb4a532c17f 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -27,12 +27,7 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { > - - {translate('workspace.qbo.taxesDescription')} - + {translate('workspace.qbo.taxesDescription')} {translate('workspace.qbo.import')} From 40b55ebcf1a1467b0ebfef2c167f505982b08340 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 26 Mar 2024 16:24:54 +0200 Subject: [PATCH 23/78] design review updates --- .../accounting/qbo/QuickbooksChartOfAccountsPage.tsx | 9 ++------- .../workspace/accounting/qbo/QuickbooksLocationsPage.tsx | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index 5d9c3c0dbc62..028c1d5922b8 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -28,7 +28,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { {translate('workspace.qbo.accountsDescription')} - + {translate('workspace.qbo.accountsSwitchTitle')} @@ -43,12 +43,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { - - {translate('workspace.qbo.accountsSwitchDescription')} - + {translate('workspace.qbo.accountsSwitchDescription')} diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index 07df8aa1a036..9fa36c615208 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -55,7 +55,7 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { )} - {translate('workspace.qbo.locationsAdditionalDescription')} + {translate('workspace.qbo.locationsAdditionalDescription')} From eb5bfcfb4607cc139f887cbefeb9f9afb4284d6d Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 26 Mar 2024 15:51:24 +0100 Subject: [PATCH 24/78] callback params cleanups --- src/libs/actions/IOU.ts | 20 +++++---- .../step/IOURequestStepConfirmation.tsx | 41 ++++++++++--------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5632268ef6ca..868b9348cb01 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -134,6 +134,11 @@ type OutstandingChildRequest = { hasOutstandingChildRequest?: boolean; }; +type GpsPoint = { + lat: number; + long: number; +}; + let betas: OnyxTypes.Beta[] = []; Onyx.connect({ key: ONYXKEYS.BETAS, @@ -2056,8 +2061,8 @@ function requestMoney( amount: number, currency: string, created: string, - merchant: string, - payeeEmail: string, + merchant: string | undefined, + payeeEmail: string | undefined, payeeAccountID: number, participant: Participant, comment: string, @@ -2070,7 +2075,7 @@ function requestMoney( policy?: OnyxEntry, policyTagList?: OnyxEntry, policyCategories?: OnyxEntry, - gpsPoints = undefined, + gpsPoints?: GpsPoint, ) { // If the report is iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); @@ -5124,14 +5129,14 @@ function unholdRequest(transactionID: string, reportID: string) { } // eslint-disable-next-line rulesdir/no-negated-variables function navigateToStartStepIfScanFileCannotBeRead( - receiptFilename: string, - receiptPath: string, + receiptFilename: string | undefined, + receiptPath: ReceiptSource | undefined, onSuccess: (file: File) => void, requestType: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, - receiptType: string, + receiptType: string | undefined, ) { if (!receiptFilename || !receiptPath) { return; @@ -5145,7 +5150,7 @@ function navigateToStartStepIfScanFileCannotBeRead( } IOUUtils.navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID); }; - FileUtils.readFileAsync(receiptPath, receiptFilename, onSuccess, onFailure, receiptType); + FileUtils.readFileAsync(receiptPath.toString(), receiptFilename, onSuccess, onFailure, receiptType); } /** Save the preferred payment method for a policy */ @@ -5153,6 +5158,7 @@ function savePreferredPaymentMethod(policyID: string, paymentMethod: PaymentMeth Onyx.merge(`${ONYXKEYS.NVP_LAST_PAYMENT_METHOD}`, {[policyID]: paymentMethod}); } +export type {GpsPoint}; export { setMoneyRequestParticipants, createDistanceRequest, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 9b1139757c11..516bd936674a 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,28 +1,27 @@ -import type { StackScreenProps } from '@react-navigation/stack'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { View } from 'react-native'; -import type { OnyxEntry } from 'react-native-onyx'; -import { withOnyx } from 'react-native-onyx'; -import { ValueOf } from 'type-fest'; +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; import ScreenWrapper from '@components/ScreenWrapper'; -import type { CurrentUserPersonalDetails } from '@components/withCurrentUserPersonalDetails'; +import type {CurrentUserPersonalDetails} from '@components/withCurrentUserPersonalDetails'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import { openDraftWorkspaceRequest } from '@libs/actions/Policy'; +import {openDraftWorkspaceRequest} from '@libs/actions/Policy'; import compose from '@libs/compose'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types'; +import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -31,11 +30,11 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type { PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Report, Transaction } from '@src/types/onyx'; +import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Report, Transaction} from '@src/types/onyx'; +import type {Participant} from '@src/types/onyx/IOU'; +import type {Receipt} from '@src/types/onyx/Transaction'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -import { Receipt } from '@src/types/onyx/Transaction'; - type IOURequestStepConfirmationStackProps = StackScreenProps; @@ -69,13 +68,15 @@ function IOURequestStepConfirmation({ const {translate} = useLocalize(); const {windowWidth} = useWindowDimensions(); const {isOffline} = useNetwork(); - const [receiptFile, setReceiptFile] = useState(); + const [receiptFile, setReceiptFile] = useState(); + const receiptFilename = transaction.filename; const receiptPath = transaction.receipt?.source; const receiptType = transaction.receipt?.type; const transactionTaxCode = transaction.taxRate?.keyForList; const transactionTaxAmount = transaction.taxAmount; const requestType = TransactionUtils.getRequestType(transaction); + const headerTitle = useMemo(() => { if (iouType === CONST.IOU.TYPE.SPLIT) { return translate('iou.split'); @@ -175,7 +176,7 @@ function IOURequestStepConfirmation({ * @param {File} [receiptObj] */ const requestMoney = useCallback( - (selectedParticipants, trimmedComment, receiptObj, gpsPoints) => { + (selectedParticipants: Participant[], trimmedComment: string, receiptObj: Receipt, gpsPoints: IOU.GpsPoint) => { IOU.requestMoney( report, transaction.amount, @@ -207,7 +208,7 @@ function IOURequestStepConfirmation({ * @param {File} [receiptObj] */ const trackExpense = useCallback( - (selectedParticipants, trimmedComment, receiptObj, gpsPoints) => { + (selectedParticipants: Participant[], trimmedComment: string, receiptObj: Receipt, gpsPoints?: IOU.GpsPoint) => { IOU.trackExpense( report, transaction.amount, @@ -254,7 +255,7 @@ function IOURequestStepConfirmation({ * @param {String} trimmedComment */ const createDistanceRequest = useCallback( - (selectedParticipants, trimmedComment) => { + (selectedParticipants: Participant[], trimmedComment: string) => { IOU.createDistanceRequest( report, selectedParticipants[0], @@ -276,8 +277,8 @@ function IOURequestStepConfirmation({ ); const createTransaction = useCallback( - (selectedParticipants) => { - const trimmedComment = lodashGet(transaction, 'comment.comment', '').trim(); + (selectedParticipants: Participant[]) => { + const trimmedComment = (transaction.comment.comment ?? '').trim(); // Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page if (formHasBeenSubmitted.current) { @@ -455,7 +456,7 @@ function IOURequestStepConfirmation({ ); const addNewParticipant = (option) => { - const newParticipants = _.map(transaction.participants, (participant) => { + const newParticipants = transaction.participants?.map((participant) => { if (participant.accountID === option.accountID) { return {...participant, selected: !participant.selected}; } @@ -559,4 +560,4 @@ export default compose( key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, }, }), -)(IOURequestStepConfirmation); \ No newline at end of file +)(IOURequestStepConfirmation); From 6e3d1d6966f423ff9343b790aae18323b6a402f5 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 27 Mar 2024 13:53:41 +0100 Subject: [PATCH 25/78] type compose, type function params --- src/libs/TransactionUtils.ts | 2 +- src/libs/actions/IOU.ts | 4 ++-- .../iou/request/step/IOURequestStepConfirmation.tsx | 13 ++++++------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 32356d56898a..402241849400 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -505,7 +505,7 @@ function getWaypointIndex(key: string): number { /** * Filters the waypoints which are valid and returns those */ -function getValidWaypoints(waypoints: WaypointCollection, reArrangeIndexes = false): WaypointCollection { +function getValidWaypoints(waypoints: WaypointCollection | undefined = {}, reArrangeIndexes = false): WaypointCollection { const sortedIndexes = Object.keys(waypoints) .map(getWaypointIndex) .sort((a, b) => a - b); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 868b9348cb01..d142aae5dcd2 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2160,7 +2160,7 @@ function trackExpense( currency: string, created: string, merchant: string, - payeeEmail: string, + payeeEmail: string | undefined, payeeAccountID: number, participant: Participant, comment: string, @@ -2173,7 +2173,7 @@ function trackExpense( policy?: OnyxEntry, policyTagList?: OnyxEntry, policyCategories?: OnyxEntry, - gpsPoints = undefined, + gpsPoints?: GpsPoint, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const { diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 516bd936674a..4b334f5c19d4 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -3,6 +3,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -42,12 +43,12 @@ type IOURequestStepConfirmationOnyxProps = { policy: OnyxEntry; policyCategories: OnyxEntry; policyTags: OnyxEntry; + personalDetails: OnyxEntry; }; type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & IOURequestStepConfirmationStackProps & { currentUserPersonalDetails: CurrentUserPersonalDetails; - personalDetails: PersonalDetailsList; report: Report; transaction: Transaction; }; @@ -436,7 +437,7 @@ function IOURequestStepConfirmation({ * @param {String} paymentMethodType */ const sendMoney = useCallback( - (paymentMethodType) => { + (paymentMethodType: ValueOf) => { const currency = transaction.currency; const trimmedComment = transaction.comment?.comment ? transaction.comment.comment.trim() : ''; @@ -468,7 +469,7 @@ function IOURequestStepConfirmation({ /** * @param billable */ - const setBillable = (billable) => { + const setBillable = (billable: boolean) => { IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, billable); }; @@ -543,13 +544,11 @@ export default compose( withCurrentUserPersonalDetails, withWritableReportOrNotFound, withFullTransactionOrNotFound, - withOnyx({ + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, }, From cafcdab921958ff2cbdeb9bca6f99b8866665313 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 27 Mar 2024 17:06:57 +0100 Subject: [PATCH 26/78] cleanup optional params, participants wip --- .../withCurrentUserPersonalDetails.tsx | 2 +- src/libs/OptionsListUtils.ts | 2 +- src/libs/actions/IOU.ts | 4 +- .../step/IOURequestStepConfirmation.tsx | 109 ++++++++++-------- 4 files changed, 68 insertions(+), 49 deletions(-) diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index 8431ededcb56..03b9cd1acac4 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -39,7 +39,7 @@ export default function ) /** * Get the participant option for a report. */ -function getParticipantsOption(participant: ReportUtils.OptionData, personalDetails: OnyxEntry): Participant { +function getParticipantsOption(participant: ReportUtils.OptionData | Participant, personalDetails: OnyxEntry): Participant { const detail = getPersonalDetailsForAccountIDs([participant.accountID ?? -1], personalDetails)[participant.accountID ?? -1]; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const login = detail?.login || participant.login || ''; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index d142aae5dcd2..d36446d79b86 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -387,7 +387,7 @@ function setMoneyRequestBillable_temporaryForRefactor(transactionID: string, bil } // eslint-disable-next-line @typescript-eslint/naming-convention -function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[]) { +function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants?: Participant[] = []) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } @@ -2061,7 +2061,7 @@ function requestMoney( amount: number, currency: string, created: string, - merchant: string | undefined, + merchant: string, payeeEmail: string | undefined, payeeAccountID: number, participant: Participant, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 4b334f5c19d4..f74dfbcea977 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -177,7 +177,10 @@ function IOURequestStepConfirmation({ * @param {File} [receiptObj] */ const requestMoney = useCallback( - (selectedParticipants: Participant[], trimmedComment: string, receiptObj: Receipt, gpsPoints: IOU.GpsPoint) => { + (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { + if (!receiptObj) { + return; + } IOU.requestMoney( report, transaction.amount, @@ -209,7 +212,10 @@ function IOURequestStepConfirmation({ * @param {File} [receiptObj] */ const trackExpense = useCallback( - (selectedParticipants: Participant[], trimmedComment: string, receiptObj: Receipt, gpsPoints?: IOU.GpsPoint) => { + (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { + if (!receiptObj) { + return; + } IOU.trackExpense( report, transaction.amount, @@ -290,57 +296,63 @@ function IOURequestStepConfirmation({ // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed if (iouType === CONST.IOU.TYPE.SPLIT && receiptFile) { - IOU.startSplitBill( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - trimmedComment, - transaction.category, - transaction.tag, - receiptFile, - report.reportID, - transaction.billable, - ); + if (currentUserPersonalDetails.login && transaction.category && transaction.tag) { + IOU.startSplitBill( + selectedParticipants, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + trimmedComment, + transaction.category, + transaction.tag, + receiptFile, + report.reportID, + transaction.billable, + ); + } return; } // IOUs created from a group report will have a reportID param in the route. // Since the user is already viewing the report, we don't need to navigate them to the report if (iouType === CONST.IOU.TYPE.SPLIT && !transaction.isFromGlobalCreate) { - IOU.splitBill( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transaction.amount, - trimmedComment, - transaction.currency, - transaction.merchant, - transaction.created, - transaction.category, - transaction.tag, - report.reportID, - transaction.billable, - transaction.iouRequestType, - ); + if (currentUserPersonalDetails.login && transaction.category && transaction.tag) { + IOU.splitBill( + selectedParticipants, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + transaction.amount, + trimmedComment, + transaction.currency, + transaction.merchant, + transaction.created, + transaction.category, + transaction.tag, + report.reportID, + transaction.billable, + transaction.iouRequestType, + ); + } return; } // If the request is created from the global create menu, we also navigate the user to the group report if (iouType === CONST.IOU.TYPE.SPLIT) { - IOU.splitBillAndOpenReport( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transaction.amount, - trimmedComment, - transaction.currency, - transaction.merchant, - transaction.created, - transaction.category, - transaction.tag, - transaction.billable, - transaction.iouRequestType, - ); + if (currentUserPersonalDetails.login && transaction.category && transaction.tag) { + IOU.splitBillAndOpenReport( + selectedParticipants, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + transaction.amount, + trimmedComment, + transaction.currency, + transaction.merchant, + transaction.created, + transaction.category, + transaction.tag, + !!transaction.billable, + transaction.iouRequestType, + ); + } return; } @@ -444,7 +456,7 @@ function IOURequestStepConfirmation({ const participant = participants?.[0]; - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE && participant) { IOU.sendMoneyElsewhere(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); return; } @@ -456,7 +468,7 @@ function IOURequestStepConfirmation({ [transaction.amount, transaction.comment, transaction.currency, participants, currentUserPersonalDetails.accountID, report], ); - const addNewParticipant = (option) => { + const addNewParticipant = (option: Participant) => { const newParticipants = transaction.participants?.map((participant) => { if (participant.accountID === option.accountID) { return {...participant, selected: !participant.selected}; @@ -505,7 +517,7 @@ function IOURequestStepConfirmation({ hasMultipleParticipants={iouType === CONST.IOU.TYPE.SPLIT} selectedParticipants={participants} iouAmount={transaction.amount} - iouComment={lodashGet(transaction, 'comment.comment', '')} + iouComment={transaction.comment.comment ?? ''} iouCurrencyCode={transaction.currency} iouIsBillable={transaction.billable} onToggleBillable={setBillable} @@ -530,6 +542,13 @@ function IOURequestStepConfirmation({ iouCreated={transaction.created} isDistanceRequest={requestType === CONST.IOU.REQUEST_TYPE.DISTANCE} shouldShowSmartScanFields={requestType !== CONST.IOU.REQUEST_TYPE.SCAN} + // reportActionID={undefined} + // hasSmartScanFailed={undefined} + // isEditingSplitBill={undefined} + // isReadOnly={undefined} + // isScanRequest={undefined} + // listStyles={undefined} + // payeePersonalDetails={undefined} /> From c04e0a4728ed8ffcbdec40d7339ece3132b5860b Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Fri, 29 Mar 2024 12:25:46 +0100 Subject: [PATCH 27/78] make function params named, modify types, add transaction checks --- src/libs/TransactionUtils.ts | 19 +- src/libs/actions/IOU.ts | 110 +++++--- .../step/IOURequestStepConfirmation.js | 78 +++--- .../step/IOURequestStepConfirmation.tsx | 258 ++++++++---------- .../iou/steps/MoneyRequestConfirmPage.js | 58 ++-- tests/actions/IOUTest.ts | 30 +- 6 files changed, 281 insertions(+), 272 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 402241849400..7c5f96b1aa50 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -48,19 +48,22 @@ function isDistanceRequest(transaction: OnyxEntry): boolean { function isScanRequest(transaction: Transaction): boolean { // This is used during the request creation flow before the transaction has been saved to the server if (lodashHas(transaction, 'iouRequestType')) { - return transaction.iouRequestType === CONST.IOU.REQUEST_TYPE.SCAN; + return transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.SCAN; } return Boolean(transaction?.receipt?.source); } -function getRequestType(transaction: Transaction): ValueOf { - if (isDistanceRequest(transaction)) { - return CONST.IOU.REQUEST_TYPE.DISTANCE; - } - if (isScanRequest(transaction)) { - return CONST.IOU.REQUEST_TYPE.SCAN; +function getRequestType(transaction: OnyxEntry): ValueOf { + if (transaction) { + if (isDistanceRequest(transaction)) { + return CONST.IOU.REQUEST_TYPE.DISTANCE; + } + if (isScanRequest(transaction)) { + return CONST.IOU.REQUEST_TYPE.SCAN; + } } + return CONST.IOU.REQUEST_TYPE.MANUAL; } @@ -417,7 +420,7 @@ function getCreated(transaction: OnyxEntry, dateFormat: string = CO /** * Returns the translation key to use for the header title */ -function getHeaderTitleTranslationKey(transaction: Transaction): TranslationPaths { +function getHeaderTitleTranslationKey(transaction: OnyxEntry): TranslationPaths { const headerTitles: Record = { [CONST.IOU.REQUEST_TYPE.DISTANCE]: 'tabSelector.distance', [CONST.IOU.REQUEST_TYPE.MANUAL]: 'tabSelector.manual', diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index d36446d79b86..780ffcf5f65e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -387,7 +387,7 @@ function setMoneyRequestBillable_temporaryForRefactor(transactionID: string, bil } // eslint-disable-next-line @typescript-eslint/naming-convention -function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants?: Participant[] = []) { +function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[] | undefined = []) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } @@ -2615,25 +2615,41 @@ function createSplitsAndOnyxData( }; } +type SplitBillActionsParams = { + participants: Participant[]; + currentUserLogin: string; + currentUserAccountID: number; + amount: number; + comment: string; + currency: string; + merchant: string; + created: string; + category?: string; + tag?: string; + billable?: boolean; + iouRequestType?: IOURequestType; + existingSplitChatReportID?: string; +}; + /** * @param amount - always in smallest currency unit * @param existingSplitChatReportID - Either a group DM or a workspace chat */ -function splitBill( - participants: Participant[], - currentUserLogin: string, - currentUserAccountID: number, - amount: number, - comment: string, - currency: string, - merchant: string, - created: string, - category: string, - tag: string, - existingSplitChatReportID = '', +function splitBill({ + participants, + currentUserLogin, + currentUserAccountID, + amount, + comment, + currency, + merchant, + created, + category = '', + tag = '', billable = false, - iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL, -) { + iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, + existingSplitChatReportID = '', +}: SplitBillActionsParams) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {splitData, splits, onyxData} = createSplitsAndOnyxData( participants, @@ -2678,20 +2694,20 @@ function splitBill( /** * @param amount - always in the smallest currency unit */ -function splitBillAndOpenReport( - participants: Participant[], - currentUserLogin: string, - currentUserAccountID: number, - amount: number, - comment: string, - currency: string, - merchant: string, - created: string, - category: string, - tag: string, - billable: boolean, - iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL, -) { +function splitBillAndOpenReport({ + participants, + currentUserLogin, + currentUserAccountID, + amount, + comment, + currency, + merchant, + created, + category = '', + tag = '', + billable = false, + iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL, +}: SplitBillActionsParams) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const {splitData, splits, onyxData} = createSplitsAndOnyxData( participants, @@ -2733,22 +2749,34 @@ function splitBillAndOpenReport( Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); } +type StartSplitBilActionParams = { + participants: Participant[]; + currentUserLogin: string; + currentUserAccountID: number; + comment: string; + receipt: Receipt; + existingSplitChatReportID?: string; + billable?: boolean; + category: string | undefined; + tag: string | undefined; +}; + /** Used exclusively for starting a split bill request that contains a receipt, the split request will be completed once the receipt is scanned * or user enters details manually. * * @param existingSplitChatReportID - Either a group DM or a workspace chat */ -function startSplitBill( - participants: Participant[], - currentUserLogin: string, - currentUserAccountID: number, - comment: string, - category: string, - tag: string, - receipt: Receipt, +function startSplitBill({ + participants, + currentUserLogin, + currentUserAccountID, + comment, + receipt, existingSplitChatReportID = '', billable = false, -) { + category = '', + tag = '', +}: StartSplitBilActionParams) { const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); const existingSplitChatReport = @@ -3008,7 +3036,7 @@ function startSplitBill( splits: JSON.stringify(splits), receipt, comment, - category, + category: category ?? '', tag, isFromGroupDM: !existingSplitChatReport, billable, @@ -4465,7 +4493,7 @@ function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxT * @param managerID - Account ID of the person sending the money * @param recipient - The user receiving the money */ -function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { +function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant | ReportUtils.OptionData) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerID, recipient); API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); @@ -4479,7 +4507,7 @@ function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: * @param managerID - Account ID of the person sending the money * @param recipient - The user receiving the money */ -function sendMoneyWithWallet(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { +function sendMoneyWithWallet(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant | ReportUtils.OptionData) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerID, recipient); API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.js b/src/pages/iou/request/step/IOURequestStepConfirmation.js index 435121a76028..46694de54125 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.js +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.js @@ -309,57 +309,57 @@ function IOURequestStepConfirmation({ // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed if (iouType === CONST.IOU.TYPE.SPLIT && receiptFile) { - IOU.startSplitBill( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - trimmedComment, - transaction.category, - transaction.tag, + IOU.startSplitBill({ + participants: selectedParticipants, + currentUserLogin: currentUserPersonalDetails.login, + currentUserAccountID: currentUserPersonalDetails.accountID, + comment: trimmedComment, receiptFile, - report.reportID, - transaction.billable, - ); + existingSplitChatReportID: report.reportID, + billable: transaction.billable, + category: transaction.category, + tag: transaction.tag, + }); return; } // IOUs created from a group report will have a reportID param in the route. // Since the user is already viewing the report, we don't need to navigate them to the report if (iouType === CONST.IOU.TYPE.SPLIT && !transaction.isFromGlobalCreate) { - IOU.splitBill( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transaction.amount, - trimmedComment, - transaction.currency, - transaction.merchant, - transaction.created, - transaction.category, - transaction.tag, - report.reportID, - transaction.billable, - transaction.iouRequestType, - ); + IOU.splitBill({ + participants: selectedParticipants, + currentUserLogin: currentUserPersonalDetails.login, + currentUserAccountID: currentUserPersonalDetails.accountID, + amount: transaction.amount, + comment: trimmedComment, + currency: transaction.currency, + merchant: transaction.merchant, + created: transaction.created, + category: transaction.category, + tag: transaction.tag, + existingSplitChatReportID: report.reportID, + billable: transaction.billable, + iouRequestType: transaction.iouRequestType, + }); return; } // If the request is created from the global create menu, we also navigate the user to the group report if (iouType === CONST.IOU.TYPE.SPLIT) { - IOU.splitBillAndOpenReport( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transaction.amount, - trimmedComment, - transaction.currency, - transaction.merchant, - transaction.created, - transaction.category, - transaction.tag, - transaction.billable, - transaction.iouRequestType, - ); + IOU.splitBillAndOpenReport({ + participants: selectedParticipants, + currentUserLogin: currentUserPersonalDetails.login, + currentUserAccountID: currentUserPersonalDetails.accountID, + amount: transaction.amount, + comment: trimmedComment, + currency: transaction.currency, + merchant: transaction.merchant, + created: transaction.created, + category: transaction.category, + tag: transaction.tag, + billable: transaction.billable, + iouRequestType: transaction.iouRequestType, + }); return; } diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index f74dfbcea977..c62f6dd64685 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,3 +1,4 @@ +/* eslint-disable rulesdir/no-negated-variables */ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; @@ -9,14 +10,12 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; import ScreenWrapper from '@components/ScreenWrapper'; -import type {CurrentUserPersonalDetails} from '@components/withCurrentUserPersonalDetails'; -import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import {openDraftWorkspaceRequest} from '@libs/actions/Policy'; -import compose from '@libs/compose'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as IOUUtils from '@libs/IOUUtils'; @@ -31,11 +30,12 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Report, Transaction} from '@src/types/onyx'; +import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Transaction} from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {Receipt} from '@src/types/onyx/Transaction'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; +import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; type IOURequestStepConfirmationStackProps = StackScreenProps; @@ -47,14 +47,12 @@ type IOURequestStepConfirmationOnyxProps = { }; type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & - IOURequestStepConfirmationStackProps & { - currentUserPersonalDetails: CurrentUserPersonalDetails; - report: Report; - transaction: Transaction; + IOURequestStepConfirmationStackProps & + WithWritableReportOrNotFoundProps & { + transaction: OnyxEntry; }; function IOURequestStepConfirmation({ - currentUserPersonalDetails, personalDetails, policy, policyTags, @@ -65,17 +63,19 @@ function IOURequestStepConfirmation({ }, transaction, }: IOURequestStepConfirmationProps) { + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const styles = useThemeStyles(); const {translate} = useLocalize(); const {windowWidth} = useWindowDimensions(); const {isOffline} = useNetwork(); const [receiptFile, setReceiptFile] = useState(); - const receiptFilename = transaction.filename; - const receiptPath = transaction.receipt?.source; - const receiptType = transaction.receipt?.type; - const transactionTaxCode = transaction.taxRate?.keyForList; - const transactionTaxAmount = transaction.taxAmount; + const receiptFilename = transaction?.filename; + const receiptPath = transaction?.receipt?.source; + const receiptType = transaction?.receipt?.type; + const transactionTaxCode = transaction?.taxRate?.keyForList; + const transactionTaxAmount = transaction?.taxAmount; + const requestType = TransactionUtils.getRequestType(transaction); const headerTitle = useMemo(() => { @@ -93,11 +93,11 @@ function IOURequestStepConfirmation({ const participants = useMemo( () => - transaction.participants?.map((participant) => { + transaction?.participants?.map((participant) => { const participantAccountID = participant.accountID ?? 0; return participant && participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); }), - [transaction.participants, personalDetails], + [transaction?.participants, personalDetails], ); const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); const formHasBeenSubmitted = useRef(false); @@ -116,7 +116,7 @@ function IOURequestStepConfirmation({ if (policyExpenseChat?.policyID) { openDraftWorkspaceRequest(policyExpenseChat.policyID); } - }, [isOffline, participants, transaction.billable, policy, transactionID]); + }, [isOffline, participants, transaction?.billable, policy, transactionID]); const defaultBillable = !!policy?.defaultBillable; useEffect(() => { @@ -124,19 +124,19 @@ function IOURequestStepConfirmation({ }, [transactionID, defaultBillable]); useEffect(() => { - if (!transaction.category) { + if (!transaction?.category) { return; } if (policyCategories?.[transaction.category] && !policyCategories[transaction.category].enabled) { IOU.setMoneyRequestCategory(transactionID, ''); } - }, [policyCategories, transaction.category, transactionID]); + }, [policyCategories, transaction?.category, transactionID]); const policyDistance = Object.values(policy?.customUnits ?? {}).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); const defaultCategory = policyDistance?.defaultCategory ?? ''; useEffect(() => { - if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !!transaction.category) { + if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !!transaction?.category) { return; } IOU.setMoneyRequestCategory(transactionID, defaultCategory); @@ -147,7 +147,7 @@ function IOURequestStepConfirmation({ const navigateBack = useCallback(() => { // If there is not a report attached to the IOU with a reportID, then the participants were manually selected and the user needs taken // back to the participants step - if (!transaction.participantsAutoAssigned) { + if (!transaction?.participantsAutoAssigned) { Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); return; } @@ -178,7 +178,7 @@ function IOURequestStepConfirmation({ */ const requestMoney = useCallback( (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { - if (!receiptObj) { + if (!receiptObj || !report || !transaction) { return; } IOU.requestMoney( @@ -206,14 +206,9 @@ function IOURequestStepConfirmation({ [report, transaction, transactionTaxCode, transactionTaxAmount, currentUserPersonalDetails.login, currentUserPersonalDetails.accountID, policy, policyTags, policyCategories], ); - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - * @param {File} [receiptObj] - */ const trackExpense = useCallback( (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { - if (!receiptObj) { + if (!receiptObj || !report || !transaction) { return; } IOU.trackExpense( @@ -238,31 +233,14 @@ function IOURequestStepConfirmation({ gpsPoints, ); }, - [ - report, - transaction.amount, - transaction.currency, - transaction.created, - transaction.merchant, - transaction.category, - transaction.tag, - transaction.billable, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transactionTaxCode, - transactionTaxAmount, - policy, - policyTags, - policyCategories, - ], + [report, transaction, currentUserPersonalDetails.login, currentUserPersonalDetails.accountID, transactionTaxCode, transactionTaxAmount, policy, policyTags, policyCategories], ); - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - */ const createDistanceRequest = useCallback( (selectedParticipants: Participant[], trimmedComment: string) => { + if (!report || !transaction) { + return; + } IOU.createDistanceRequest( report, selectedParticipants[0], @@ -285,7 +263,7 @@ function IOURequestStepConfirmation({ const createTransaction = useCallback( (selectedParticipants: Participant[]) => { - const trimmedComment = (transaction.comment.comment ?? '').trim(); + const trimmedComment = (transaction?.comment.comment ?? '').trim(); // Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page if (formHasBeenSubmitted.current) { @@ -296,68 +274,68 @@ function IOURequestStepConfirmation({ // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed if (iouType === CONST.IOU.TYPE.SPLIT && receiptFile) { - if (currentUserPersonalDetails.login && transaction.category && transaction.tag) { - IOU.startSplitBill( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - trimmedComment, - transaction.category, - transaction.tag, - receiptFile, - report.reportID, - transaction.billable, - ); + if (currentUserPersonalDetails.login && !!transaction) { + IOU.startSplitBill({ + participants: selectedParticipants, + currentUserLogin: currentUserPersonalDetails.login, + currentUserAccountID: currentUserPersonalDetails.accountID, + comment: trimmedComment, + receipt: receiptFile, + existingSplitChatReportID: report?.reportID, + billable: transaction.billable, + category: transaction.category, + tag: transaction.tag, + }); } return; } // IOUs created from a group report will have a reportID param in the route. // Since the user is already viewing the report, we don't need to navigate them to the report - if (iouType === CONST.IOU.TYPE.SPLIT && !transaction.isFromGlobalCreate) { - if (currentUserPersonalDetails.login && transaction.category && transaction.tag) { - IOU.splitBill( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transaction.amount, - trimmedComment, - transaction.currency, - transaction.merchant, - transaction.created, - transaction.category, - transaction.tag, - report.reportID, - transaction.billable, - transaction.iouRequestType, - ); + if (iouType === CONST.IOU.TYPE.SPLIT && !transaction?.isFromGlobalCreate) { + if (currentUserPersonalDetails.login && !!transaction) { + IOU.splitBill({ + participants: selectedParticipants, + currentUserLogin: currentUserPersonalDetails.login, + currentUserAccountID: currentUserPersonalDetails.accountID, + amount: transaction.amount, + comment: trimmedComment, + currency: transaction.currency, + merchant: transaction.merchant, + created: transaction.created, + category: transaction.category, + tag: transaction.tag, + existingSplitChatReportID: report?.reportID, + billable: transaction.billable, + iouRequestType: transaction.iouRequestType, + }); } return; } // If the request is created from the global create menu, we also navigate the user to the group report if (iouType === CONST.IOU.TYPE.SPLIT) { - if (currentUserPersonalDetails.login && transaction.category && transaction.tag) { - IOU.splitBillAndOpenReport( - selectedParticipants, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transaction.amount, - trimmedComment, - transaction.currency, - transaction.merchant, - transaction.created, - transaction.category, - transaction.tag, - !!transaction.billable, - transaction.iouRequestType, - ); + if (currentUserPersonalDetails.login && !!transaction) { + IOU.splitBillAndOpenReport({ + participants: selectedParticipants, + currentUserLogin: currentUserPersonalDetails.login, + currentUserAccountID: currentUserPersonalDetails.accountID, + amount: transaction.amount, + comment: trimmedComment, + currency: transaction.currency, + merchant: transaction.merchant, + created: transaction.created, + category: transaction.category, + tag: transaction.tag, + billable: !!transaction.billable, + iouRequestType: transaction.iouRequestType, + }); } return; } if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { - if (receiptFile) { + if (receiptFile && transaction) { // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. if (transaction.amount === 0) { getCurrentPosition( @@ -391,7 +369,7 @@ function IOURequestStepConfirmation({ return; } - if (receiptFile) { + if (receiptFile && !!transaction) { // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. if (transaction.amount === 0) { getCurrentPosition( @@ -437,7 +415,7 @@ function IOURequestStepConfirmation({ requestMoney, currentUserPersonalDetails.login, currentUserPersonalDetails.accountID, - report.reportID, + report?.reportID, trackExpense, createDistanceRequest, ], @@ -450,13 +428,17 @@ function IOURequestStepConfirmation({ */ const sendMoney = useCallback( (paymentMethodType: ValueOf) => { - const currency = transaction.currency; + const currency = transaction?.currency; - const trimmedComment = transaction.comment?.comment ? transaction.comment.comment.trim() : ''; + const trimmedComment = transaction?.comment?.comment ? transaction.comment.comment.trim() : ''; const participant = participants?.[0]; - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE && participant) { + if (!participant || !report || !transaction?.amount || !currency) { + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { IOU.sendMoneyElsewhere(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); return; } @@ -465,11 +447,11 @@ function IOURequestStepConfirmation({ IOU.sendMoneyWithWallet(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); } }, - [transaction.amount, transaction.comment, transaction.currency, participants, currentUserPersonalDetails.accountID, report], + [transaction?.amount, transaction?.comment, transaction?.currency, participants, currentUserPersonalDetails.accountID, report], ); const addNewParticipant = (option: Participant) => { - const newParticipants = transaction.participants?.map((participant) => { + const newParticipants = transaction?.participants?.map((participant) => { if (participant.accountID === option.accountID) { return {...participant, selected: !participant.selected}; } @@ -478,9 +460,6 @@ function IOURequestStepConfirmation({ IOU.setMoneyRequestParticipants_temporaryForRefactor(transactionID, newParticipants); }; - /** - * @param billable - */ const setBillable = (billable: boolean) => { IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, billable); }; @@ -516,12 +495,12 @@ function IOURequestStepConfirmation({ transaction={transaction} hasMultipleParticipants={iouType === CONST.IOU.TYPE.SPLIT} selectedParticipants={participants} - iouAmount={transaction.amount} - iouComment={transaction.comment.comment ?? ''} - iouCurrencyCode={transaction.currency} - iouIsBillable={transaction.billable} + iouAmount={transaction?.amount} + iouComment={transaction?.comment.comment ?? ''} + iouCurrencyCode={transaction?.currency} + iouIsBillable={transaction?.billable} onToggleBillable={setBillable} - iouCategory={transaction.category} + iouCategory={transaction?.category} onConfirm={createTransaction} onSendMoney={sendMoney} onSelectParticipant={addNewParticipant} @@ -535,20 +514,20 @@ function IOURequestStepConfirmation({ // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from // the floating-action-button (since it is something that exists outside the context of a report). - canModifyParticipants={!transaction.isFromGlobalCreate} - policyID={report.policyID} + canModifyParticipants={!transaction?.isFromGlobalCreate} + policyID={report?.policyID} bankAccountRoute={ReportUtils.getBankAccountRoute(report)} - iouMerchant={transaction.merchant} - iouCreated={transaction.created} + iouMerchant={transaction?.merchant} + iouCreated={transaction?.created} isDistanceRequest={requestType === CONST.IOU.REQUEST_TYPE.DISTANCE} shouldShowSmartScanFields={requestType !== CONST.IOU.REQUEST_TYPE.SCAN} - // reportActionID={undefined} - // hasSmartScanFailed={undefined} - // isEditingSplitBill={undefined} - // isReadOnly={undefined} - // isScanRequest={undefined} - // listStyles={undefined} - // payeePersonalDetails={undefined} + reportActionID={undefined} + hasSmartScanFailed={undefined} + isEditingSplitBill={undefined} + isReadOnly={undefined} + isScanRequest={undefined} + listStyles={undefined} + payeePersonalDetails={undefined} /> @@ -559,23 +538,20 @@ function IOURequestStepConfirmation({ IOURequestStepConfirmation.displayName = 'IOURequestStepConfirmation'; -export default compose( - withCurrentUserPersonalDetails, - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(IOURequestStepConfirmation); +const ComponentWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmation); +const ComponentWithFullTransactionOrNotFound = withFullTransactionOrNotFound(ComponentWithWritableReportOrNotFound); +export default withOnyx({ + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, + }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, + }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, + }, + // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. +})(ComponentWithFullTransactionOrNotFound); diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js index 1738ac78df47..fac3d51a1fd6 100644 --- a/src/pages/iou/steps/MoneyRequestConfirmPage.js +++ b/src/pages/iou/steps/MoneyRequestConfirmPage.js @@ -245,14 +245,14 @@ function MoneyRequestConfirmPage(props) { if (iouType === CONST.IOU.TYPE.SPLIT && props.iou.receiptPath) { const existingSplitChatReportID = CONST.REGEX.NUMBER.test(reportID) ? reportID : ''; const onSuccess = (receipt) => { - IOU.startSplitBill( - selectedParticipants, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - trimmedComment, + IOU.startSplitBill({ + participants: selectedParticipants, + currentUserLogin: props.currentUserPersonalDetails.login, + currentUserAccountID: props.currentUserPersonalDetails.accountID, + comment: trimmedComment, receipt, existingSplitChatReportID, - ); + }); }; FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename, onSuccess); return; @@ -261,34 +261,34 @@ function MoneyRequestConfirmPage(props) { // IOUs created from a group report will have a reportID param in the route. // Since the user is already viewing the report, we don't need to navigate them to the report if (iouType === CONST.IOU.TYPE.SPLIT && CONST.REGEX.NUMBER.test(reportID)) { - IOU.splitBill( - selectedParticipants, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.amount, - trimmedComment, - props.iou.currency, - props.iou.category, - props.iou.tag, - reportID, - props.iou.merchant, - ); + IOU.splitBill({ + participants: selectedParticipants, + currentUserLogin: props.currentUserPersonalDetails.login, + currentUserAccountID: props.currentUserPersonalDetails.accountID, + amount: props.iou.amount, + comment: trimmedComment, + currency: props.iou.currency, + merchant: props.iou.merchant, + category: props.iou.category, + tag: props.iou.tag, + existingSplitChatReportID: reportID, + }); return; } // If the request is created from the global create menu, we also navigate the user to the group report if (iouType === CONST.IOU.TYPE.SPLIT) { - IOU.splitBillAndOpenReport( - selectedParticipants, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.amount, - trimmedComment, - props.iou.currency, - props.iou.category, - props.iou.tag, - props.iou.merchant, - ); + IOU.splitBillAndOpenReport({ + participants: selectedParticipants, + currentUserLogin: props.currentUserPersonalDetails.login, + currentUserAccountID: props.currentUserPersonalDetails.accountID, + amount: props.iou.amount, + comment: trimmedComment, + currency: props.iou.currency, + merchant: props.iou.merchant, + category: props.iou.category, + tag: props.iou.tag, + }); return; } diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 3298cd51c9f1..b6ecde9adb8b 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -1041,20 +1041,22 @@ describe('actions/IOU', () => { fetch.pause(); IOU.splitBill( // TODO: Migrate after the backend accepts accountIDs - [ - [CARLOS_EMAIL, String(CARLOS_ACCOUNT_ID)], - [JULES_EMAIL, String(JULES_ACCOUNT_ID)], - [VIT_EMAIL, String(VIT_ACCOUNT_ID)], - ].map(([email, accountID]) => ({login: email, accountID: Number(accountID)})), - RORY_EMAIL, - RORY_ACCOUNT_ID, - amount, - comment, - CONST.CURRENCY.USD, - merchant, - '', - '', - '', + { + participants: [ + [CARLOS_EMAIL, String(CARLOS_ACCOUNT_ID)], + [JULES_EMAIL, String(JULES_ACCOUNT_ID)], + [VIT_EMAIL, String(VIT_ACCOUNT_ID)], + ].map(([email, accountID]) => ({login: email, accountID: Number(accountID)})), + currentUserLogin: RORY_EMAIL, + currentUserAccountID: RORY_ACCOUNT_ID, + amount, + comment, + currency: CONST.CURRENCY.USD, + merchant, + created: '', + tag: '', + existingSplitChatReportID: '', + }, ); return waitForBatchedUpdates(); }) From 7658a253922bab285f4075969d5ff2dfd7599a6a Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Sat, 30 Mar 2024 01:41:32 +0100 Subject: [PATCH 28/78] cleanup --- src/libs/actions/IOU.ts | 2 +- .../step/IOURequestStepConfirmation.tsx | 35 +++++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 780ffcf5f65e..300f7de1c2bb 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4052,7 +4052,7 @@ function getSendMoneyParams( comment: string, paymentMethodType: PaymentMethodType, managerID: number, - recipient: Participant, + recipient: Participant | ReportUtils.OptionData, ): SendMoneyParamsData { const recipientEmail = PhoneNumber.addSMSDomainIfPhoneNumber(recipient.login ?? ''); const recipientAccountID = Number(recipient.accountID); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index c62f6dd64685..dc7e6a615ae8 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,10 +1,9 @@ -/* eslint-disable rulesdir/no-negated-variables */ -import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; +import type { StackScreenProps } from '@react-navigation/stack'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { View } from 'react-native'; +import type { OnyxEntry } from 'react-native-onyx'; +import { withOnyx } from 'react-native-onyx'; +import type { ValueOf } from 'type-fest'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -15,13 +14,13 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import {openDraftWorkspaceRequest} from '@libs/actions/Policy'; +import { openDraftWorkspaceRequest } from '@libs/actions/Policy'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; +import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -30,12 +29,13 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Transaction} from '@src/types/onyx'; -import type {Participant} from '@src/types/onyx/IOU'; -import type {Receipt} from '@src/types/onyx/Transaction'; +import type { PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Transaction } from '@src/types/onyx'; +import type { Participant } from '@src/types/onyx/IOU'; +import type { Receipt } from '@src/types/onyx/Transaction'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; +import type { WithWritableReportOrNotFoundProps } from './withWritableReportOrNotFound'; + type IOURequestStepConfirmationStackProps = StackScreenProps; @@ -171,11 +171,6 @@ function IOURequestStepConfirmation({ IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID, receiptType); }, [receiptType, receiptPath, receiptFilename, requestType, iouType, transactionID, reportID]); - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - * @param {File} [receiptObj] - */ const requestMoney = useCallback( (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { if (!receiptObj || !report || !transaction) { @@ -538,7 +533,9 @@ function IOURequestStepConfirmation({ IOURequestStepConfirmation.displayName = 'IOURequestStepConfirmation'; +/* eslint-disable rulesdir/no-negated-variables */ const ComponentWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmation); +/* eslint-disable rulesdir/no-negated-variables */ const ComponentWithFullTransactionOrNotFound = withFullTransactionOrNotFound(ComponentWithWritableReportOrNotFound); export default withOnyx({ personalDetails: { @@ -554,4 +551,4 @@ export default withOnyx `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, }, // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. -})(ComponentWithFullTransactionOrNotFound); +})(ComponentWithFullTransactionOrNotFound); \ No newline at end of file From 0e457d85320f61a39a8d373095ef4662b5d03ded Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Sat, 30 Mar 2024 03:53:58 +0100 Subject: [PATCH 29/78] migrate iouRequestStepCategory, adjust route types --- src/components/CategoryPicker.tsx | 4 +- src/libs/Navigation/types.ts | 4 +- src/libs/OptionsListUtils.ts | 10 +- src/libs/ReportUtils.ts | 12 +- src/libs/SidebarUtils.ts | 12 +- src/libs/actions/IOU.ts | 6 +- .../request/step/IOURequestStepCategory.tsx | 171 ++++++++++++++++++ .../step/IOURequestStepConfirmation.tsx | 27 ++- 8 files changed, 208 insertions(+), 38 deletions(-) create mode 100644 src/pages/iou/request/step/IOURequestStepCategory.tsx diff --git a/src/components/CategoryPicker.tsx b/src/components/CategoryPicker.tsx index 3033bf118e8f..9fc570e21006 100644 --- a/src/components/CategoryPicker.tsx +++ b/src/components/CategoryPicker.tsx @@ -21,7 +21,7 @@ type CategoryPickerProps = CategoryPickerOnyxProps & { /** It's used by withOnyx HOC */ // eslint-disable-next-line react/no-unused-prop-types policyID: string; - selectedCategory: string; + selectedCategory: string | undefined; onSubmit: (item: ListItem) => void; }; @@ -38,7 +38,7 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC { name: selectedCategory, enabled: true, - accountID: null, + accountID: undefined, isSelected: true, }, ]; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4846251cac4a..44c427eb32a2 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -356,8 +356,8 @@ type MoneyRequestNavigatorParamList = { action: ValueOf; iouType: ValueOf; transactionID: string; - reportID: string; - backTo: string; + reportActionID: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { iouType: string; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index cd8e93b1bf4f..870f24044cce 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -611,7 +611,7 @@ function createOption( ): ReportUtils.OptionData { const result: ReportUtils.OptionData = { text: undefined, - alternateText: null, + alternateText: undefined, pendingAction: undefined, allReportErrors: undefined, brickRoadIndicator: null, @@ -621,12 +621,12 @@ function createOption( subtitle: null, participantsList: undefined, accountID: 0, - login: null, + login: undefined, reportID: '', - phoneNumber: null, + phoneNumber: undefined, hasDraftComment: false, - keyForList: null, - searchText: null, + keyForList: undefined, + searchText: undefined, isDefaultRoom: false, isPinned: false, isWaitingOnBankAccount: false, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e7a6af8c6f3a..6dea32275a08 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -363,7 +363,7 @@ type CustomIcon = { type OptionData = { text?: string; - alternateText?: string | null; + alternateText?: string; allReportErrors?: Errors; brickRoadIndicator?: ValueOf | '' | null; tooltipText?: string | null; @@ -371,16 +371,16 @@ type OptionData = { boldStyle?: boolean; customIcon?: CustomIcon; subtitle?: string | null; - login?: string | null; - accountID?: number | null; + login?: string; + accountID?: number; pronouns?: string; status?: Status | null; - phoneNumber?: string | null; + phoneNumber?: string; isUnread?: boolean | null; isUnreadWithMention?: boolean | null; hasDraftComment?: boolean | null; - keyForList?: string | null; - searchText?: string | null; + keyForList?: string; + searchText?: string; isIOUReportOwner?: boolean | null; isArchivedRoom?: boolean | null; shouldShowSubscript?: boolean | null; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 63b907a42e25..43dfc11ab191 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -211,20 +211,20 @@ function getOptionData({ const result: ReportUtils.OptionData = { text: '', - alternateText: null, + alternateText: undefined, allReportErrors: OptionsListUtils.getAllReportErrors(report, reportActions), brickRoadIndicator: null, tooltipText: null, subtitle: null, - login: null, - accountID: null, + login: undefined, + accountID: undefined, reportID: '', - phoneNumber: null, + phoneNumber: undefined, isUnread: null, isUnreadWithMention: null, hasDraftComment: false, - keyForList: null, - searchText: null, + keyForList: undefined, + searchText: undefined, isPinned: false, hasOutstandingChildRequest: false, isIOUReportOwner: null, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 300f7de1c2bb..38eceda02352 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2005,7 +2005,7 @@ function updateMoneyRequestDistance( function updateMoneyRequestCategory( transactionID: string, transactionThreadReportID: string, - category: string, + category: string | undefined, policy: OnyxEntry, policyTagList: OnyxEntry, policyCategories: OnyxEntry, @@ -4052,7 +4052,7 @@ function getSendMoneyParams( comment: string, paymentMethodType: PaymentMethodType, managerID: number, - recipient: Participant | ReportUtils.OptionData, + recipient: Participant, ): SendMoneyParamsData { const recipientEmail = PhoneNumber.addSMSDomainIfPhoneNumber(recipient.login ?? ''); const recipientAccountID = Number(recipient.accountID); @@ -4493,7 +4493,7 @@ function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxT * @param managerID - Account ID of the person sending the money * @param recipient - The user receiving the money */ -function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant | ReportUtils.OptionData) { +function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) { const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerID, recipient); API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx new file mode 100644 index 000000000000..ee14b5bcef8e --- /dev/null +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -0,0 +1,171 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import lodashIsEmpty from 'lodash/isEmpty'; +import React from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import CategoryPicker from '@components/CategoryPicker'; +import type {ListItem} from '@components/SelectionList/types'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as ReportUtils from '@libs/ReportUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; +import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type {Policy, PolicyCategories, PolicyTagList, ReportActions, Session, Transaction} from '@src/types/onyx'; +import StepScreenWrapper from './StepScreenWrapper'; +import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; +import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; +import withWritableReportOrNotFound from './withWritableReportOrNotFound'; + +type IOURequestStepCategoryStackProps = {stackProps: StackScreenProps}; + +type IOURequestStepCategoryOnyxProps = { + /** The draft transaction that holds data to be persisted on the current transaction */ + splitDraftTransaction: OnyxEntry; + /** The policy of the report */ + policy: OnyxEntry; + /** Collection of categories attached to a policy */ + policyCategories: OnyxEntry; + /** Collection of tags attached to a policy */ + policyTags: OnyxEntry; + /** The actions from the parent report */ + reportActions: OnyxEntry; + /** Session info for the currently logged in user. */ + session: OnyxEntry; +}; + +type IOURequestStepCategoryProps = IOURequestStepCategoryStackProps & + IOURequestStepCategoryOnyxProps & + WithWritableReportOrNotFoundProps & { + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + transaction: OnyxEntry; + }; + +function IOURequestStepCategory({ + report, + stackProps: { + route: { + params: {transactionID, backTo, action, iouType, reportActionID}, + }, + }, + transaction, + splitDraftTransaction, + policy, + policyTags, + policyCategories, + reportActions, + session, +}: IOURequestStepCategoryProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const isEditing = action === CONST.IOU.ACTION.EDIT; + const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT; + const transactionCategory = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction)?.category; + + const reportAction = reportActions?.[report?.parentReportActionID ?? reportActionID] ?? null; + const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (transactionCategory ?? OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); + const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; + const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); + // eslint-disable-next-line rulesdir/no-negated-variables + const shouldShowNotFoundPage = !shouldShowCategory || (isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction))); + + const navigateBack = () => { + Navigation.goBack(backTo); + }; + + const updateCategory = (category: ListItem) => { + const categorySearchText = category.searchText ?? ''; + const isSelectedCategory = categorySearchText === transactionCategory; + const updatedCategory = isSelectedCategory ? '' : categorySearchText; + + if (transaction) { + // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value + if (isEditingSplitBill) { + IOU.setDraftSplitTransaction(transaction.transactionID, {category: updatedCategory}); + navigateBack(); + return; + } + + if (isEditing && report) { + IOU.updateMoneyRequestCategory(transaction.transactionID, report.reportID, updatedCategory, policy, policyTags, policyCategories); + navigateBack(); + return; + } + } + + IOU.setMoneyRequestCategory(transactionID, updatedCategory); + + navigateBack(); + }; + + return ( + + {translate('iou.categorySelection')} + + + ); +} + +IOURequestStepCategory.displayName = 'IOURequestStepCategory'; + +/* eslint-disable rulesdir/no-negated-variables */ +const ComponentWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepCategory); +/* eslint-disable rulesdir/no-negated-variables */ +const ComponentWithFullTransactionOrNotFound = withFullTransactionOrNotFound(ComponentWithWritableReportOrNotFound); +export default withOnyx({ + splitDraftTransaction: { + key: ({route}) => { + const transactionID = route?.params.transactionID ?? 0; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; + }, + }, + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, + }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, + }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, + }, + reportActions: { + key: ({ + report, + route: { + params: {action, iouType}, + }, + }) => { + let reportID = '0'; + if (action === CONST.IOU.ACTION.EDIT && report) { + if (iouType === CONST.IOU.TYPE.SPLIT) { + reportID = report.reportID; + } else if (report.parentReportID) { + reportID = report.parentReportID; + } + } + return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; + }, + canEvict: false, + }, + session: { + key: ONYXKEYS.SESSION, + }, + // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. +})(ComponentWithFullTransactionOrNotFound); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index dc7e6a615ae8..3bde56792580 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1,9 +1,9 @@ -import type { StackScreenProps } from '@react-navigation/stack'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { View } from 'react-native'; -import type { OnyxEntry } from 'react-native-onyx'; -import { withOnyx } from 'react-native-onyx'; -import type { ValueOf } from 'type-fest'; +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -14,13 +14,13 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import { openDraftWorkspaceRequest } from '@libs/actions/Policy'; +import {openDraftWorkspaceRequest} from '@libs/actions/Policy'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getCurrentPosition from '@libs/getCurrentPosition'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import type { MoneyRequestNavigatorParamList } from '@libs/Navigation/types'; +import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -29,13 +29,12 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type { PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Transaction } from '@src/types/onyx'; -import type { Participant } from '@src/types/onyx/IOU'; -import type { Receipt } from '@src/types/onyx/Transaction'; +import type {PersonalDetailsList, Policy, PolicyCategories, PolicyTagList, Transaction} from '@src/types/onyx'; +import type {Participant} from '@src/types/onyx/IOU'; +import type {Receipt} from '@src/types/onyx/Transaction'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -import type { WithWritableReportOrNotFoundProps } from './withWritableReportOrNotFound'; - +import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; type IOURequestStepConfirmationStackProps = StackScreenProps; @@ -551,4 +550,4 @@ export default withOnyx `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, }, // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. -})(ComponentWithFullTransactionOrNotFound); \ No newline at end of file +})(ComponentWithFullTransactionOrNotFound); From f681840b1c0ab003e8cb2f5601f80fc7cb496340 Mon Sep 17 00:00:00 2001 From: gijoe0295 Date: Tue, 2 Apr 2024 10:39:30 +0700 Subject: [PATCH 30/78] fix: send a message button in help page is not working --- docs/_layouts/default.html | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 99f4b22b473c..4232c565e715 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -84,6 +84,7 @@

+ {% include CONST.html %}

Didn't find what you were looking for?

Concierge is here to answer all your questions.

From 6a947ccbf1cabb5ea1e6fcdffbdc03c15256e556 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 2 Apr 2024 10:19:47 +0200 Subject: [PATCH 31/78] cleanup --- .../request/step/IOURequestStepCategory.js | 191 ------ .../request/step/IOURequestStepCategory.tsx | 6 +- .../step/IOURequestStepConfirmation.js | 585 ------------------ .../step/IOURequestStepConfirmation.tsx | 6 +- 4 files changed, 6 insertions(+), 782 deletions(-) delete mode 100644 src/pages/iou/request/step/IOURequestStepCategory.js delete mode 100644 src/pages/iou/request/step/IOURequestStepConfirmation.js diff --git a/src/pages/iou/request/step/IOURequestStepCategory.js b/src/pages/iou/request/step/IOURequestStepCategory.js deleted file mode 100644 index 4f0c77480c04..000000000000 --- a/src/pages/iou/request/step/IOURequestStepCategory.js +++ /dev/null @@ -1,191 +0,0 @@ -import lodashGet from 'lodash/get'; -import lodashIsEmpty from 'lodash/isEmpty'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import CategoryPicker from '@components/CategoryPicker'; -import categoryPropTypes from '@components/categoryPropTypes'; -import tagPropTypes from '@components/tagPropTypes'; -import Text from '@components/Text'; -import transactionPropTypes from '@components/transactionPropTypes'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as ReportUtils from '@libs/ReportUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; -import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as IOU from '@userActions/IOU'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import {policyPropTypes} from '@src/pages/workspace/withPolicy'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; -import StepScreenWrapper from './StepScreenWrapper'; -import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; -import withWritableReportOrNotFound from './withWritableReportOrNotFound'; - -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: IOURequestStepRoutePropTypes.isRequired, - - /* Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - transaction: transactionPropTypes, - - /** The draft transaction that holds data to be persisted on the current transaction */ - splitDraftTransaction: transactionPropTypes, - - /** The report attached to the transaction */ - report: reportPropTypes, - - /** The policy of the report */ - policy: policyPropTypes.policy, - - /** Collection of categories attached to a policy */ - policyCategories: PropTypes.objectOf(categoryPropTypes), - - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, - - /** The actions from the parent report */ - reportActions: PropTypes.shape(reportActionPropTypes), - - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user accountID */ - accountID: PropTypes.number, - - /** Currently logged in user email */ - email: PropTypes.string, - }).isRequired, -}; - -const defaultProps = { - report: {}, - transaction: {}, - splitDraftTransaction: {}, - policy: null, - policyTags: null, - policyCategories: null, - reportActions: {}, -}; - -function IOURequestStepCategory({ - report, - route: { - params: {transactionID, backTo, action, iouType, reportActionID}, - }, - transaction, - splitDraftTransaction, - policy, - policyTags, - policyCategories, - session, - reportActions, -}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const isEditing = action === CONST.IOU.ACTION.EDIT; - const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT; - const {category: transactionCategory} = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction); - - const reportAction = reportActions[report.parentReportActionID || reportActionID]; - const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (transactionCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); - const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; - const canEditSplitBill = isSplitBill && reportAction && session.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); - // eslint-disable-next-line rulesdir/no-negated-variables - const shouldShowNotFoundPage = !shouldShowCategory || (isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction))); - - const navigateBack = () => { - Navigation.goBack(backTo); - }; - - /** - * @param {Object} category - * @param {String} category.searchText - */ - const updateCategory = (category) => { - const isSelectedCategory = category.searchText === transactionCategory; - const updatedCategory = isSelectedCategory ? '' : category.searchText; - - // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value - if (isEditingSplitBill) { - IOU.setDraftSplitTransaction(transaction.transactionID, {category: updatedCategory}); - navigateBack(); - return; - } - - if (isEditing) { - IOU.updateMoneyRequestCategory(transaction.transactionID, report.reportID, updatedCategory, policy, policyTags, policyCategories); - navigateBack(); - return; - } - - IOU.setMoneyRequestCategory(transactionID, updatedCategory); - navigateBack(); - }; - - return ( - - {translate('iou.categorySelection')} - - - ); -} - -IOURequestStepCategory.displayName = 'IOURequestStepCategory'; -IOURequestStepCategory.propTypes = propTypes; -IOURequestStepCategory.defaultProps = defaultProps; - -export default compose( - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - withOnyx({ - splitDraftTransaction: { - key: ({route}) => { - const transactionID = lodashGet(route, 'params.transactionID', 0); - return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; - }, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - reportActions: { - key: ({ - report, - route: { - params: {action, iouType}, - }, - }) => { - let reportID = '0'; - if (action === CONST.IOU.ACTION.EDIT) { - reportID = iouType === CONST.IOU.TYPE.SPLIT ? report.reportID : report.parentReportID; - } - return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; - }, - canEvict: false, - }, - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(IOURequestStepCategory); diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index ee14b5bcef8e..f386381ea765 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -126,9 +126,9 @@ function IOURequestStepCategory({ IOURequestStepCategory.displayName = 'IOURequestStepCategory'; /* eslint-disable rulesdir/no-negated-variables */ -const ComponentWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepCategory); +const IOURequestStepCategoryWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepCategory); /* eslint-disable rulesdir/no-negated-variables */ -const ComponentWithFullTransactionOrNotFound = withFullTransactionOrNotFound(ComponentWithWritableReportOrNotFound); +const IOURequestStepCategoryWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepCategoryWithWritableReportOrNotFound); export default withOnyx({ splitDraftTransaction: { key: ({route}) => { @@ -168,4 +168,4 @@ export default withOnyx { - if (iouType === CONST.IOU.TYPE.SPLIT) { - return translate('iou.split'); - } - if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { - return translate('iou.trackExpense'); - } - if (iouType === CONST.IOU.TYPE.SEND) { - return translate('common.send'); - } - return translate(TransactionUtils.getHeaderTitleTranslationKey(transaction)); - }, [iouType, transaction, translate]); - - const participants = useMemo( - () => - _.map(transaction.participants, (participant) => { - const participantAccountID = lodashGet(participant, 'accountID', 0); - return participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); - }), - [transaction.participants, personalDetails], - ); - const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); - const formHasBeenSubmitted = useRef(false); - - useEffect(() => { - if (!transaction || !transaction.originalCurrency) { - return; - } - // If user somehow lands on this page without the currency reset, then reset it here. - IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, transaction.originalCurrency, true); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat); - if (policyExpenseChat) { - Policy.openDraftWorkspaceRequest(policyExpenseChat.policyID); - } - }, [isOffline, participants, transaction.billable, policy, transactionID]); - - const defaultBillable = lodashGet(policy, 'defaultBillable', false); - useEffect(() => { - IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, defaultBillable); - }, [transactionID, defaultBillable]); - - useEffect(() => { - if (!transaction.category) { - return; - } - if (policyCategories && policyCategories[transaction.category] && !policyCategories[transaction.category].enabled) { - IOU.setMoneyRequestCategory(transactionID, ''); - } - }, [policyCategories, transaction.category, transactionID]); - const defaultCategory = lodashGet( - _.find(lodashGet(policy, 'customUnits', {}), (customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE), - 'defaultCategory', - '', - ); - useEffect(() => { - if (requestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || !_.isEmpty(transaction.category)) { - return; - } - IOU.setMoneyRequestCategory(transactionID, defaultCategory); - // Prevent resetting to default when unselect category - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [transactionID, requestType, defaultCategory]); - - const navigateBack = useCallback(() => { - // If there is not a report attached to the IOU with a reportID, then the participants were manually selected and the user needs taken - // back to the participants step - if (!transaction.participantsAutoAssigned) { - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); - return; - } - IOUUtils.navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID); - }, [transaction, iouType, requestType, transactionID, reportID]); - - const navigateToAddReceipt = useCallback(() => { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams())); - }, [iouType, transactionID, reportID]); - - // When the component mounts, if there is a receipt, see if the image can be read from the disk. If not, redirect the user to the starting step of the flow. - // This is because until the request is saved, the receipt file is only stored in the browsers memory as a blob:// and if the browser is refreshed, then - // the image ceases to exist. The best way for the user to recover from this is to start over from the start of the request process. - useEffect(() => { - const onSuccess = (file) => { - const receipt = file; - receipt.state = file && requestType === CONST.IOU.REQUEST_TYPE.MANUAL ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY; - setReceiptFile(receipt); - }; - - IOU.navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID, receiptType); - }, [receiptType, receiptPath, receiptFilename, requestType, iouType, transactionID, reportID]); - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - * @param {File} [receiptObj] - */ - const requestMoney = useCallback( - (selectedParticipants, trimmedComment, receiptObj, gpsPoints) => { - IOU.requestMoney( - report, - transaction.amount, - transaction.currency, - transaction.created, - transaction.merchant, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - selectedParticipants[0], - trimmedComment, - receiptObj, - transaction.category, - transaction.tag, - transactionTaxCode, - transactionTaxAmount, - transaction.billable, - policy, - policyTags, - policyCategories, - gpsPoints, - ); - }, - [report, transaction, transactionTaxCode, transactionTaxAmount, currentUserPersonalDetails.login, currentUserPersonalDetails.accountID, policy, policyTags, policyCategories], - ); - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - * @param {File} [receiptObj] - */ - const trackExpense = useCallback( - (selectedParticipants, trimmedComment, receiptObj, gpsPoints) => { - IOU.trackExpense( - report, - transaction.amount, - transaction.currency, - transaction.created, - transaction.merchant, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - selectedParticipants[0], - trimmedComment, - receiptObj, - transaction.category, - transaction.tag, - transactionTaxCode, - transactionTaxAmount, - transaction.billable, - policy, - policyTags, - policyCategories, - gpsPoints, - ); - }, - [ - report, - transaction.amount, - transaction.currency, - transaction.created, - transaction.merchant, - transaction.category, - transaction.tag, - transaction.billable, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - transactionTaxCode, - transactionTaxAmount, - policy, - policyTags, - policyCategories, - ], - ); - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - */ - const createDistanceRequest = useCallback( - (selectedParticipants, trimmedComment) => { - IOU.createDistanceRequest( - report, - selectedParticipants[0], - trimmedComment, - transaction.created, - transaction.category, - transaction.tag, - transaction.amount, - transaction.currency, - transaction.merchant, - transaction.billable, - TransactionUtils.getValidWaypoints(transaction.comment.waypoints, true), - policy, - policyTags, - policyCategories, - ); - }, - [policy, policyCategories, policyTags, report, transaction], - ); - - const createTransaction = useCallback( - (selectedParticipants) => { - const trimmedComment = lodashGet(transaction, 'comment.comment', '').trim(); - - // Don't let the form be submitted multiple times while the navigator is waiting to take the user to a different page - if (formHasBeenSubmitted.current) { - return; - } - - formHasBeenSubmitted.current = true; - - // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed - if (iouType === CONST.IOU.TYPE.SPLIT && receiptFile) { - IOU.startSplitBill({ - participants: selectedParticipants, - currentUserLogin: currentUserPersonalDetails.login, - currentUserAccountID: currentUserPersonalDetails.accountID, - comment: trimmedComment, - receiptFile, - existingSplitChatReportID: report.reportID, - billable: transaction.billable, - category: transaction.category, - tag: transaction.tag, - }); - return; - } - - // IOUs created from a group report will have a reportID param in the route. - // Since the user is already viewing the report, we don't need to navigate them to the report - if (iouType === CONST.IOU.TYPE.SPLIT && !transaction.isFromGlobalCreate) { - IOU.splitBill({ - participants: selectedParticipants, - currentUserLogin: currentUserPersonalDetails.login, - currentUserAccountID: currentUserPersonalDetails.accountID, - amount: transaction.amount, - comment: trimmedComment, - currency: transaction.currency, - merchant: transaction.merchant, - created: transaction.created, - category: transaction.category, - tag: transaction.tag, - existingSplitChatReportID: report.reportID, - billable: transaction.billable, - iouRequestType: transaction.iouRequestType, - }); - return; - } - - // If the request is created from the global create menu, we also navigate the user to the group report - if (iouType === CONST.IOU.TYPE.SPLIT) { - IOU.splitBillAndOpenReport({ - participants: selectedParticipants, - currentUserLogin: currentUserPersonalDetails.login, - currentUserAccountID: currentUserPersonalDetails.accountID, - amount: transaction.amount, - comment: trimmedComment, - currency: transaction.currency, - merchant: transaction.merchant, - created: transaction.created, - category: transaction.category, - tag: transaction.tag, - billable: transaction.billable, - iouRequestType: transaction.iouRequestType, - }); - return; - } - - if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { - if (receiptFile) { - // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. - if (transaction.amount === 0) { - getCurrentPosition( - (successData) => { - trackExpense(selectedParticipants, trimmedComment, receiptFile, { - lat: successData.coords.latitude, - long: successData.coords.longitude, - }); - }, - (errorData) => { - Log.info('[IOURequestStepConfirmation] getCurrentPosition failed', false, errorData); - // When there is an error, the money can still be requested, it just won't include the GPS coordinates - trackExpense(selectedParticipants, trimmedComment, receiptFile); - }, - { - // It's OK to get a cached location that is up to an hour old because the only accuracy needed is the country the user is in - maximumAge: 1000 * 60 * 60, - - // 15 seconds, don't wait too long because the server can always fall back to using the IP address - timeout: 15000, - }, - ); - return; - } - - // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed. - trackExpense(selectedParticipants, trimmedComment, receiptFile); - return; - } - trackExpense(selectedParticipants, trimmedComment, receiptFile); - return; - } - - if (receiptFile) { - // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. - if (transaction.amount === 0) { - getCurrentPosition( - (successData) => { - requestMoney(selectedParticipants, trimmedComment, receiptFile, { - lat: successData.coords.latitude, - long: successData.coords.longitude, - }); - }, - (errorData) => { - Log.info('[IOURequestStepConfirmation] getCurrentPosition failed', false, errorData); - // When there is an error, the money can still be requested, it just won't include the GPS coordinates - requestMoney(selectedParticipants, trimmedComment, receiptFile); - }, - { - // It's OK to get a cached location that is up to an hour old because the only accuracy needed is the country the user is in - maximumAge: 1000 * 60 * 60, - - // 15 seconds, don't wait too long because the server can always fall back to using the IP address - timeout: 15000, - }, - ); - return; - } - - // Otherwise, the money is being requested through the "Manual" flow with an attached image and the GPS coordinates are not needed. - requestMoney(selectedParticipants, trimmedComment, receiptFile); - return; - } - - if (requestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { - createDistanceRequest(selectedParticipants, trimmedComment); - return; - } - - requestMoney(selectedParticipants, trimmedComment); - }, - [ - transaction, - iouType, - receiptFile, - requestType, - requestMoney, - currentUserPersonalDetails.login, - currentUserPersonalDetails.accountID, - report.reportID, - trackExpense, - createDistanceRequest, - ], - ); - - /** - * Checks if user has a GOLD wallet then creates a paid IOU report on the fly - * - * @param {String} paymentMethodType - */ - const sendMoney = useCallback( - (paymentMethodType) => { - const currency = transaction.currency; - - const trimmedComment = transaction.comment && transaction.comment.comment ? transaction.comment.comment.trim() : ''; - - const participant = participants[0]; - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { - IOU.sendMoneyElsewhere(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); - return; - } - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { - IOU.sendMoneyWithWallet(report, transaction.amount, currency, trimmedComment, currentUserPersonalDetails.accountID, participant); - } - }, - [transaction.amount, transaction.comment, transaction.currency, participants, currentUserPersonalDetails.accountID, report], - ); - - const addNewParticipant = (option) => { - const newParticipants = _.map(transaction.participants, (participant) => { - if (participant.accountID === option.accountID) { - return {...participant, selected: !participant.selected}; - } - return participant; - }); - IOU.setMoneyRequestParticipants_temporaryForRefactor(transactionID, newParticipants); - }; - - /** - * @param {Boolean} billable - */ - const setBillable = (billable) => { - IOU.setMoneyRequestBillable_temporaryForRefactor(transactionID, billable); - }; - - // This loading indicator is shown because the transaction originalCurrency is being updated later than the component mounts. - // To prevent the component from rendering with the wrong currency, we show a loading indicator until the correct currency is set. - const isLoading = !!(transaction && transaction.originalCurrency); - - return ( - - {({safeAreaPaddingBottomStyle}) => ( - - - {isLoading && } - - - - - )} - - ); -} - -IOURequestStepConfirmation.propTypes = propTypes; -IOURequestStepConfirmation.defaultProps = defaultProps; -IOURequestStepConfirmation.displayName = 'IOURequestStepConfirmation'; - -export default compose( - withCurrentUserPersonalDetails, - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(IOURequestStepConfirmation); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 3bde56792580..90d4bc1c64be 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -533,9 +533,9 @@ function IOURequestStepConfirmation({ IOURequestStepConfirmation.displayName = 'IOURequestStepConfirmation'; /* eslint-disable rulesdir/no-negated-variables */ -const ComponentWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmation); +const IOURequestStepConfirmationWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmation); /* eslint-disable rulesdir/no-negated-variables */ -const ComponentWithFullTransactionOrNotFound = withFullTransactionOrNotFound(ComponentWithWritableReportOrNotFound); +const IOURequestStepConfirmationWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepConfirmationWithWritableReportOrNotFound); export default withOnyx({ personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -550,4 +550,4 @@ export default withOnyx `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, }, // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. -})(ComponentWithFullTransactionOrNotFound); +})(IOURequestStepConfirmationWithFullTransactionOrNotFound); From 6845b0d607f179f623bea30436f7ae15d908ea12 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 2 Apr 2024 11:10:05 +0200 Subject: [PATCH 32/78] cleanup --- src/libs/actions/IOU.ts | 10 +++++----- .../iou/request/step/IOURequestStepConfirmation.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 38eceda02352..e7f7da94799c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -134,7 +134,7 @@ type OutstandingChildRequest = { hasOutstandingChildRequest?: boolean; }; -type GpsPoint = { +type GPSPoint = { lat: number; long: number; }; @@ -2075,7 +2075,7 @@ function requestMoney( policy?: OnyxEntry, policyTagList?: OnyxEntry, policyCategories?: OnyxEntry, - gpsPoints?: GpsPoint, + gpsPoints?: GPSPoint, ) { // If the report is iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); @@ -2173,7 +2173,7 @@ function trackExpense( policy?: OnyxEntry, policyTagList?: OnyxEntry, policyCategories?: OnyxEntry, - gpsPoints?: GpsPoint, + gpsPoints?: GPSPoint, ) { const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created); const { @@ -3036,7 +3036,7 @@ function startSplitBill({ splits: JSON.stringify(splits), receipt, comment, - category: category ?? '', + category, tag, isFromGroupDM: !existingSplitChatReport, billable, @@ -5186,7 +5186,7 @@ function savePreferredPaymentMethod(policyID: string, paymentMethod: PaymentMeth Onyx.merge(`${ONYXKEYS.NVP_LAST_PAYMENT_METHOD}`, {[policyID]: paymentMethod}); } -export type {GpsPoint}; +export type {GPSPoint as GpsPoint}; export { setMoneyRequestParticipants, createDistanceRequest, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 90d4bc1c64be..a42a6d1e0be0 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -94,7 +94,7 @@ function IOURequestStepConfirmation({ () => transaction?.participants?.map((participant) => { const participantAccountID = participant.accountID ?? 0; - return participant && participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); + return participantAccountID ? OptionsListUtils.getParticipantsOption(participant, personalDetails) : OptionsListUtils.getReportOption(participant); }), [transaction?.participants, personalDetails], ); From 9c8afd31a25f060e21978372400774122bed27f8 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 2 Apr 2024 12:55:51 +0200 Subject: [PATCH 33/78] review fixes --- .../withCurrentUserPersonalDetails.tsx | 2 +- src/libs/Navigation/types.ts | 8 +- .../request/step/IOURequestStepCategory.tsx | 35 +- .../step/IOURequestStepConfirmation.tsx | 23 +- .../step/withWritableReportOrNotFound.tsx | 12 +- .../iou/steps/MoneyRequestConfirmPage.js | 473 ------------------ 6 files changed, 37 insertions(+), 516 deletions(-) delete mode 100644 src/pages/iou/steps/MoneyRequestConfirmPage.js diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index 03b9cd1acac4..8431ededcb56 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -39,7 +39,7 @@ export default function ; - iouType: string; - transactionID: string; - reportID: string; - }; [SCREENS.MONEY_REQUEST.CURRENCY]: { iouType: string; reportID: string; @@ -435,7 +429,7 @@ type MoneyRequestNavigatorParamList = { reportID: string; }; [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: { - action: keyof typeof CONST.IOU.ACTION; + action: ValueOf; iouType: ValueOf; transactionID: string; reportID: string; diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index f386381ea765..529be126ce11 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -1,4 +1,3 @@ -import type {StackScreenProps} from '@react-navigation/stack'; import lodashIsEmpty from 'lodash/isEmpty'; import React from 'react'; import type {OnyxEntry} from 'react-native-onyx'; @@ -9,7 +8,6 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -23,36 +21,36 @@ import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -type IOURequestStepCategoryStackProps = {stackProps: StackScreenProps}; - type IOURequestStepCategoryOnyxProps = { /** The draft transaction that holds data to be persisted on the current transaction */ splitDraftTransaction: OnyxEntry; + /** The policy of the report */ policy: OnyxEntry; + /** Collection of categories attached to a policy */ policyCategories: OnyxEntry; + /** Collection of tags attached to a policy */ policyTags: OnyxEntry; + /** The actions from the parent report */ reportActions: OnyxEntry; + /** Session info for the currently logged in user. */ session: OnyxEntry; }; -type IOURequestStepCategoryProps = IOURequestStepCategoryStackProps & - IOURequestStepCategoryOnyxProps & - WithWritableReportOrNotFoundProps & { +type IOURequestStepCategoryProps = IOURequestStepCategoryOnyxProps & + WithWritableReportOrNotFoundProps & { /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ transaction: OnyxEntry; }; function IOURequestStepCategory({ report, - stackProps: { - route: { - params: {transactionID, backTo, action, iouType, reportActionID}, - }, + route: { + params: {transactionID, backTo, action, iouType, reportActionID}, }, transaction, splitDraftTransaction, @@ -125,11 +123,7 @@ function IOURequestStepCategory({ IOURequestStepCategory.displayName = 'IOURequestStepCategory'; -/* eslint-disable rulesdir/no-negated-variables */ -const IOURequestStepCategoryWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepCategory); -/* eslint-disable rulesdir/no-negated-variables */ -const IOURequestStepCategoryWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepCategoryWithWritableReportOrNotFound); -export default withOnyx({ +const IOURequestStepCategoryWithOnyx = withOnyx({ splitDraftTransaction: { key: ({route}) => { const transactionID = route?.params.transactionID ?? 0; @@ -167,5 +161,10 @@ export default withOnyx; - type IOURequestStepConfirmationOnyxProps = { policy: OnyxEntry; policyCategories: OnyxEntry; @@ -47,8 +42,7 @@ type IOURequestStepConfirmationOnyxProps = { }; type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & - IOURequestStepConfirmationStackProps & - WithWritableReportOrNotFoundProps & { + WithWritableReportOrNotFoundProps & { transaction: OnyxEntry; }; @@ -533,11 +527,7 @@ function IOURequestStepConfirmation({ IOURequestStepConfirmation.displayName = 'IOURequestStepConfirmation'; -/* eslint-disable rulesdir/no-negated-variables */ -const IOURequestStepConfirmationWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmation); -/* eslint-disable rulesdir/no-negated-variables */ -const IOURequestStepConfirmationWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepConfirmationWithWritableReportOrNotFound); -export default withOnyx({ +const IOURequestStepConfirmationWithOnyx = withOnyx({ personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, @@ -550,5 +540,10 @@ export default withOnyx `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, }, - // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. -})(IOURequestStepConfirmationWithFullTransactionOrNotFound); +})(IOURequestStepConfirmation); +/* eslint-disable rulesdir/no-negated-variables */ +const IOURequestStepConfirmationWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepConfirmationWithOnyx); +/* eslint-disable rulesdir/no-negated-variables */ +// @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. +const IOURequestStepConfirmationWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepConfirmationWithFullTransactionOrNotFound); +export default IOURequestStepConfirmationWithWritableReportOrNotFound; diff --git a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx index d5d27d8268b1..d2ece8c9cbf5 100644 --- a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx +++ b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx @@ -17,11 +17,17 @@ type WithWritableReportOrNotFoundOnyxProps = { report: OnyxEntry; }; -type Route = RouteProp; +type MoneyRequestRouteName = + | typeof SCREENS.MONEY_REQUEST.STEP_WAYPOINT + | typeof SCREENS.MONEY_REQUEST.STEP_DESCRIPTION + | typeof SCREENS.MONEY_REQUEST.STEP_CATEGORY + | typeof SCREENS.MONEY_REQUEST.STEP_CONFIRMATION; -type WithWritableReportOrNotFoundProps = WithWritableReportOrNotFoundOnyxProps & {route: Route}; +type Route = RouteProp; -export default function ( +type WithWritableReportOrNotFoundProps = WithWritableReportOrNotFoundOnyxProps & {route: Route}; + +export default function , TRef>( WrappedComponent: ComponentType>, ): React.ComponentType, keyof WithWritableReportOrNotFoundOnyxProps>> { // eslint-disable-next-line rulesdir/no-negated-variables diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js deleted file mode 100644 index fac3d51a1fd6..000000000000 --- a/src/pages/iou/steps/MoneyRequestConfirmPage.js +++ /dev/null @@ -1,473 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import categoryPropTypes from '@components/categoryPropTypes'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; -import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationList'; -import {usePersonalDetails} from '@components/OnyxProvider'; -import ScreenWrapper from '@components/ScreenWrapper'; -import tagPropTypes from '@components/tagPropTypes'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; -import withLocalize from '@components/withLocalize'; -import useInitialValue from '@hooks/useInitialValue'; -import useNetwork from '@hooks/useNetwork'; -import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import compose from '@libs/compose'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; -import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; -import Navigation from '@libs/Navigation/Navigation'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as ReportUtils from '@libs/ReportUtils'; -import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes'; -import reportPropTypes from '@pages/reportPropTypes'; -import {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy'; -import * as IOU from '@userActions/IOU'; -import * as Policy from '@userActions/Policy'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; - -const propTypes = { - /** React Navigation route */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - }).isRequired, - - report: reportPropTypes, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, - - /** The policy of the current request */ - policy: policyPropTypes, - - policyTags: tagPropTypes, - - policyCategories: PropTypes.objectOf(categoryPropTypes), - - ...withCurrentUserPersonalDetailsPropTypes, -}; - -const defaultProps = { - report: {}, - policyCategories: {}, - policyTags: {}, - iou: iouDefaultProps, - policy: policyDefaultProps, - ...withCurrentUserPersonalDetailsDefaultProps, -}; - -function MoneyRequestConfirmPage(props) { - const styles = useThemeStyles(); - const {isOffline} = useNetwork(); - const {windowWidth} = useWindowDimensions(); - const prevMoneyRequestId = useRef(props.iou.id); - const iouType = useInitialValue(() => lodashGet(props.route, 'params.iouType', '')); - const reportID = useInitialValue(() => lodashGet(props.route, 'params.reportID', '')); - const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType, props.selectedTab); - const isScanRequest = MoneyRequestUtils.isScanRequest(props.selectedTab); - const [receiptFile, setReceiptFile] = useState(); - const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; - - const participants = useMemo( - () => - _.map(props.iou.participants, (participant) => { - const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false); - return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails); - }), - [props.iou.participants, personalDetails], - ); - const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(props.report)), [props.report]); - const isManualRequestDM = props.selectedTab === CONST.TAB_REQUEST.MANUAL && iouType === CONST.IOU.TYPE.REQUEST; - - useEffect(() => { - const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat); - if (policyExpenseChat) { - Policy.openDraftWorkspaceRequest(policyExpenseChat.policyID); - } - }, [isOffline, participants, props.iou.billable, props.policy]); - - const defaultBillable = lodashGet(props.policy, 'defaultBillable', false); - useEffect(() => { - IOU.setMoneyRequestBillable(defaultBillable); - }, [defaultBillable, isOffline]); - - useEffect(() => { - if (!props.iou.receiptPath || !props.iou.receiptFilename) { - return; - } - const onSuccess = (file) => { - const receipt = file; - receipt.state = file && isManualRequestDM ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY; - setReceiptFile(receipt); - }; - const onFailure = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID)); - }; - FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename, onSuccess, onFailure); - }, [props.iou.receiptPath, props.iou.receiptFilename, isManualRequestDM, iouType, reportID]); - - useEffect(() => { - // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request - if (!isDistanceRequest && prevMoneyRequestId.current !== props.iou.id) { - // The ID is cleared on completing a request. In that case, we will do nothing. - if (props.iou.id) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - return; - } - - // Reset the money request Onyx if the ID in Onyx does not match the ID from params - const moneyRequestId = `${iouType}${reportID}`; - const shouldReset = !isDistanceRequest && props.iou.id !== moneyRequestId && !_.isEmpty(reportID); - if (shouldReset) { - IOU.resetMoneyRequestInfo(moneyRequestId); - } - - if (_.isEmpty(props.iou.participants) || (props.iou.amount === 0 && !props.iou.receiptPath && !isDistanceRequest) || shouldReset || ReportUtils.isArchivedRoom(props.report)) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - - return () => { - prevMoneyRequestId.current = props.iou.id; - }; - }, [props.iou.participants, props.iou.amount, props.iou.id, props.iou.receiptPath, isDistanceRequest, props.report, iouType, reportID]); - - const navigateBack = () => { - let fallback; - if (reportID) { - fallback = ROUTES.MONEY_REQUEST.getRoute(iouType, reportID); - } else { - fallback = ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType); - } - Navigation.goBack(fallback); - }; - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - * @param {File} [receipt] - */ - const requestMoney = useCallback( - (selectedParticipants, trimmedComment, receipt) => { - IOU.requestMoney( - props.report, - props.iou.amount, - props.iou.currency, - props.iou.created, - props.iou.merchant, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - selectedParticipants[0], - trimmedComment, - receipt, - props.iou.category, - props.iou.tag, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ); - }, - [ - props.report, - props.iou.amount, - props.iou.currency, - props.iou.created, - props.iou.merchant, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.category, - props.iou.tag, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ], - ); - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - */ - const createDistanceRequest = useCallback( - (selectedParticipants, trimmedComment) => { - IOU.createDistanceRequest( - props.report, - selectedParticipants[0], - trimmedComment, - props.iou.created, - props.iou.transactionID, - props.iou.category, - props.iou.tag, - props.iou.amount, - props.iou.currency, - props.iou.merchant, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ); - }, - [ - props.report, - props.iou.created, - props.iou.transactionID, - props.iou.category, - props.iou.tag, - props.iou.amount, - props.iou.currency, - props.iou.merchant, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ], - ); - - const createTransaction = useCallback( - (selectedParticipants) => { - const trimmedComment = props.iou.comment.trim(); - - // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed - if (iouType === CONST.IOU.TYPE.SPLIT && props.iou.receiptPath) { - const existingSplitChatReportID = CONST.REGEX.NUMBER.test(reportID) ? reportID : ''; - const onSuccess = (receipt) => { - IOU.startSplitBill({ - participants: selectedParticipants, - currentUserLogin: props.currentUserPersonalDetails.login, - currentUserAccountID: props.currentUserPersonalDetails.accountID, - comment: trimmedComment, - receipt, - existingSplitChatReportID, - }); - }; - FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename, onSuccess); - return; - } - - // IOUs created from a group report will have a reportID param in the route. - // Since the user is already viewing the report, we don't need to navigate them to the report - if (iouType === CONST.IOU.TYPE.SPLIT && CONST.REGEX.NUMBER.test(reportID)) { - IOU.splitBill({ - participants: selectedParticipants, - currentUserLogin: props.currentUserPersonalDetails.login, - currentUserAccountID: props.currentUserPersonalDetails.accountID, - amount: props.iou.amount, - comment: trimmedComment, - currency: props.iou.currency, - merchant: props.iou.merchant, - category: props.iou.category, - tag: props.iou.tag, - existingSplitChatReportID: reportID, - }); - return; - } - - // If the request is created from the global create menu, we also navigate the user to the group report - if (iouType === CONST.IOU.TYPE.SPLIT) { - IOU.splitBillAndOpenReport({ - participants: selectedParticipants, - currentUserLogin: props.currentUserPersonalDetails.login, - currentUserAccountID: props.currentUserPersonalDetails.accountID, - amount: props.iou.amount, - comment: trimmedComment, - currency: props.iou.currency, - merchant: props.iou.merchant, - category: props.iou.category, - tag: props.iou.tag, - }); - return; - } - - if (receiptFile) { - requestMoney(selectedParticipants, trimmedComment, receiptFile); - return; - } - - if (isDistanceRequest) { - createDistanceRequest(selectedParticipants, trimmedComment); - return; - } - - requestMoney(selectedParticipants, trimmedComment); - }, - [ - props.iou.amount, - props.iou.comment, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.currency, - props.iou.category, - props.iou.tag, - props.iou.receiptPath, - props.iou.receiptFilename, - isDistanceRequest, - requestMoney, - createDistanceRequest, - receiptFile, - iouType, - reportID, - props.iou.merchant, - ], - ); - - /** - * Checks if user has a GOLD wallet then creates a paid IOU report on the fly - * - * @param {String} paymentMethodType - */ - const sendMoney = useCallback( - (paymentMethodType) => { - const currency = props.iou.currency; - const trimmedComment = props.iou.comment.trim(); - const participant = participants[0]; - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { - IOU.sendMoneyElsewhere(props.report, props.iou.amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); - return; - } - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { - IOU.sendMoneyWithWallet(props.report, props.iou.amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); - } - }, - [props.iou.amount, props.iou.comment, participants, props.iou.currency, props.currentUserPersonalDetails.accountID, props.report], - ); - - const headerTitle = () => { - if (isDistanceRequest) { - return props.translate('common.distance'); - } - - if (iouType === CONST.IOU.TYPE.SPLIT) { - return props.translate('iou.split'); - } - - if (iouType === CONST.IOU.TYPE.SEND) { - return props.translate('common.send'); - } - - if (isScanRequest) { - return props.translate('tabSelector.scan'); - } - - return props.translate('tabSelector.manual'); - }; - - return ( - - {({safeAreaPaddingBottomStyle}) => ( - - Navigation.navigate(ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, reportID)), - }, - ]} - /> - { - const newParticipants = _.map(props.iou.participants, (participant) => { - if (participant.accountID === option.accountID) { - return {...participant, selected: !participant.selected}; - } - return participant; - }); - IOU.setMoneyRequestParticipants(newParticipants); - }} - receiptPath={props.iou.receiptPath} - receiptFilename={props.iou.receiptFilename} - iouType={iouType} - reportID={reportID} - isPolicyExpenseChat={isPolicyExpenseChat} - // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. - // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, - // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill - // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from - // the floating-action-button (since it is something that exists outside the context of a report). - canModifyParticipants={!_.isEmpty(reportID)} - policyID={props.report.policyID} - bankAccountRoute={ReportUtils.getBankAccountRoute(props.report)} - iouMerchant={props.iou.merchant} - iouCreated={props.iou.created} - isScanRequest={isScanRequest} - isDistanceRequest={isDistanceRequest} - shouldShowSmartScanFields={_.isEmpty(props.iou.receiptPath)} - /> - - )} - - ); -} - -MoneyRequestConfirmPage.displayName = 'MoneyRequestConfirmPage'; -MoneyRequestConfirmPage.propTypes = propTypes; -MoneyRequestConfirmPage.defaultProps = defaultProps; - -export default compose( - withCurrentUserPersonalDetails, - withLocalize, - withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - report: { - key: ({route, iou}) => { - const reportID = IOU.getIOUReportID(iou, route); - - return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - }, - }, - selectedTab: { - key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`, - }, - }), - withOnyx({ - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(MoneyRequestConfirmPage); From 236eec33f6e6c3f822a8906f5f54d5e716d660de Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 2 Apr 2024 13:17:23 +0200 Subject: [PATCH 34/78] lint fix --- src/pages/iou/request/step/withWritableReportOrNotFound.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx index d2ece8c9cbf5..f72810258adb 100644 --- a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx +++ b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx @@ -53,7 +53,10 @@ export default function , WithWritableReportOrNotFoundOnyxProps>({ report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params?.reportID ?? '0'}`, + key: ({route}) => { + const reportId = 'reportID' in route.params ? route.params.reportID : '0'; + return `${ONYXKEYS.COLLECTION.REPORT}${reportId}`; + }, }, })(forwardRef(WithWritableReportOrNotFound)); } From 5ee42273ea1fe5f34c9443cea999437df7a86543 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 2 Apr 2024 14:45:51 +0300 Subject: [PATCH 35/78] updates based on new stack implementation --- .../WorkspaceSettingsModalStackNavigator.tsx | 5 +++++ .../Navigation/AppNavigator/ModalStackNavigators/index.tsx | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx index 14153809bc86..08b26f80eefe 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx @@ -75,6 +75,11 @@ function WorkspaceSettingsModalStackNavigator() { name={SCREENS.WORKSPACE.DISTANCE_RATES} getComponent={() => require('@pages/workspace/distanceRates/PolicyDistanceRatesPage').default as React.ComponentType} /> + require('@pages/workspace/accounting/WorkspaceAccountingPage').default as React.ComponentType} + /> ); } diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 55c58290b1cd..e31a78d96290 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -258,6 +258,12 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/ExitSurvey/ExitSurveyReasonPage').default as React.ComponentType, [SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyResponsePage').default as React.ComponentType, [SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyConfirmPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksImportPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksCustomersPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksTaxesPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksLocationsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksClassesPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage').default as React.ComponentType, From 9717dfb0fc68b3a436fd7c6fcc1769529105cb4c Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 2 Apr 2024 14:47:04 +0300 Subject: [PATCH 36/78] prettier --- .../WorkspaceSettingsModalStackNavigator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx index 08b26f80eefe..bafce9f42128 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx @@ -75,7 +75,7 @@ function WorkspaceSettingsModalStackNavigator() { name={SCREENS.WORKSPACE.DISTANCE_RATES} getComponent={() => require('@pages/workspace/distanceRates/PolicyDistanceRatesPage').default as React.ComponentType} /> - require('@pages/workspace/accounting/WorkspaceAccountingPage').default as React.ComponentType} From 058dafa95ed38e9f06c5070fa2a9d139cfc7ec67 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 2 Apr 2024 16:33:17 +0200 Subject: [PATCH 37/78] fix stepscreenwrapper --- src/pages/iou/request/step/StepScreenWrapper.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/request/step/StepScreenWrapper.tsx b/src/pages/iou/request/step/StepScreenWrapper.tsx index 902122fa0dd4..3f4d5017d71e 100644 --- a/src/pages/iou/request/step/StepScreenWrapper.tsx +++ b/src/pages/iou/request/step/StepScreenWrapper.tsx @@ -1,3 +1,4 @@ +import React, {forwardRef} from 'react'; import type {PropsWithChildren} from 'react'; import {View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; @@ -27,7 +28,7 @@ type StepScreenWrapperProps = { testID: string; /** Whether or not to include safe area padding */ - includeSafeAreaPaddingBottom: boolean; + includeSafeAreaPaddingBottom?: boolean; }; function StepScreenWrapper({ @@ -62,7 +63,7 @@ function StepScreenWrapper({ /> { // If props.children is a function, call it to provide the insets to the children - callOrReturn(children, {insets, safeAreaPaddingBottomStyle, didScreenTransitionEnd}) + callOrReturn(children, [insets, safeAreaPaddingBottomStyle, didScreenTransitionEnd]) } @@ -71,6 +72,4 @@ function StepScreenWrapper({ ); } -StepScreenWrapper.displayName = 'StepScreenWrapper'; - -export default StepScreenWrapper; +export default forwardRef(StepScreenWrapper); From 091da01454c155e82955be982a05b5054dab5774 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 2 Apr 2024 17:03:13 +0200 Subject: [PATCH 38/78] fix step category --- src/pages/iou/request/step/IOURequestStepCategory.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 529be126ce11..272db69e7d17 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -67,7 +67,9 @@ function IOURequestStepCategory({ const transactionCategory = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction)?.category; const reportAction = reportActions?.[report?.parentReportActionID ?? reportActionID] ?? null; - const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (transactionCategory ?? OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); + + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (transactionCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); // eslint-disable-next-line rulesdir/no-negated-variables From 931ea4519b351c596e183cb27d7830e884c43ad1 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 2 Apr 2024 23:14:36 +0100 Subject: [PATCH 39/78] Update thread headers and ancestry to deep link back to the original comment using comment linking --- src/components/AvatarWithDisplayName.tsx | 1 + src/components/ParentNavigationSubtitle.tsx | 7 +++++-- src/pages/ReportDetailsPage.tsx | 1 + src/pages/home/HeaderView.tsx | 1 + src/pages/home/report/ReportActionItemParentAction.tsx | 2 +- src/pages/home/report/ThreadDivider.tsx | 2 +- 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 396c10151fbf..f6afb4dae2d6 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -141,6 +141,7 @@ function AvatarWithDisplayName({ )} diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx index 3109453ca6b0..d36a2e93f5b3 100644 --- a/src/components/ParentNavigationSubtitle.tsx +++ b/src/components/ParentNavigationSubtitle.tsx @@ -15,11 +15,14 @@ type ParentNavigationSubtitleProps = { /** parent Report ID */ parentReportID?: string; + /** parent Report Action ID */ + parentReportActionID?: string; + /** PressableWithoutFeedack additional styles */ pressableStyles?: StyleProp; }; -function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportID = '', pressableStyles}: ParentNavigationSubtitleProps) { +function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportActionID, parentReportID = '', pressableStyles}: ParentNavigationSubtitleProps) { const styles = useThemeStyles(); const {workspaceName, reportName} = parentNavigationSubtitleData; @@ -28,7 +31,7 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportID return ( { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(parentReportID)); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID)); }} accessibilityLabel={translate('threads.parentNavigationSummary', {reportName, workspaceName})} role={CONST.ROLE.LINK} diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 9093bf32b9dd..ccfe329419e3 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -253,6 +253,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD )} diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 515a63aa5265..c42984be2959 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -272,6 +272,7 @@ function HeaderView({report, personalDetails, parentReport, parentReportAction, )} diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx index 3d98973c86c4..bf34a833b081 100644 --- a/src/pages/home/report/ReportActionItemParentAction.tsx +++ b/src/pages/home/report/ReportActionItemParentAction.tsx @@ -103,7 +103,7 @@ function ReportActionItemParentAction({ > Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', ancestor.reportAction.reportActionID))} parentReportAction={parentReportAction} report={ancestor.report} reportActions={reportActions} diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx index 083129e15e6d..f2f929091f93 100644 --- a/src/pages/home/report/ThreadDivider.tsx +++ b/src/pages/home/report/ThreadDivider.tsx @@ -26,7 +26,7 @@ function ThreadDivider({ancestor}: ThreadDividerProps) { return ( Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor?.report?.parentReportID ?? ''))} + onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor?.report?.parentReportID ?? '', ancestor.reportAction.reportActionID))} accessibilityLabel={translate('threads.thread')} role={CONST.ROLE.BUTTON} style={[styles.flexRow, styles.alignItemsCenter, styles.gap1]} From 5550a8171b2da7a238b00f9ba25cb37dabca6a93 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 3 Apr 2024 13:14:39 +0200 Subject: [PATCH 40/78] fix request money flow --- src/libs/API/parameters/RequestMoneyParams.ts | 2 +- src/libs/TransactionUtils.ts | 20 ++++++++++--------- src/libs/actions/IOU.ts | 2 +- .../step/IOURequestStepConfirmation.tsx | 3 ++- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/libs/API/parameters/RequestMoneyParams.ts b/src/libs/API/parameters/RequestMoneyParams.ts index b55f9fd7a2a9..ce8fb99c3f25 100644 --- a/src/libs/API/parameters/RequestMoneyParams.ts +++ b/src/libs/API/parameters/RequestMoneyParams.ts @@ -17,7 +17,7 @@ type RequestMoneyParams = { createdChatReportActionID: string; createdIOUReportActionID: string; reportPreviewReportActionID: string; - receipt: Receipt; + receipt?: Receipt; receiptState?: ValueOf; category?: string; tag?: string; diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 9b4617b3754f..6f07fb9fd618 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -45,7 +45,7 @@ function isDistanceRequest(transaction: OnyxEntry): boolean { return type === CONST.TRANSACTION.TYPE.CUSTOM_UNIT && customUnitName === CONST.CUSTOM_UNITS.NAME_DISTANCE; } -function isScanRequest(transaction: Transaction): boolean { +function isScanRequest(transaction: OnyxEntry): boolean { // This is used during the request creation flow before the transaction has been saved to the server if (lodashHas(transaction, 'iouRequestType')) { return transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.SCAN; @@ -55,13 +55,11 @@ function isScanRequest(transaction: Transaction): boolean { } function getRequestType(transaction: OnyxEntry): ValueOf { - if (transaction) { - if (isDistanceRequest(transaction)) { - return CONST.IOU.REQUEST_TYPE.DISTANCE; - } - if (isScanRequest(transaction)) { - return CONST.IOU.REQUEST_TYPE.SCAN; - } + if (isDistanceRequest(transaction)) { + return CONST.IOU.REQUEST_TYPE.DISTANCE; + } + if (isScanRequest(transaction)) { + return CONST.IOU.REQUEST_TYPE.SCAN; } return CONST.IOU.REQUEST_TYPE.MANUAL; @@ -508,7 +506,11 @@ function getWaypointIndex(key: string): number { /** * Filters the waypoints which are valid and returns those */ -function getValidWaypoints(waypoints: WaypointCollection | undefined = {}, reArrangeIndexes = false): WaypointCollection { +function getValidWaypoints(waypoints: WaypointCollection | undefined, reArrangeIndexes = false): WaypointCollection { + if (!waypoints) { + return {}; + } + const sortedIndexes = Object.keys(waypoints) .map(getWaypointIndex) .sort((a, b) => a - b); diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e7b380598da4..faab87ed628e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2078,7 +2078,7 @@ function requestMoney( payeeAccountID: number, participant: Participant, comment: string, - receipt: Receipt, + receipt: Receipt | undefined, category?: string, tag?: string, taxCode = '', diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index d60bae644024..ba92fdf0ae00 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -167,9 +167,10 @@ function IOURequestStepConfirmation({ const requestMoney = useCallback( (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { - if (!receiptObj || !report || !transaction) { + if (!report || !transaction) { return; } + IOU.requestMoney( report, transaction.amount, From 6694dc28e6f1ff1c363d58d07c063fce986aa4a0 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Wed, 3 Apr 2024 15:09:05 +0300 Subject: [PATCH 41/78] Export date page - initial --- src/libs/Navigation/types.ts | 6 -- src/libs/WorkspacesSettingsUtils.ts | 5 ++ .../qbo/QuickbooksChartOfAccountsPage.tsx | 53 +++++++++----- .../accounting/qbo/QuickbooksClassesPage.tsx | 68 ++++++++++------- .../qbo/QuickbooksCustomersPage.tsx | 67 ++++++++++------- .../accounting/qbo/QuickbooksImportPage.tsx | 50 ++++++++----- .../qbo/QuickbooksLocationsPage.tsx | 73 +++++++++++-------- .../accounting/qbo/QuickbooksTaxesPage.tsx | 49 ++++++++----- 8 files changed, 230 insertions(+), 141 deletions(-) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4c92ca58459e..3a1f2319e261 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -648,12 +648,6 @@ type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.ACCOUNTING]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: { - policyID: string; - }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: { - policyID: string; - }; }; type FullScreenNavigatorParamList = { diff --git a/src/libs/WorkspacesSettingsUtils.ts b/src/libs/WorkspacesSettingsUtils.ts index 30820fc0c48b..addc5ac8261b 100644 --- a/src/libs/WorkspacesSettingsUtils.ts +++ b/src/libs/WorkspacesSettingsUtils.ts @@ -287,6 +287,10 @@ function getOwnershipChecksDisplayText( return {title, text, buttonText}; } +function hasAccessToAccountingFeatures(policy: Policy | null, canUseAccountingIntegrations?: boolean) { + return policy?.role === CONST.POLICY.ROLE.ADMIN && policy?.areConnectionsEnabled && canUseAccountingIntegrations; +} + export { getBrickRoadForPolicy, getWorkspacesBrickRoads, @@ -297,5 +301,6 @@ export { getChatTabBrickRoad, getUnitTranslationKey, getOwnershipChecksDisplayText, + hasAccessToAccountingFeatures, }; export type {BrickRoad}; diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index 028c1d5922b8..61916543d1e0 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -7,17 +8,23 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const {canUseAccountingIntegrations} = usePermissions(); const policyID = policy?.id ?? ''; const {enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; + const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - - {translate('workspace.qbo.accountsDescription')} - + + + + {translate('workspace.qbo.accountsDescription')} + + + {translate('workspace.qbo.accountsSwitchTitle')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'enableNewCategories', !enableNewCategories)} + /> + + + - {translate('workspace.qbo.accountsSwitchTitle')} + {translate('workspace.qbo.accountsSwitchDescription')} - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'enableNewCategories', !enableNewCategories)} - /> - - - - - {translate('workspace.qbo.accountsSwitchDescription')} - - + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index b22e98252eb7..1d61ec85052f 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -8,11 +9,15 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksClassesPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -21,40 +26,51 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { const {syncClasses, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncClasses && syncClasses !== 'NONE'); const isReportFieldsSelected = syncClasses === 'REPORT_FIELD'; + const {canUseAccountingIntegrations} = usePermissions(); + const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); + return ( - - - {translate('workspace.qbo.classesDescription')} - - - {translate('workspace.qbo.import')} + + + + {translate('workspace.qbo.classesDescription')} + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncClasses', isSwitchOn ? 'NONE' : 'TAG')} + /> + + - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncClasses', isSwitchOn ? 'NONE' : 'TAG')} + {isSwitchOn && ( + + - - - - {isSwitchOn && ( - - - - )} - + + )} + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index 078ea466b929..f42375f957a1 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -8,11 +9,15 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksCustomersPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -21,40 +26,50 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { const {syncCustomers, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncCustomers && syncCustomers !== 'NONE'); const isReportFieldsSelected = syncCustomers === 'REPORT_FIELD'; + const {canUseAccountingIntegrations} = usePermissions(); + const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - - {translate('workspace.qbo.customersDescription')} - - - {translate('workspace.qbo.import')} + + + + {translate('workspace.qbo.customersDescription')} + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncCustomers', isSwitchOn ? 'NONE' : 'TAG')} + /> + + - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncCustomers', isSwitchOn ? 'NONE' : 'TAG')} + {isSwitchOn && ( + + - - - - {isSwitchOn && ( - - - - )} - + + )} + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index da7229ded9ac..f0897d6d2cfe 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -6,16 +7,20 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const {canUseAccountingIntegrations} = usePermissions(); const quickbooksOnlineConfigTitles = { DEFAULT: translate('workspace.qbo.imported'), true: translate('workspace.qbo.imported'), @@ -24,6 +29,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { TAG: translate('workspace.qbo.importedAsTags'), REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), }; + const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); const policyID = policy?.id ?? ''; const {syncClasses, syncCustomers, syncLocations, syncTaxes, enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; @@ -71,24 +77,32 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { shouldEnableMaxHeight testID={QuickbooksImportPage.displayName} > - - - {translate('workspace.qbo.importDescription')} - {sections.map((section) => ( - - - - ))} - + + + + {translate('workspace.qbo.importDescription')} + {sections.map((section) => ( + + + + ))} + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index 9fa36c615208..767aad6f7df3 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -8,11 +9,15 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksLocationsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -21,43 +26,53 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { const {syncLocations, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncLocations && syncLocations !== 'NONE'); const isReportFieldsSelected = syncLocations === 'REPORT_FIELD'; + const {canUseAccountingIntegrations} = usePermissions(); + const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - - {translate('workspace.qbo.locationsDescription')} - - - {translate('workspace.qbo.import')} + + + + {translate('workspace.qbo.locationsDescription')} + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncLocations', isSwitchOn ? 'NONE' : 'TAG')} + /> + + - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncLocations', isSwitchOn ? 'NONE' : 'TAG')} + {isSwitchOn && ( + + - - - - {isSwitchOn && ( - - - - )} - - {translate('workspace.qbo.locationsAdditionalDescription')} - - + + )} + + {translate('workspace.qbo.locationsAdditionalDescription')} + + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index 8cb4a532c17f..cde5d179dcbb 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -7,11 +8,15 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; +import Navigation from '@navigation/Navigation'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksTaxesPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -19,30 +24,40 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { const policyID = policy?.id ?? ''; const {syncTaxes, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncTaxes && syncTaxes !== 'NONE'); + const {canUseAccountingIntegrations} = usePermissions(); + const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - - {translate('workspace.qbo.taxesDescription')} - - - {translate('workspace.qbo.import')} - - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncTaxes', isSwitchOn ? 'NONE' : 'TAG')} - /> + + + + {translate('workspace.qbo.taxesDescription')} + + + {translate('workspace.qbo.import')} - - - + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncTaxes', isSwitchOn ? 'NONE' : 'TAG')} + /> + + + + + ); } From 9d56c094774075b7bc944d79a9f718f5a15f8750 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:47:18 +0100 Subject: [PATCH 42/78] Fix: when linking the last message, New sent message is not displayed until refresh, the cause of the bug: when we already have messages after the linked message, loadNewerChats and handleReportActionPagination are called and isFirstLinkedActionRender.current is set to false, but when the linked message is the last message in the report handleReportActionPagination is not called (based on hasNewestReportAction) and isFirstLinkedActionRender.current remains true. --- src/pages/home/report/ReportActionsView.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 1b6a9614a466..d9b1dc43c940 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -382,13 +382,17 @@ function ReportActionsView({ // Determines if loading older reports is necessary when the content is smaller than the list // and there are fewer than 23 items, indicating we've reached the oldest message. const isLoadingOlderReportsFirstNeeded = checkIfContentSmallerThanList() && reportActions.length > 23; - + if ( (reportActionID && indexOfLinkedAction > -1 && !hasNewestReportAction && !isLoadingOlderReportsFirstNeeded) || (!reportActionID && !hasNewestReportAction && !isLoadingOlderReportsFirstNeeded) ) { handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID}); } + if (reportActionID && indexOfLinkedAction > -1 && hasNewestReportAction && isFirstLinkedActionRender.current) { + isFirstLinkedActionRender.current = false; + setCurrentReportActionID(newestReportAction?.reportActionID); + } }, [ isLoadingInitialReportActions, isLoadingOlderReportActions, From 7d23a770a2273e8431c854eefe631063a2a4155f Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Wed, 3 Apr 2024 18:02:40 +0200 Subject: [PATCH 43/78] fix forwardref --- src/pages/iou/request/step/StepScreenWrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/StepScreenWrapper.tsx b/src/pages/iou/request/step/StepScreenWrapper.tsx index 3f4d5017d71e..c7ed6862ee11 100644 --- a/src/pages/iou/request/step/StepScreenWrapper.tsx +++ b/src/pages/iou/request/step/StepScreenWrapper.tsx @@ -63,7 +63,7 @@ function StepScreenWrapper({ /> { // If props.children is a function, call it to provide the insets to the children - callOrReturn(children, [insets, safeAreaPaddingBottomStyle, didScreenTransitionEnd]) + callOrReturn(children, {insets, safeAreaPaddingBottomStyle, didScreenTransitionEnd}) } From 35e9511c56b5858e43ff8082563cbd50ed4ad31c Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:51:59 +0100 Subject: [PATCH 44/78] Fix: Not here page shows up when opening room link under header subtitle in a deleted report with messages --- src/pages/home/ReportScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 152b02366227..12d2af21e7af 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -580,7 +580,7 @@ function ReportScreen({ return false; } const action = sortedAllReportActions.find((item) => item.reportActionID === reportActionIDFromRoute); - return action && ReportActionsUtils.isDeletedAction(action); + return action && !ReportActionsUtils.shouldReportActionBeVisible(action, action.reportActionID); }, [reportActionIDFromRoute, sortedAllReportActions]); if (isLinkedReportActionDeleted ?? (!shouldShowSkeleton && reportActionIDFromRoute && reportActions?.length === 0 && !isLinkingToMessage)) { From 5f0581d85df2e2db8ea98e4991254b3bfb2540b0 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 3 Apr 2024 19:16:26 +0100 Subject: [PATCH 45/78] Fix: Not here page shows up when opening room link under header subtitle in a deleted report with no messages --- src/components/ParentNavigationSubtitle.tsx | 5 ++++- src/pages/home/report/ReportActionItemParentAction.tsx | 6 +++++- src/pages/home/report/ReportActionsView.tsx | 2 +- src/pages/home/report/ThreadDivider.tsx | 6 +++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx index d36a2e93f5b3..a72de3d4eafb 100644 --- a/src/components/ParentNavigationSubtitle.tsx +++ b/src/components/ParentNavigationSubtitle.tsx @@ -3,6 +3,7 @@ import type {StyleProp, ViewStyle} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import CONST from '@src/CONST'; import type {ParentNavigationSummaryParams} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; @@ -31,7 +32,9 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct return ( { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID)); + const parentAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? ''); + const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? ''); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, isVisibleAction ? parentReportActionID : undefined)); }} accessibilityLabel={translate('threads.parentNavigationSummary', {reportName, workspaceName})} role={CONST.ROLE.LINK} diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx index bf34a833b081..0394a290b9af 100644 --- a/src/pages/home/report/ReportActionItemParentAction.tsx +++ b/src/pages/home/report/ReportActionItemParentAction.tsx @@ -7,6 +7,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import onyxSubscribe from '@libs/onyxSubscribe'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -103,7 +104,10 @@ function ReportActionItemParentAction({ > Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', ancestor.reportAction.reportActionID))} + onPress={() => { + const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(ancestor.reportAction, ancestor.reportAction.reportActionID ?? ''); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', isVisibleAction ? ancestor.reportAction.reportActionID : undefined)); + }} parentReportAction={parentReportAction} report={ancestor.report} reportActions={reportActions} diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index d9b1dc43c940..ce5e693c8b48 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -382,7 +382,7 @@ function ReportActionsView({ // Determines if loading older reports is necessary when the content is smaller than the list // and there are fewer than 23 items, indicating we've reached the oldest message. const isLoadingOlderReportsFirstNeeded = checkIfContentSmallerThanList() && reportActions.length > 23; - + if ( (reportActionID && indexOfLinkedAction > -1 && !hasNewestReportAction && !isLoadingOlderReportsFirstNeeded) || (!reportActionID && !hasNewestReportAction && !isLoadingOlderReportsFirstNeeded) diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx index f2f929091f93..e1ccca8725cf 100644 --- a/src/pages/home/report/ThreadDivider.tsx +++ b/src/pages/home/report/ThreadDivider.tsx @@ -8,6 +8,7 @@ import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import type {Ancestor} from '@libs/ReportUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -26,7 +27,10 @@ function ThreadDivider({ancestor}: ThreadDividerProps) { return ( Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor?.report?.parentReportID ?? '', ancestor.reportAction.reportActionID))} + onPress={() => { + const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(ancestor.reportAction, ancestor.reportAction.reportActionID ?? ''); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', isVisibleAction ? ancestor.reportAction.reportActionID : undefined)); + }} accessibilityLabel={translate('threads.thread')} role={CONST.ROLE.BUTTON} style={[styles.flexRow, styles.alignItemsCenter, styles.gap1]} From d8e225e824c14e552fccfccdc37f911865a5dcb7 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 4 Apr 2024 16:13:22 +0300 Subject: [PATCH 46/78] add wrappers for not showing page --- src/libs/WorkspacesSettingsUtils.ts | 5 - .../accounting/WorkspaceAccountingPage.tsx | 2 +- .../qbo/QuickbooksChartOfAccountsPage.tsx | 73 +++++++------- .../accounting/qbo/QuickbooksClassesPage.tsx | 87 ++++++++--------- .../qbo/QuickbooksCustomersPage.tsx | 87 ++++++++--------- .../accounting/qbo/QuickbooksImportPage.tsx | 69 +++++++------- .../qbo/QuickbooksLocationsPage.tsx | 94 +++++++++---------- .../accounting/qbo/QuickbooksTaxesPage.tsx | 69 +++++++------- 8 files changed, 226 insertions(+), 260 deletions(-) diff --git a/src/libs/WorkspacesSettingsUtils.ts b/src/libs/WorkspacesSettingsUtils.ts index addc5ac8261b..30820fc0c48b 100644 --- a/src/libs/WorkspacesSettingsUtils.ts +++ b/src/libs/WorkspacesSettingsUtils.ts @@ -287,10 +287,6 @@ function getOwnershipChecksDisplayText( return {title, text, buttonText}; } -function hasAccessToAccountingFeatures(policy: Policy | null, canUseAccountingIntegrations?: boolean) { - return policy?.role === CONST.POLICY.ROLE.ADMIN && policy?.areConnectionsEnabled && canUseAccountingIntegrations; -} - export { getBrickRoadForPolicy, getWorkspacesBrickRoads, @@ -301,6 +297,5 @@ export { getChatTabBrickRoad, getUnitTranslationKey, getOwnershipChecksDisplayText, - hasAccessToAccountingFeatures, }; export type {BrickRoad}; diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx index 7c2245514839..f96ee9608145 100644 --- a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -11,7 +11,7 @@ function WorkspaceAccountingPage() { shouldEnableMaxHeight testID={WorkspaceAccountingPage.displayName} > - + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index 61916543d1e0..d3668b875c8c 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {View} from 'react-native'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -8,60 +7,56 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; -import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import CONST from '@src/CONST'; function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {canUseAccountingIntegrations} = usePermissions(); const policyID = policy?.id ?? ''; const {enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - + - - - {translate('workspace.qbo.accountsDescription')} - + + + + {translate('workspace.qbo.accountsDescription')} + + + {translate('workspace.qbo.accountsSwitchTitle')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'enableNewCategories', !enableNewCategories)} + /> + + + - {translate('workspace.qbo.accountsSwitchTitle')} + {translate('workspace.qbo.accountsSwitchDescription')} - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'enableNewCategories', !enableNewCategories)} - /> - - - - - {translate('workspace.qbo.accountsSwitchDescription')} - - - - + + + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index 1d61ec85052f..82c9e229cb6c 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {View} from 'react-native'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -9,15 +8,14 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; -import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import CONST from '@src/CONST'; function QuickbooksClassesPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -26,52 +24,49 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { const {syncClasses, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncClasses && syncClasses !== 'NONE'); const isReportFieldsSelected = syncClasses === 'REPORT_FIELD'; - const {canUseAccountingIntegrations} = usePermissions(); - const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - + - - - {translate('workspace.qbo.classesDescription')} - - - {translate('workspace.qbo.import')} + + + + {translate('workspace.qbo.classesDescription')} + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncClasses', isSwitchOn ? 'NONE' : 'TAG')} + /> + + - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncClasses', isSwitchOn ? 'NONE' : 'TAG')} + {isSwitchOn && ( + + - - - - {isSwitchOn && ( - - - - )} - - - + + )} + + + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index f42375f957a1..8ad65c445ba4 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {View} from 'react-native'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -9,15 +8,14 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; -import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import CONST from '@src/CONST'; function QuickbooksCustomersPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -26,51 +24,48 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { const {syncCustomers, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncCustomers && syncCustomers !== 'NONE'); const isReportFieldsSelected = syncCustomers === 'REPORT_FIELD'; - const {canUseAccountingIntegrations} = usePermissions(); - const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - + - - - {translate('workspace.qbo.customersDescription')} - - - {translate('workspace.qbo.import')} + + + + {translate('workspace.qbo.customersDescription')} + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncCustomers', isSwitchOn ? 'NONE' : 'TAG')} + /> + + - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncCustomers', isSwitchOn ? 'NONE' : 'TAG')} + {isSwitchOn && ( + + - - - - {isSwitchOn && ( - - - - )} - - - + + )} + + + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index f0897d6d2cfe..2a212232e5a9 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -7,20 +6,18 @@ import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; function QuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {canUseAccountingIntegrations} = usePermissions(); const quickbooksOnlineConfigTitles = { DEFAULT: translate('workspace.qbo.imported'), true: translate('workspace.qbo.imported'), @@ -29,7 +26,6 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { TAG: translate('workspace.qbo.importedAsTags'), REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), }; - const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); const policyID = policy?.id ?? ''; const {syncClasses, syncCustomers, syncLocations, syncTaxes, enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; @@ -72,38 +68,37 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { ]; return ( - - + - - - {translate('workspace.qbo.importDescription')} - {sections.map((section) => ( - - - - ))} - - - + + + + {translate('workspace.qbo.importDescription')} + {sections.map((section) => ( + + + + ))} + + + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index 767aad6f7df3..b88d8bbdc800 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {View} from 'react-native'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -9,15 +8,14 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; -import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import CONST from '@src/CONST'; function QuickbooksLocationsPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -26,54 +24,52 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { const {syncLocations, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncLocations && syncLocations !== 'NONE'); const isReportFieldsSelected = syncLocations === 'REPORT_FIELD'; - const {canUseAccountingIntegrations} = usePermissions(); - const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); + return ( - - + - - - {translate('workspace.qbo.locationsDescription')} - - - {translate('workspace.qbo.import')} + + + + {translate('workspace.qbo.locationsDescription')} + + + {translate('workspace.qbo.import')} + + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncLocations', isSwitchOn ? 'NONE' : 'TAG')} + /> + + - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncLocations', isSwitchOn ? 'NONE' : 'TAG')} + {isSwitchOn && ( + + - - - - {isSwitchOn && ( - - - - )} - - {translate('workspace.qbo.locationsAdditionalDescription')} - - - - + + )} + + {translate('workspace.qbo.locationsAdditionalDescription')} + + + + + ); } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index cde5d179dcbb..0ff5bc892b16 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -1,6 +1,5 @@ import React from 'react'; import {View} from 'react-native'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -8,15 +7,14 @@ import ScrollView from '@components/ScrollView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {hasAccessToAccountingFeatures} from '@libs/WorkspacesSettingsUtils'; -import Navigation from '@navigation/Navigation'; +import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; +import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import CONST from '@src/CONST'; function QuickbooksTaxesPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -24,41 +22,38 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { const policyID = policy?.id ?? ''; const {syncTaxes, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; const isSwitchOn = Boolean(syncTaxes && syncTaxes !== 'NONE'); - const {canUseAccountingIntegrations} = usePermissions(); - const hasAccess = hasAccessToAccountingFeatures(policy, canUseAccountingIntegrations); return ( - - + - - - {translate('workspace.qbo.taxesDescription')} - - - {translate('workspace.qbo.import')} - - - - Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncTaxes', isSwitchOn ? 'NONE' : 'TAG')} - /> + + + + {translate('workspace.qbo.taxesDescription')} + + + {translate('workspace.qbo.import')} - - - - - + + + Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncTaxes', isSwitchOn ? 'NONE' : 'TAG')} + /> + + + + + + + ); } From 2d373156600a6206f929b76a3b26e04960fe47ca Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 4 Apr 2024 16:33:45 +0300 Subject: [PATCH 47/78] resolve c+ comments --- src/CONST.ts | 9 +++++++++ src/ROUTES.ts | 12 +++++------ src/SCREENS.ts | 12 +++++------ .../ModalStackNavigators/index.tsx | 12 +++++------ .../FULL_SCREEN_TO_RHP_MAPPING.ts | 12 +++++------ src/libs/Navigation/linkingConfig/config.ts | 12 +++++------ src/libs/Navigation/types.ts | 12 +++++------ .../accounting/qbo/QuickbooksImportPage.tsx | 20 ++++++++++--------- src/types/onyx/Policy.ts | 2 +- 9 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 2b3cc7c09708..cc636390d954 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1183,6 +1183,15 @@ const CONST = { EXPENSIFY_EMAIL_DOMAIN: '@expensify.com', }, + INTEGRATION_ENTITY_MAP_TYPES: { + DEFAULT: 'DEFAULT', + NONE: 'NONE', + TAG: 'TAG', + REPORT_FIELD: 'REPORT_FIELD', + NOT_IMPORTED: 'NOT IMPORTED', + IMPORTED: 'IMPORTED', + }, + ACCOUNT_ID: { ACCOUNTING: Number(Config?.EXPENSIFY_ACCOUNT_ID_ACCOUNTING ?? 9645353), ADMIN: Number(Config?.EXPENSIFY_ACCOUNT_ID_ADMIN ?? -1), diff --git a/src/ROUTES.ts b/src/ROUTES.ts index b5c916e88e02..346bc66ebec7 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -669,27 +669,27 @@ const ROUTES = { route: 'r/:reportID/transaction/:transactionID/receipt', getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const, }, - WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_IMPORT: { + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_IMPORT: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import` as const, }, - WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: { + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/accounts', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/accounts` as const, }, - WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES: { + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CLASSES: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/classes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/classes` as const, }, - WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS: { + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CUSTOMERS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/customers', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/customers` as const, }, - WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS: { + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_LOCATIONS: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/locations', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/locations` as const, }, - WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES: { + WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/taxes` as const, }, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f62e62715ad6..3e9dcf05fa7c 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -247,12 +247,12 @@ const SCREENS = { DISTANCE_RATES: 'Distance_Rates', CREATE_DISTANCE_RATE: 'Create_Distance_Rate', DISTANCE_RATES_SETTINGS: 'Distance_Rates_Settings', - QUICKBOOKSONLINE_IMPORT: 'Workspace_Accounting_QuickbooksOnline_Import', - QUICKBOOKSONLINE_CHART_OF_ACCOUNTS: 'Workspace_Accounting_QuickbooksOnline_Import_Chart_Of_Accounts', - QUICKBOOKSONLINE_CLASSES: 'Workspace_Accounting_QuickbooksOnline_Import_Classes', - QUICKBOOKSONLINE_CUSTOMERS: 'Workspace_Accounting_QuickbooksOnline_Import_Customers', - QUICKBOOKSONLINE_LOCATIONS: 'Workspace_Accounting_QuickbooksOnline_Import_Locations', - QUICKBOOKSONLINE_TAXES: 'Workspace_Accounting_QuickbooksOnline_Import_Taxes', + QUICKBOOKS_ONLINE_IMPORT: 'Workspace_Accounting_Quickbooks_Online_Import', + QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS: 'Workspace_Accounting_Quickbooks_Online_Import_Chart_Of_Accounts', + QUICKBOOKS_ONLINE_CLASSES: 'Workspace_Accounting_Quickbooks_Online_Import_Classes', + QUICKBOOKS_ONLINE_CUSTOMERS: 'Workspace_Accounting_Quickbooks_Online_Import_Customers', + QUICKBOOKS_ONLINE_LOCATIONS: 'Workspace_Accounting_Quickbooks_Online_Import_Locations', + QUICKBOOKS_ONLINE_TAXES: 'Workspace_Accounting_Quickbooks_Online_Import_Taxes', DISTANCE_RATE_DETAILS: 'Distance_Rate_Details', DISTANCE_RATE_EDIT: 'Distance_Rate_Edit', }, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index e31a78d96290..c1eaa6182be3 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -258,12 +258,12 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/ExitSurvey/ExitSurveyReasonPage').default as React.ComponentType, [SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyResponsePage').default as React.ComponentType, [SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM]: () => require('../../../../pages/settings/ExitSurvey/ExitSurveyConfirmPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksImportPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksCustomersPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksTaxesPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksLocationsPage').default as React.ComponentType, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksClassesPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_IMPORT]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksImportPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CUSTOMERS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksCustomersPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_TAXES]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksTaxesPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_LOCATIONS]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksLocationsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CLASSES]: () => require('../../../../pages/workspace/accounting/qbo/QuickbooksClassesPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage').default as React.ComponentType, [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET]: () => require('../../../../pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index 5452a95fa7ba..50d1516fc9be 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -20,12 +20,12 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.WORKFLOWS_PAYER, ], [SCREENS.WORKSPACE.ACCOUNTING]: [ - SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT, - SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS, - SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES, - SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES, - SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS, - SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS, + SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_IMPORT, + SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CLASSES, + SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_TAXES, + SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_LOCATIONS, + SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CUSTOMERS, ], [SCREENS.WORKSPACE.TAXES]: [ SCREENS.WORKSPACE.TAXES_SETTINGS, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index dffed8c0d055..37fb4d80007f 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -232,12 +232,12 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CURRENCY]: { path: ROUTES.WORKSPACE_PROFILE_CURRENCY.route, }, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_IMPORT.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.route}, - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES.route}, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_IMPORT]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_IMPORT.route}, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS.route}, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CLASSES]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CLASSES.route}, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CUSTOMERS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CUSTOMERS.route}, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_LOCATIONS]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_LOCATIONS.route}, + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_TAXES]: {path: ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES.route}, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 3a1f2319e261..53395915f9ae 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -246,22 +246,22 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_IMPORT]: { + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_IMPORT]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CHART_OF_ACCOUNTS]: { + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_LOCATIONS]: { + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_LOCATIONS]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CLASSES]: { + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CLASSES]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_CUSTOMERS]: { + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_CUSTOMERS]: { policyID: string; }; - [SCREENS.WORKSPACE.QUICKBOOKSONLINE_TAXES]: { + [SCREENS.WORKSPACE.QUICKBOOKS_ONLINE_TAXES]: { policyID: string; }; [SCREENS.GET_ASSISTANCE]: { diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 2a212232e5a9..98c01c1d4cf4 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -19,12 +19,14 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const quickbooksOnlineConfigTitles = { - DEFAULT: translate('workspace.qbo.imported'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.DEFAULT]: translate('workspace.qbo.imported'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED]: translate('workspace.qbo.imported'), true: translate('workspace.qbo.imported'), false: translate('workspace.qbo.notImported'), - NONE: translate('workspace.qbo.notImported'), - TAG: translate('workspace.qbo.importedAsTags'), - REPORT_FIELD: translate('workspace.qbo.importedAsReportFields'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.NOT_IMPORTED]: translate('workspace.qbo.notImported'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE]: translate('workspace.qbo.notImported'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG]: translate('workspace.qbo.importedAsTags'), + [CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD]: translate('workspace.qbo.importedAsReportFields'), }; const policyID = policy?.id ?? ''; const {syncClasses, syncCustomers, syncLocations, syncTaxes, enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; @@ -32,35 +34,35 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { const sections = [ { description: translate('workspace.qbo.accounts'), - action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), hasError: Boolean(policy?.errors?.enableNewCategories), title: enableNewCategories, pendingAction: pendingFields?.enableNewCategories, }, { description: translate('workspace.qbo.classes'), - action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CLASSES.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CLASSES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncClasses), title: syncClasses, pendingAction: pendingFields?.syncClasses, }, { description: translate('workspace.qbo.customers'), - action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_CUSTOMERS.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CUSTOMERS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncCustomers), title: syncCustomers, pendingAction: pendingFields?.syncCustomers, }, { description: translate('workspace.qbo.locations'), - action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_LOCATIONS.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_LOCATIONS.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncLocations), title: syncLocations, pendingAction: pendingFields?.syncLocations, }, { description: translate('workspace.qbo.taxes'), - action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKSONLINE_TAXES.getRoute(policyID)), + action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES.getRoute(policyID)), hasError: Boolean(policy?.errors?.syncTaxes), title: syncTaxes, pendingAction: pendingFields?.syncTaxes, diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 0565620c8566..86e087e1cab1 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -141,7 +141,7 @@ type QBOConnectionData = { vendors: Vendor[]; }; -type IntegrationEntityMap = 'NONE' | 'DEFAULT' | 'TAG' | 'REPORT_FIELD' | false | true; +type IntegrationEntityMap = (typeof CONST.INTEGRATION_ENTITY_MAP_TYPES)[keyof typeof CONST.INTEGRATION_ENTITY_MAP_TYPES] | false | true; /** * User configuration for the QuickBooks Online accounting integration. From 431470bf30ff67f4ea1ee66a513e485435e84f5e Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 4 Apr 2024 16:00:24 +0200 Subject: [PATCH 48/78] review fixes --- src/pages/iou/request/step/IOURequestStepCategory.tsx | 3 ++- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 272db69e7d17..3a343244a0be 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -66,7 +66,8 @@ function IOURequestStepCategory({ const isEditingSplitBill = isEditing && iouType === CONST.IOU.TYPE.SPLIT; const transactionCategory = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction)?.category; - const reportAction = reportActions?.[report?.parentReportActionID ?? reportActionID] ?? null; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const reportAction = reportActions?.[report?.parentReportActionID || reportActionID] ?? null; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (transactionCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index b8f77304ffbc..d00a8a532d73 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -36,13 +36,19 @@ import withWritableReportOrNotFound from './withWritableReportOrNotFound'; import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; type IOURequestStepConfirmationOnyxProps = { + /** The policy of the report */ policy: OnyxEntry; + + /** The category configuration of the report's policy */ policyCategories: OnyxEntry; + + /** The tag configuration of the report's policy */ policyTags: OnyxEntry; }; type IOURequestStepConfirmationProps = IOURequestStepConfirmationOnyxProps & WithWritableReportOrNotFoundProps & { + /** The transaction object being modified in Onyx */ transaction: OnyxEntry; }; From 5c54efe88e320b8ce5cbfa914eec282f1197007e Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 4 Apr 2024 16:19:15 +0200 Subject: [PATCH 49/78] fix null/undef --- src/components/TagPicker/index.tsx | 4 ++-- src/libs/OptionsListUtils.ts | 2 +- src/libs/ReportUtils.ts | 2 +- src/libs/SidebarUtils.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 54ad016173b7..fc9c0ca6ad1a 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -15,7 +15,7 @@ import type {PolicyTag, PolicyTagList, PolicyTags, RecentlyUsedTags} from '@src/ type SelectedTagOption = { name: string; enabled: boolean; - accountID: number | null; + accountID: number | undefined; }; type TagPickerOnyxProps = { @@ -76,7 +76,7 @@ function TagPicker({selectedTag, tagListName, policyTags, tagListIndex, policyRe { name: selectedTag, enabled: true, - accountID: null, + accountID: undefined, }, ]; }, [selectedTag]); diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 71b0b81e3aea..7c9c264f4243 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -648,7 +648,7 @@ function createOption( icons: undefined, tooltipText: null, ownerAccountID: undefined, - subtitle: null, + subtitle: undefined, participantsList: undefined, accountID: 0, login: undefined, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 20bd636b409b..070c1906ea89 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -383,7 +383,7 @@ type OptionData = { alternateTextMaxLines?: number; boldStyle?: boolean; customIcon?: CustomIcon; - subtitle?: string | null; + subtitle?: string; login?: string; accountID?: number; pronouns?: string; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 6abe75ecaf70..10c019298eda 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -207,7 +207,7 @@ function getOptionData({ allReportErrors: OptionsListUtils.getAllReportErrors(report, reportActions), brickRoadIndicator: null, tooltipText: null, - subtitle: null, + subtitle: undefined, login: undefined, accountID: undefined, reportID: '', From cfc2dfd8f7cba8e1b40788c5e919f522ae62a8f1 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 4 Apr 2024 16:25:06 +0200 Subject: [PATCH 50/78] fix null/undef --- src/pages/RoomInvitePage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 49e53381e040..9792a35e9154 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -70,7 +70,7 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { }); const newSelectedOptions: ReportUtils.OptionData[] = []; selectedOptions.forEach((option) => { - newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], isSelected: true} : option); + newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], accountID: detailsMap[option.login] ?? undefined, isSelected: true} : option); }); setUserToInvite(inviteOptions.userToInvite); @@ -134,7 +134,7 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { if (isOptionInList) { newSelectedOptions = selectedOptions.filter((selectedOption) => selectedOption.login !== option.login); } else { - newSelectedOptions = [...selectedOptions, {...option, isSelected: true}]; + newSelectedOptions = [...selectedOptions, {...option, accountID: option.accountID ?? undefined, isSelected: true}]; } setSelectedOptions(newSelectedOptions); From 77ec664cc061ca52c96d547e8c219acf0fd76e0d Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 4 Apr 2024 16:29:29 +0200 Subject: [PATCH 51/78] fix null/undef --- src/pages/RoomInvitePage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 9792a35e9154..28d6f5db2780 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -70,7 +70,9 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { }); const newSelectedOptions: ReportUtils.OptionData[] = []; selectedOptions.forEach((option) => { - newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], accountID: detailsMap[option.login] ?? undefined, isSelected: true} : option); + newSelectedOptions.push( + option.login && option.login in detailsMap ? {...detailsMap[option.login], accountID: detailsMap[option.login].accountID ?? undefined, isSelected: true} : option, + ); }); setUserToInvite(inviteOptions.userToInvite); From 1e59910562bd2464525c9b9ed5d03f92a9eab7d7 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Thu, 4 Apr 2024 17:44:47 +0300 Subject: [PATCH 52/78] remove color --- src/pages/workspace/accounting/WorkspaceAccountingPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx index f96ee9608145..7c2245514839 100644 --- a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -11,7 +11,7 @@ function WorkspaceAccountingPage() { shouldEnableMaxHeight testID={WorkspaceAccountingPage.displayName} > - + ); } From c25187020df1d23f3b7ba42d4fd6021f324304f7 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Fri, 5 Apr 2024 00:15:55 +0200 Subject: [PATCH 53/78] review fixes --- src/ROUTES.ts | 3 ++- src/components/CategoryPicker.tsx | 2 +- src/libs/API/parameters/TrackExpenseParams.ts | 2 +- src/libs/IOUUtils.ts | 3 ++- src/libs/OptionsListUtils.ts | 2 +- src/libs/TransactionUtils.ts | 3 ++- src/libs/actions/IOU.ts | 12 ++++++------ src/pages/RoomInvitePage.tsx | 6 ++---- .../iou/request/step/IOURequestStepCategory.tsx | 4 +++- .../iou/request/step/IOURequestStepConfirmation.tsx | 10 ++-------- src/types/onyx/Transaction.ts | 3 ++- 11 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 8130c271a2db..067e8ec8b43a 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -1,5 +1,6 @@ import type {IsEqual, ValueOf} from 'type-fest'; import type CONST from './CONST'; +import type {IOURequestType} from './libs/actions/IOU'; // This is a file containing constants for all the routes we want to be able to go to @@ -393,7 +394,7 @@ const ROUTES = { // straight to those flows without needing to have optimistic transaction and report IDs. MONEY_REQUEST_START: { route: 'start/:iouType/:iouRequestType', - getRoute: (iouType: ValueOf, iouRequestType: ValueOf) => `start/${iouType}/${iouRequestType}` as const, + getRoute: (iouType: ValueOf, iouRequestType: IOURequestType) => `start/${iouType}/${iouRequestType}` as const, }, MONEY_REQUEST_CREATE_TAB_DISTANCE: { route: ':action/:iouType/start/:transactionID/:reportID/distance', diff --git a/src/components/CategoryPicker.tsx b/src/components/CategoryPicker.tsx index 799b89d1e84f..f26d7c25c7e2 100644 --- a/src/components/CategoryPicker.tsx +++ b/src/components/CategoryPicker.tsx @@ -21,7 +21,7 @@ type CategoryPickerProps = CategoryPickerOnyxProps & { /** It's used by withOnyx HOC */ // eslint-disable-next-line react/no-unused-prop-types policyID: string; - selectedCategory: string | undefined; + selectedCategory?: string; onSubmit: (item: ListItem) => void; }; diff --git a/src/libs/API/parameters/TrackExpenseParams.ts b/src/libs/API/parameters/TrackExpenseParams.ts index f48c8666f109..9c8d9761d888 100644 --- a/src/libs/API/parameters/TrackExpenseParams.ts +++ b/src/libs/API/parameters/TrackExpenseParams.ts @@ -15,7 +15,7 @@ type TrackExpenseParams = { createdChatReportActionID: string; createdIOUReportActionID?: string; reportPreviewReportActionID?: string; - receipt: Receipt; + receipt?: Receipt; receiptState?: ValueOf; category?: string; tag?: string; diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 65390982f18c..415872750243 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -3,11 +3,12 @@ import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Report, Transaction} from '@src/types/onyx'; +import type {IOURequestType} from './actions/IOU'; import * as CurrencyUtils from './CurrencyUtils'; import Navigation from './Navigation/Navigation'; import * as TransactionUtils from './TransactionUtils'; -function navigateToStartMoneyRequestStep(requestType: ValueOf, iouType: ValueOf, transactionID: string, reportID: string) { +function navigateToStartMoneyRequestStep(requestType: IOURequestType, iouType: ValueOf, transactionID: string, reportID: string) { // If the participants were automatically added to the transaction, then the user needs taken back to the starting step switch (requestType) { case CONST.IOU.REQUEST_TYPE.DISTANCE: diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 7c9c264f4243..1879896e93dd 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -166,7 +166,7 @@ type MemberForList = { keyForList: string; isSelected: boolean; isDisabled: boolean; - accountID?: number | null; + accountID?: number; login: string; icons?: OnyxCommon.Icon[]; pendingAction?: OnyxCommon.PendingAction; diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 8b37288c711a..f6f519c784c4 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -8,6 +8,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {RecentWaypoint, Report, TaxRate, TaxRates, TaxRatesWithDefault, Transaction, TransactionViolation} from '@src/types/onyx'; import type {Comment, Receipt, TransactionChanges, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type {IOURequestType} from './actions/IOU'; import {isCorporateCard, isExpensifyCard} from './CardUtils'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; @@ -55,7 +56,7 @@ function isScanRequest(transaction: OnyxEntry): boolean { return Boolean(transaction?.receipt?.source); } -function getRequestType(transaction: OnyxEntry): ValueOf { +function getRequestType(transaction: OnyxEntry): IOURequestType { if (isDistanceRequest(transaction)) { return CONST.IOU.REQUEST_TYPE.DISTANCE; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 17fafa5961de..a914439bc30d 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -343,7 +343,7 @@ function updateMoneyRequestTypeParams(routes: StackNavigationState, reportID: string, requestType?: ValueOf) { +function startMoneyRequest(iouType: ValueOf, reportID: string, requestType?: IOURequestType) { clearMoneyRequest(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); switch (requestType) { case CONST.IOU.REQUEST_TYPE.MANUAL: @@ -415,7 +415,7 @@ function setMoneyRequestBillable_temporaryForRefactor(transactionID: string, bil } // eslint-disable-next-line @typescript-eslint/naming-convention -function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[] | undefined = []) { +function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[] = []) { Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants}); } @@ -2068,7 +2068,7 @@ function updateMoneyRequestDistance( function updateMoneyRequestCategory( transactionID: string, transactionThreadReportID: string, - category: string | undefined, + category: string, policy: OnyxEntry, policyTagList: OnyxEntry, policyCategories: OnyxEntry, @@ -2227,7 +2227,7 @@ function trackExpense( payeeAccountID: number, participant: Participant, comment: string, - receipt: Receipt, + receipt?: Receipt, category?: string, tag?: string, taxCode = '', @@ -5292,7 +5292,7 @@ function navigateToStartStepIfScanFileCannotBeRead( receiptFilename: string | undefined, receiptPath: ReceiptSource | undefined, onSuccess: (file: File) => void, - requestType: ValueOf, + requestType: IOURequestType, iouType: ValueOf, transactionID: string, reportID: string, @@ -5318,7 +5318,7 @@ function savePreferredPaymentMethod(policyID: string, paymentMethod: PaymentMeth Onyx.merge(`${ONYXKEYS.NVP_LAST_PAYMENT_METHOD}`, {[policyID]: paymentMethod}); } -export type {GPSPoint as GpsPoint}; +export type {GPSPoint as GpsPoint, IOURequestType}; export { setMoneyRequestParticipants, createDistanceRequest, diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 28d6f5db2780..b9f9fd09fa44 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -70,9 +70,7 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { }); const newSelectedOptions: ReportUtils.OptionData[] = []; selectedOptions.forEach((option) => { - newSelectedOptions.push( - option.login && option.login in detailsMap ? {...detailsMap[option.login], accountID: detailsMap[option.login].accountID ?? undefined, isSelected: true} : option, - ); + newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], accountID: detailsMap[option.login].accountID, isSelected: true} : option); }); setUserToInvite(inviteOptions.userToInvite); @@ -136,7 +134,7 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { if (isOptionInList) { newSelectedOptions = selectedOptions.filter((selectedOption) => selectedOption.login !== option.login); } else { - newSelectedOptions = [...selectedOptions, {...option, accountID: option.accountID ?? undefined, isSelected: true}]; + newSelectedOptions = [...selectedOptions, {...option, accountID: option.accountID, isSelected: true}]; } setSelectedOptions(newSelectedOptions); diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 3a343244a0be..8aeb9250a4c9 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -69,8 +69,10 @@ function IOURequestStepCategory({ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const reportAction = reportActions?.[report?.parentReportActionID || reportActionID] ?? null; + // The transactionCategory can be an empty string, so to maintain the logic we'd like to keep it in this shape until utils refactor // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (transactionCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); + const shouldShowCategory = ReportUtils.isGroupPolicy(report) && (!!transactionCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); + const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); // eslint-disable-next-line rulesdir/no-negated-variables diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index d00a8a532d73..2e205de7145d 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -206,7 +206,7 @@ function IOURequestStepConfirmation({ const trackExpense = useCallback( (selectedParticipants: Participant[], trimmedComment: string, receiptObj?: Receipt, gpsPoints?: IOU.GpsPoint) => { - if (!receiptObj || !report || !transaction) { + if (!report || !transaction) { return; } IOU.trackExpense( @@ -489,6 +489,7 @@ function IOURequestStepConfirmation({ /> {isLoading && } + {/* @ts-expect-error wait until MoneyRequestConfirmationList is migrated to typescript */} diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 8d05a9af5bd7..589fc8a6a391 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -1,4 +1,5 @@ import type {KeysOfUnion, ValueOf} from 'type-fest'; +import type {IOURequestType} from '@libs/actions/IOU'; import type CONST from '@src/CONST'; import type ONYXKEYS from '@src/ONYXKEYS'; import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; @@ -136,7 +137,7 @@ type Transaction = OnyxCommon.OnyxValueWithOfflineFeedback< filename?: string; /** Used during the creation flow before the transaction is saved to the server */ - iouRequestType?: ValueOf; + iouRequestType?: IOURequestType; /** The original merchant name */ merchant: string; From 160be500cb74ea831e33040945085bcc18394e7d Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Fri, 5 Apr 2024 00:18:56 +0200 Subject: [PATCH 54/78] review fixes --- src/libs/TransactionUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index f6f519c784c4..a22baa1ffc7c 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -454,7 +454,7 @@ function getCreated(transaction: OnyxEntry, dateFormat: string = CO * Returns the translation key to use for the header title */ function getHeaderTitleTranslationKey(transaction: OnyxEntry): TranslationPaths { - const headerTitles: Record = { + const headerTitles: Record = { [CONST.IOU.REQUEST_TYPE.DISTANCE]: 'tabSelector.distance', [CONST.IOU.REQUEST_TYPE.MANUAL]: 'tabSelector.manual', [CONST.IOU.REQUEST_TYPE.SCAN]: 'tabSelector.scan', From 55495c71a6628ae95684fcd2dbfba71b7708b371 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 4 Apr 2024 23:38:34 +0100 Subject: [PATCH 55/78] Fix: Thread - App shows skeleton loading when clicking on parent/ancestor message offline --- src/components/ParentNavigationSubtitle.tsx | 5 +++-- src/pages/home/report/ReportActionItemParentAction.tsx | 6 +++++- src/pages/home/report/ThreadDivider.tsx | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx index a72de3d4eafb..0ad32f18659b 100644 --- a/src/components/ParentNavigationSubtitle.tsx +++ b/src/components/ParentNavigationSubtitle.tsx @@ -1,6 +1,7 @@ import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; @@ -26,7 +27,7 @@ type ParentNavigationSubtitleProps = { function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportActionID, parentReportID = '', pressableStyles}: ParentNavigationSubtitleProps) { const styles = useThemeStyles(); const {workspaceName, reportName} = parentNavigationSubtitleData; - + const {isOffline} = useNetwork(); const {translate} = useLocalize(); return ( @@ -34,7 +35,7 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct onPress={() => { const parentAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? ''); const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? ''); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, isVisibleAction ? parentReportActionID : undefined)); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, isVisibleAction && !isOffline ? parentReportActionID : undefined)); }} accessibilityLabel={translate('threads.parentNavigationSummary', {reportName, workspaceName})} role={CONST.ROLE.LINK} diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx index 0394a290b9af..537f6292c3e4 100644 --- a/src/pages/home/report/ReportActionItemParentAction.tsx +++ b/src/pages/home/report/ReportActionItemParentAction.tsx @@ -2,6 +2,7 @@ import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -59,6 +60,7 @@ function ReportActionItemParentAction({ const {isSmallScreenWidth} = useWindowDimensions(); const ancestorIDs = useRef(ReportUtils.getAllAncestorReportActionIDs(report)); const [allAncestors, setAllAncestors] = useState([]); + const {isOffline} = useNetwork(); useEffect(() => { const unsubscribeReports: Array<() => void> = []; @@ -106,7 +108,9 @@ function ReportActionItemParentAction({ { const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(ancestor.reportAction, ancestor.reportAction.reportActionID ?? ''); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', isVisibleAction ? ancestor.reportAction.reportActionID : undefined)); + Navigation.navigate( + ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', isVisibleAction && !isOffline ? ancestor.reportAction.reportActionID : undefined), + ); }} parentReportAction={parentReportAction} report={ancestor.report} diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx index e1ccca8725cf..c728cdf20db4 100644 --- a/src/pages/home/report/ThreadDivider.tsx +++ b/src/pages/home/report/ThreadDivider.tsx @@ -5,6 +5,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import {PressableWithoutFeedback} from '@components/Pressable'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; @@ -23,13 +24,16 @@ function ThreadDivider({ancestor}: ThreadDividerProps) { const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); + const {isOffline} = useNetwork(); return ( { const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(ancestor.reportAction, ancestor.reportAction.reportActionID ?? ''); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', isVisibleAction ? ancestor.reportAction.reportActionID : undefined)); + Navigation.navigate( + ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? '', isVisibleAction && !isOffline ? ancestor.reportAction.reportActionID : undefined), + ); }} accessibilityLabel={translate('threads.thread')} role={CONST.ROLE.BUTTON} From 75bc45904754626d199a9feaa07e190118c01650 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:04:53 +0100 Subject: [PATCH 56/78] Fix: Thread - New message does not appear in main chat after returning from thread and sending text | Report - 'New message' button is not displayed when navigating to parent report | Chat - Parent msgs disappear after back from thread by clicking header/browser back button --- src/pages/home/report/ReportActionsView.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index ce5e693c8b48..7ce9182d4335 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -1,5 +1,6 @@ import type {RouteProp} from '@react-navigation/native'; import {useIsFocused, useRoute} from '@react-navigation/native'; +import {useFocusEffect} from '@react-navigation/native'; import lodashIsEqual from 'lodash/isEqual'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager} from 'react-native'; @@ -239,6 +240,17 @@ function ReportActionsView({ [fetchNewerAction, hasMoreCached, newestReportAction], ); + useFocusEffect( + useCallback(() => { + if (isFirstLinkedActionRender.current) { + isFirstLinkedActionRender.current = false; + } + if (newestReportAction?.reportActionID) { + setCurrentReportActionID(newestReportAction.reportActionID); + } + }, [newestReportAction?.reportActionID]), + ); + const mostRecentIOUReportActionID = useMemo(() => ReportActionsUtils.getMostRecentIOURequestActionID(reportActions), [reportActions]); const hasCachedActionOnFirstRender = useInitialValue(() => reportActions.length > 0); const hasNewestReportAction = reportActions[0]?.created === report.lastVisibleActionCreated || reportActions[0]?.created === transactionThreadReport?.lastVisibleActionCreated; @@ -389,10 +401,6 @@ function ReportActionsView({ ) { handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID}); } - if (reportActionID && indexOfLinkedAction > -1 && hasNewestReportAction && isFirstLinkedActionRender.current) { - isFirstLinkedActionRender.current = false; - setCurrentReportActionID(newestReportAction?.reportActionID); - } }, [ isLoadingInitialReportActions, isLoadingOlderReportActions, From 14ae8252c06e0483a2d400dcad55f298327e5e56 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:14:51 +0100 Subject: [PATCH 57/78] Fix lint error --- src/pages/home/report/ReportActionsView.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 7ce9182d4335..f6152111b4e7 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -1,6 +1,5 @@ import type {RouteProp} from '@react-navigation/native'; -import {useIsFocused, useRoute} from '@react-navigation/native'; -import {useFocusEffect} from '@react-navigation/native'; +import {useIsFocused, useRoute, useFocusEffect} from '@react-navigation/native'; import lodashIsEqual from 'lodash/isEqual'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager} from 'react-native'; From 97316f029efa245c5dcc493fbc33a5fd31f7055c Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 00:22:01 +0100 Subject: [PATCH 58/78] Prettier --- src/pages/home/report/ReportActionsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index f6152111b4e7..1b88176ef8f1 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -1,5 +1,5 @@ import type {RouteProp} from '@react-navigation/native'; -import {useIsFocused, useRoute, useFocusEffect} from '@react-navigation/native'; +import {useFocusEffect, useIsFocused, useRoute} from '@react-navigation/native'; import lodashIsEqual from 'lodash/isEqual'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager} from 'react-native'; From 2dfabdc373ddbb428dc734c7845e6b70450b1296 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 01:29:07 +0100 Subject: [PATCH 59/78] Fix: Report - 'New message' button is not displayed when navigating to parent report --- src/pages/home/report/ReportActionsList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index d1b9c420b0af..85566b8c5fa0 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -464,10 +464,10 @@ function ReportActionsList({ setCurrentUnreadMarker(reportAction.reportActionID); } }); - if (!markerFound) { + if (!markerFound && !linkedReportActionID) { setCurrentUnreadMarker(null); } - }, [sortedVisibleReportActions, report.reportID, shouldDisplayNewMarker, currentUnreadMarker]); + }, [sortedVisibleReportActions, report.reportID, shouldDisplayNewMarker, currentUnreadMarker, linkedReportActionID]); useEffect(() => { calculateUnreadMarker(); From 4f6f0e3bf0d676309e30df30b750153ea8c07424 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 02:56:49 +0100 Subject: [PATCH 60/78] Fix: comment linking does not preserve message position on native --- src/pages/home/report/ReportActionsView.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index bce4a54f0f35..1b0424e12f0a 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -99,6 +99,7 @@ function ReportActionsView({ // we don't set currentReportActionID on initial render as linkedID as it should trigger visibleReportActions after linked message was positioned const [currentReportActionID, setCurrentReportActionID] = useState(''); const isFirstLinkedActionRender = useRef(true); + const isFirstRender = useRef(true); const network = useNetwork(); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); @@ -231,6 +232,10 @@ function ReportActionsView({ useFocusEffect( useCallback(() => { + if (isFirstRender.current) { + isFirstRender.current = false; + return; + } if (isFirstLinkedActionRender.current) { isFirstLinkedActionRender.current = false; } From 61d378ae066f9010229014fcf635288f9600a94e Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 07:09:30 +0100 Subject: [PATCH 61/78] Fix: comment linking does not preserve message position --- src/pages/home/report/ReportActionsView.tsx | 23 ++++----------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 1b0424e12f0a..b7d13cd56d97 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -225,26 +225,11 @@ function ReportActionsView({ if (isFirstLinkedActionRender.current) { isFirstLinkedActionRender.current = false; } - setCurrentReportActionID(firstReportActionID); + setCurrentReportActionID(firstReportActionID); }, [fetchNewerAction, hasMoreCached, newestReportAction], ); - useFocusEffect( - useCallback(() => { - if (isFirstRender.current) { - isFirstRender.current = false; - return; - } - if (isFirstLinkedActionRender.current) { - isFirstLinkedActionRender.current = false; - } - if (newestReportAction?.reportActionID) { - setCurrentReportActionID(newestReportAction.reportActionID); - } - }, [newestReportAction?.reportActionID]), - ); - const mostRecentIOUReportActionID = useMemo(() => ReportActionsUtils.getMostRecentIOURequestActionID(reportActions), [reportActions]); const hasCachedActionOnFirstRender = useInitialValue(() => reportActions.length > 0); const hasNewestReportAction = reportActions[0]?.created === report.lastVisibleActionCreated || reportActions[0]?.created === transactionThreadReport?.lastVisibleActionCreated; @@ -368,10 +353,10 @@ function ReportActionsView({ const isLoadingOlderReportsFirstNeeded = checkIfContentSmallerThanList() && reportActions.length > 23; if ( - (reportActionID && indexOfLinkedAction > -1 && !hasNewestReportAction && !isLoadingOlderReportsFirstNeeded) || - (!reportActionID && !hasNewestReportAction && !isLoadingOlderReportsFirstNeeded) + (reportActionID && indexOfLinkedAction > -1 && !isLoadingOlderReportsFirstNeeded) || + (!reportActionID && !isLoadingOlderReportsFirstNeeded) ) { - handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID}); + handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID, hasNewestReportAction}); } }, [ isLoadingInitialReportActions, From ce32cad16d80f3c3af265c62b08e60d50a87a5dd Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 07:24:11 +0100 Subject: [PATCH 62/78] Fix lint errors --- src/pages/home/report/ReportActionsView.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index b7d13cd56d97..92717a1b8896 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -1,5 +1,5 @@ import type {RouteProp} from '@react-navigation/native'; -import {useFocusEffect, useIsFocused, useRoute} from '@react-navigation/native'; +import {useIsFocused, useRoute} from '@react-navigation/native'; import lodashIsEqual from 'lodash/isEqual'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager} from 'react-native'; @@ -99,7 +99,6 @@ function ReportActionsView({ // we don't set currentReportActionID on initial render as linkedID as it should trigger visibleReportActions after linked message was positioned const [currentReportActionID, setCurrentReportActionID] = useState(''); const isFirstLinkedActionRender = useRef(true); - const isFirstRender = useRef(true); const network = useNetwork(); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); @@ -356,7 +355,7 @@ function ReportActionsView({ (reportActionID && indexOfLinkedAction > -1 && !isLoadingOlderReportsFirstNeeded) || (!reportActionID && !isLoadingOlderReportsFirstNeeded) ) { - handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID, hasNewestReportAction}); + handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID}); } }, [ isLoadingInitialReportActions, From 2750dce4b5709297041c7c34006036f0e6f7dd0d Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 07:33:30 +0100 Subject: [PATCH 63/78] Fix lint errors --- src/pages/home/report/ReportActionsView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 92717a1b8896..9f2d982c4fab 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -363,7 +363,6 @@ function ReportActionsView({ checkIfContentSmallerThanList, reportActionID, indexOfLinkedAction, - hasNewestReportAction, handleReportActionPagination, network.isOffline, reportActions.length, From 45e1992fc5a80984d3218ae0c6fbaaaca2e6ca5c Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 5 Apr 2024 07:40:44 +0100 Subject: [PATCH 64/78] Prettier --- src/pages/home/report/ReportActionsView.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 9f2d982c4fab..b8c683a803db 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -224,7 +224,7 @@ function ReportActionsView({ if (isFirstLinkedActionRender.current) { isFirstLinkedActionRender.current = false; } - setCurrentReportActionID(firstReportActionID); + setCurrentReportActionID(firstReportActionID); }, [fetchNewerAction, hasMoreCached, newestReportAction], ); @@ -351,10 +351,7 @@ function ReportActionsView({ // and there are fewer than 23 items, indicating we've reached the oldest message. const isLoadingOlderReportsFirstNeeded = checkIfContentSmallerThanList() && reportActions.length > 23; - if ( - (reportActionID && indexOfLinkedAction > -1 && !isLoadingOlderReportsFirstNeeded) || - (!reportActionID && !isLoadingOlderReportsFirstNeeded) - ) { + if ((reportActionID && indexOfLinkedAction > -1 && !isLoadingOlderReportsFirstNeeded) || (!reportActionID && !isLoadingOlderReportsFirstNeeded)) { handleReportActionPagination({firstReportActionID: newestReportAction?.reportActionID}); } }, [ From 5e3adc16080ba2595d59fd4191ecaf3f20e41553 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Fri, 5 Apr 2024 09:41:58 +0200 Subject: [PATCH 65/78] review fixes --- src/libs/actions/IOU.ts | 4 ---- src/pages/RoomInvitePage.tsx | 4 ++-- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 83a7e7563b7c..7de6369f175f 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -128,10 +128,6 @@ type SendMoneyParamsData = { failureData: OnyxUpdate[]; }; -type OutstandingChildRequest = { - hasOutstandingChildRequest?: boolean; -}; - type GPSPoint = { lat: number; long: number; diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index b9f9fd09fa44..49e53381e040 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -70,7 +70,7 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { }); const newSelectedOptions: ReportUtils.OptionData[] = []; selectedOptions.forEach((option) => { - newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], accountID: detailsMap[option.login].accountID, isSelected: true} : option); + newSelectedOptions.push(option.login && option.login in detailsMap ? {...detailsMap[option.login], isSelected: true} : option); }); setUserToInvite(inviteOptions.userToInvite); @@ -134,7 +134,7 @@ function RoomInvitePage({betas, report, policies}: RoomInvitePageProps) { if (isOptionInList) { newSelectedOptions = selectedOptions.filter((selectedOption) => selectedOption.login !== option.login); } else { - newSelectedOptions = [...selectedOptions, {...option, accountID: option.accountID, isSelected: true}]; + newSelectedOptions = [...selectedOptions, {...option, isSelected: true}]; } setSelectedOptions(newSelectedOptions); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 2e205de7145d..40f3de833d9e 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -489,7 +489,7 @@ function IOURequestStepConfirmation({ /> {isLoading && } - {/* @ts-expect-error wait until MoneyRequestConfirmationList is migrated to typescript */} + {/* @ts-expect-error TODO: Remove this once MoneyRequestConfirmationList (https://github.com/Expensify/App/issues/36130) is migrated to TypeScript. */} Date: Mon, 8 Apr 2024 10:49:12 +0200 Subject: [PATCH 66/78] remove forwardRef --- src/pages/iou/request/step/StepScreenWrapper.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/step/StepScreenWrapper.tsx b/src/pages/iou/request/step/StepScreenWrapper.tsx index c7ed6862ee11..e64f2792d2e4 100644 --- a/src/pages/iou/request/step/StepScreenWrapper.tsx +++ b/src/pages/iou/request/step/StepScreenWrapper.tsx @@ -1,4 +1,4 @@ -import React, {forwardRef} from 'react'; +import React from 'react'; import type {PropsWithChildren} from 'react'; import {View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; @@ -72,4 +72,4 @@ function StepScreenWrapper({ ); } -export default forwardRef(StepScreenWrapper); +export default StepScreenWrapper; From 9c4c43ab87e7a06725e33811f35910cf84fc8cec Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Mon, 8 Apr 2024 11:58:17 +0200 Subject: [PATCH 67/78] fix tests --- tests/unit/OptionsListUtilsTest.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/unit/OptionsListUtilsTest.ts b/tests/unit/OptionsListUtilsTest.ts index baefd1bd6d66..6333ee6f1bc7 100644 --- a/tests/unit/OptionsListUtilsTest.ts +++ b/tests/unit/OptionsListUtilsTest.ts @@ -1213,22 +1213,22 @@ describe('OptionsListUtils', () => { Engineering: { enabled: false, name: 'Engineering', - accountID: null, + accountID: undefined, }, Medical: { enabled: true, name: 'Medical', - accountID: null, + accountID: undefined, }, Accounting: { enabled: true, name: 'Accounting', - accountID: null, + accountID: undefined, }, HR: { enabled: true, name: 'HR', - accountID: null, + accountID: undefined, }, }; const smallResultList: OptionsListUtils.CategorySection[] = [ @@ -1291,57 +1291,57 @@ describe('OptionsListUtils', () => { Engineering: { enabled: false, name: 'Engineering', - accountID: null, + accountID: undefined, }, Medical: { enabled: true, name: 'Medical', - accountID: null, + accountID: undefined, }, Accounting: { enabled: true, name: 'Accounting', - accountID: null, + accountID: undefined, }, HR: { enabled: true, name: 'HR', - accountID: null, + accountID: undefined, }, Food: { enabled: true, name: 'Food', - accountID: null, + accountID: undefined, }, Traveling: { enabled: false, name: 'Traveling', - accountID: null, + accountID: undefined, }, Cleaning: { enabled: true, name: 'Cleaning', - accountID: null, + accountID: undefined, }, Software: { enabled: true, name: 'Software', - accountID: null, + accountID: undefined, }, OfficeSupplies: { enabled: false, name: 'Office Supplies', - accountID: null, + accountID: undefined, }, Taxes: { enabled: true, name: 'Taxes', - accountID: null, + accountID: undefined, }, Benefits: { enabled: true, name: 'Benefits', - accountID: null, + accountID: undefined, }, }; const largeResultList: OptionsListUtils.CategorySection[] = [ From 3ca396fcaad84d16d2181351c76d50a2807f2184 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 8 Apr 2024 14:08:51 +0300 Subject: [PATCH 68/78] resolve comments --- .../accounting/qbo/QuickbooksClassesPage.tsx | 13 ++++++++++--- .../accounting/qbo/QuickbooksCustomersPage.tsx | 13 ++++++++++--- .../accounting/qbo/QuickbooksLocationsPage.tsx | 13 ++++++++++--- .../accounting/qbo/QuickbooksTaxesPage.tsx | 11 +++++++++-- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index 82c9e229cb6c..f875389fee4e 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -22,8 +22,8 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { const styles = useThemeStyles(); const policyID = policy?.id ?? ''; const {syncClasses, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isSwitchOn = Boolean(syncClasses && syncClasses !== 'NONE'); - const isReportFieldsSelected = syncClasses === 'REPORT_FIELD'; + const isSwitchOn = Boolean(syncClasses && syncClasses !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isReportFieldsSelected = syncClasses === CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD; return ( @@ -48,7 +48,14 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncClasses', isSwitchOn ? 'NONE' : 'TAG')} + onToggle={() => + Policy.updatePolicyConnectionConfig( + policyID, + 'quickbooksOnline', + 'syncClasses', + isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, + ) + } /> diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index 8ad65c445ba4..34ec496d870f 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -22,8 +22,8 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { const styles = useThemeStyles(); const policyID = policy?.id ?? ''; const {syncCustomers, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isSwitchOn = Boolean(syncCustomers && syncCustomers !== 'NONE'); - const isReportFieldsSelected = syncCustomers === 'REPORT_FIELD'; + const isSwitchOn = Boolean(syncCustomers && syncCustomers !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isReportFieldsSelected = syncCustomers === CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD; return ( Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncCustomers', isSwitchOn ? 'NONE' : 'TAG')} + onToggle={() => + Policy.updatePolicyConnectionConfig( + policyID, + 'quickbooksOnline', + 'syncCustomers', + isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, + ) + } /> diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index b88d8bbdc800..6bc530998827 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -22,8 +22,8 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { const styles = useThemeStyles(); const policyID = policy?.id ?? ''; const {syncLocations, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isSwitchOn = Boolean(syncLocations && syncLocations !== 'NONE'); - const isReportFieldsSelected = syncLocations === 'REPORT_FIELD'; + const isSwitchOn = Boolean(syncLocations && syncLocations !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); + const isReportFieldsSelected = syncLocations === CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD; return ( @@ -48,7 +48,14 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncLocations', isSwitchOn ? 'NONE' : 'TAG')} + onToggle={() => + Policy.updatePolicyConnectionConfig( + policyID, + 'quickbooksOnline', + 'syncLocations', + isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, + ) + } /> diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index 0ff5bc892b16..4a5eda0d6a25 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -21,7 +21,7 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { const styles = useThemeStyles(); const policyID = policy?.id ?? ''; const {syncTaxes, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; - const isSwitchOn = Boolean(syncTaxes && syncTaxes !== 'NONE'); + const isSwitchOn = Boolean(syncTaxes && syncTaxes !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); return ( Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'syncTaxes', isSwitchOn ? 'NONE' : 'TAG')} + onToggle={() => + Policy.updatePolicyConnectionConfig( + policyID, + 'quickbooksOnline', + 'syncTaxes', + isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, + ) + } /> From b4d73c1e63ec3372fa49647b52aca7c285b91e6b Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 9 Apr 2024 10:24:02 +0300 Subject: [PATCH 69/78] remove true false from types --- src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx | 6 ++---- src/types/onyx/Policy.ts | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 98c01c1d4cf4..0d44901f91f2 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -21,8 +21,6 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { const quickbooksOnlineConfigTitles = { [CONST.INTEGRATION_ENTITY_MAP_TYPES.DEFAULT]: translate('workspace.qbo.imported'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED]: translate('workspace.qbo.imported'), - true: translate('workspace.qbo.imported'), - false: translate('workspace.qbo.notImported'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.NOT_IMPORTED]: translate('workspace.qbo.notImported'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE]: translate('workspace.qbo.notImported'), [CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG]: translate('workspace.qbo.importedAsTags'), @@ -36,7 +34,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { description: translate('workspace.qbo.accounts'), action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), hasError: Boolean(policy?.errors?.enableNewCategories), - title: enableNewCategories, + title: enableNewCategories ? CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED : CONST.INTEGRATION_ENTITY_MAP_TYPES.NOT_IMPORTED, pendingAction: pendingFields?.enableNewCategories, }, { @@ -89,7 +87,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { pendingAction={section.pendingAction} > Date: Tue, 9 Apr 2024 14:44:22 +0300 Subject: [PATCH 70/78] resolve c+ comments --- src/CONST.ts | 11 ++++++++++- .../parameters/UpdatePolicyConnectionConfigParams.ts | 7 +++++-- src/libs/actions/Policy.ts | 4 ++-- .../accounting/qbo/QuickbooksChartOfAccountsPage.tsx | 11 +++++++++-- .../accounting/qbo/QuickbooksClassesPage.tsx | 3 +-- .../accounting/qbo/QuickbooksCustomersPage.tsx | 3 +-- .../workspace/accounting/qbo/QuickbooksImportPage.tsx | 2 +- .../accounting/qbo/QuickbooksLocationsPage.tsx | 3 +-- .../workspace/accounting/qbo/QuickbooksTaxesPage.tsx | 3 +-- src/types/onyx/Policy.ts | 2 +- 10 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index cc636390d954..57c449cc85a0 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1188,9 +1188,18 @@ const CONST = { NONE: 'NONE', TAG: 'TAG', REPORT_FIELD: 'REPORT_FIELD', - NOT_IMPORTED: 'NOT IMPORTED', + NOT_IMPORTED: 'NOT_IMPORTED', IMPORTED: 'IMPORTED', }, + QUICK_BOOKS_ONLINE: 'quickbooksOnline', + + QUICK_BOOKS_IMPORTS: { + SYNC_CLASSES: 'syncClasses', + ENABLE_NEW_CATEGORIES: 'enableNewCategories', + SYNC_CUSTOMERS: 'syncCustomers', + SYNC_LOCATIONS: 'syncLocations', + SYNC_TAXES: 'syncTaxes', + }, ACCOUNT_ID: { ACCOUNTING: Number(Config?.EXPENSIFY_ACCOUNT_ID_ACCOUNTING ?? 9645353), diff --git a/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts b/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts index 0e5475f1a27d..be062435eaa4 100644 --- a/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts +++ b/src/libs/API/parameters/UpdatePolicyConnectionConfigParams.ts @@ -1,8 +1,11 @@ +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; + type UpdatePolicyConnectionConfigParams = { policyID: string; connectionName: string; - settingName: string; - settingValue: string | boolean; + settingName: ValueOf; + settingValue: ValueOf; idempotencyKey: string; }; diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 5ff4016867e5..6c20f8046db4 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -3608,8 +3608,8 @@ function openPolicyDistanceRatesPage(policyID?: string) { API.read(READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE, params); } -function updatePolicyConnectionConfig(policyID: string, connectionName: string, settingName: string, settingValue: string | boolean) { - const parameters = {policyID, connectionName, settingName, settingValue, idempotencyKey: settingName}; +function updatePolicyConnectionConfig(policyID: string, settingName: ValueOf, settingValue: ValueOf) { + const parameters = {policyID, connectionName: CONST.QUICK_BOOKS_ONLINE, settingName, settingValue, idempotencyKey: settingName}; const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index d3668b875c8c..13cceb6ad57c 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -21,6 +21,7 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { const styles = useThemeStyles(); const policyID = policy?.id ?? ''; const {enableNewCategories, pendingFields} = policy?.connections?.quickbooksOnline?.config ?? {}; + const isSwitchOn = Boolean(enableNewCategories && enableNewCategories !== CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE); return ( @@ -44,8 +45,14 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { Policy.updatePolicyConnectionConfig(policyID, 'quickbooksOnline', 'enableNewCategories', !enableNewCategories)} + isOn={isSwitchOn} + onToggle={() => + Policy.updatePolicyConnectionConfig( + policyID, + CONST.QUICK_BOOKS_IMPORTS.ENABLE_NEW_CATEGORIES, + isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, + ) + } /> diff --git a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx index f875389fee4e..f8c631b31476 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksClassesPage.tsx @@ -51,8 +51,7 @@ function QuickbooksClassesPage({policy}: WithPolicyProps) { onToggle={() => Policy.updatePolicyConnectionConfig( policyID, - 'quickbooksOnline', - 'syncClasses', + CONST.QUICK_BOOKS_IMPORTS.SYNC_CLASSES, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx index 34ec496d870f..27fde14081e7 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksCustomersPage.tsx @@ -50,8 +50,7 @@ function QuickbooksCustomersPage({policy}: WithPolicyProps) { onToggle={() => Policy.updatePolicyConnectionConfig( policyID, - 'quickbooksOnline', - 'syncCustomers', + CONST.QUICK_BOOKS_IMPORTS.SYNC_CUSTOMERS, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx index 0d44901f91f2..531b413c9d08 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksImportPage.tsx @@ -34,7 +34,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { description: translate('workspace.qbo.accounts'), action: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS.getRoute(policyID)), hasError: Boolean(policy?.errors?.enableNewCategories), - title: enableNewCategories ? CONST.INTEGRATION_ENTITY_MAP_TYPES.IMPORTED : CONST.INTEGRATION_ENTITY_MAP_TYPES.NOT_IMPORTED, + title: enableNewCategories, pendingAction: pendingFields?.enableNewCategories, }, { diff --git a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx index 6bc530998827..21da79587c0c 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksLocationsPage.tsx @@ -51,8 +51,7 @@ function QuickbooksLocationsPage({policy}: WithPolicyProps) { onToggle={() => Policy.updatePolicyConnectionConfig( policyID, - 'quickbooksOnline', - 'syncLocations', + CONST.QUICK_BOOKS_IMPORTS.SYNC_LOCATIONS, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx index 4a5eda0d6a25..293d6518baa0 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksTaxesPage.tsx @@ -48,8 +48,7 @@ function QuickbooksTaxesPage({policy}: WithPolicyProps) { onToggle={() => Policy.updatePolicyConnectionConfig( policyID, - 'quickbooksOnline', - 'syncTaxes', + CONST.QUICK_BOOKS_IMPORTS.SYNC_TAXES, isSwitchOn ? CONST.INTEGRATION_ENTITY_MAP_TYPES.NONE : CONST.INTEGRATION_ENTITY_MAP_TYPES.TAG, ) } diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index c48341770191..77fc2a1929e0 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -171,7 +171,7 @@ type QBOConnectionConfig = OnyxCommon.OnyxValueWithOfflineFeedback<{ exportDate: string; lastConfigurationTime: number; syncTax: boolean; - enableNewCategories: boolean; + enableNewCategories: IntegrationEntityMap; errors?: OnyxCommon.Errors; errorFields?: OnyxCommon.ErrorFields; export: { From 6355d8c38fe21db97dd1a9f94eadcf54985f4366 Mon Sep 17 00:00:00 2001 From: narefyev91 Date: Tue, 9 Apr 2024 18:05:35 +0300 Subject: [PATCH 71/78] Update src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx Co-authored-by: Eugene Voloshchak --- .../workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx index 13cceb6ad57c..593e5f9dc00a 100644 --- a/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx +++ b/src/pages/workspace/accounting/qbo/QuickbooksChartOfAccountsPage.tsx @@ -67,6 +67,6 @@ function QuickbooksChartOfAccountsPage({policy}: WithPolicyProps) { ); } -QuickbooksChartOfAccountsPage.displayName = 'QuickbooksChartOfAccountsConfigurationPage'; +QuickbooksChartOfAccountsPage.displayName = 'QuickbooksChartOfAccountsPage'; export default withPolicy(QuickbooksChartOfAccountsPage); From 08bbde158466df349a9c455955d2516203845a4c Mon Sep 17 00:00:00 2001 From: narefyev91 Date: Tue, 9 Apr 2024 18:05:48 +0300 Subject: [PATCH 72/78] Update src/pages/workspace/accounting/WorkspaceAccountingPage.tsx Co-authored-by: Eugene Voloshchak --- src/pages/workspace/accounting/WorkspaceAccountingPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx index 7c2245514839..e3b3bf1d3d05 100644 --- a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -3,7 +3,7 @@ import {View} from 'react-native'; import ScreenWrapper from '@components/ScreenWrapper'; import withPolicy from '@pages/workspace/withPolicy'; -// Fake page will be removed after normal on will be merged +// Fake page will be removed after normal one will be merged function WorkspaceAccountingPage() { return ( Date: Tue, 9 Apr 2024 19:59:24 +0300 Subject: [PATCH 73/78] merge updates --- .../WorkspaceSettingsModalStackNavigator.tsx | 5 ----- src/libs/Navigation/linkingConfig/config.ts | 3 --- src/libs/Navigation/types.ts | 3 --- src/pages/workspace/accounting/WorkspaceAccountingPage.tsx | 4 +++- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx index 25a140d76079..2dce4247c7ae 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/WorkspaceSettingsModalStackNavigator.tsx @@ -82,11 +82,6 @@ function WorkspaceSettingsModalStackNavigator() { name={SCREENS.WORKSPACE.DISTANCE_RATES} getComponent={() => require('@pages/workspace/distanceRates/PolicyDistanceRatesPage').default as React.ComponentType} /> - require('@pages/workspace/accounting/WorkspaceAccountingPage').default as React.ComponentType} - /> ); } diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 79d857c2c2a2..f7cdc54335ab 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -656,9 +656,6 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.INVOICES]: { path: ROUTES.WORKSPACE_INVOICES.route, }, - [SCREENS.WORKSPACE.ACCOUNTING]: { - path: ROUTES.WORKSPACE_ACCOUNTING.route, - }, [SCREENS.WORKSPACE.TRAVEL]: { path: ROUTES.WORKSPACE_TRAVEL.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index ccbd53b5b144..00e722e76b5d 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -621,9 +621,6 @@ type WorkspacesCentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.TRAVEL]: { policyID: string; }; - [SCREENS.WORKSPACE.ACCOUNTING]: { - policyID: string; - }; [SCREENS.WORKSPACE.MEMBERS]: { policyID: string; }; diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx index 2c87e8803be6..b09a41f8d180 100644 --- a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -18,6 +18,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; // import useWaitForNavigation from '@hooks/useWaitForNavigation'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import Navigation from '@navigation/Navigation'; import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper'; @@ -25,6 +26,7 @@ import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; function WorkspaceAccountingPage({policy}: WithPolicyProps) { const theme = useTheme(); @@ -141,7 +143,7 @@ function WorkspaceAccountingPage({policy}: WithPolicyProps) { shouldShowRightIcon: true, title: translate('workspace.accounting.import'), wrapperStyle: [styles.sectionMenuItemTopDescription], - onPress: () => {}, + onPress: () => Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_IMPORT.getRoute(policyID)), }, { icon: Expensicons.Send, From 03c74520b7b3bae127ef1ad21a71271278204904 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Tue, 9 Apr 2024 20:11:45 +0300 Subject: [PATCH 74/78] prettier --- src/pages/workspace/accounting/WorkspaceAccountingPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx index b09a41f8d180..6fada466e2bb 100644 --- a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -163,7 +163,7 @@ function WorkspaceAccountingPage({policy}: WithPolicyProps) { }, ]), ], - [translate, theme.spinner, isSyncInProgress, overflowMenu, threeDotsMenuPosition, styles.popoverMenuIcon, threeDotsMenuContainerRef, styles.sectionMenuItemTopDescription], + [styles.sectionMenuItemTopDescription, styles.popoverMenuIcon, translate, isSyncInProgress, theme.spinner, overflowMenu, threeDotsMenuPosition, policyID], ); const headerThreeDotsMenuItems: ThreeDotsMenuProps['menuItems'] = [ From a7b8f4539a60d7b62dd92dcf9c56801eeb077aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Tue, 9 Apr 2024 20:00:41 +0200 Subject: [PATCH 75/78] Fix problem with detecting video progress bar gestures inside modals --- .../VideoPlayerControls/ProgressBar/index.tsx | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/VideoPlayer/VideoPlayerControls/ProgressBar/index.tsx b/src/components/VideoPlayer/VideoPlayerControls/ProgressBar/index.tsx index c9cf2c25d7ad..848664c249b7 100644 --- a/src/components/VideoPlayer/VideoPlayerControls/ProgressBar/index.tsx +++ b/src/components/VideoPlayer/VideoPlayerControls/ProgressBar/index.tsx @@ -1,7 +1,7 @@ import React, {useEffect, useState} from 'react'; import type {LayoutChangeEvent, ViewStyle} from 'react-native'; import type {GestureStateChangeEvent, GestureUpdateEvent, PanGestureChangeEventPayload, PanGestureHandlerEventPayload} from 'react-native-gesture-handler'; -import {Gesture, GestureDetector} from 'react-native-gesture-handler'; +import {Gesture, GestureDetector, GestureHandlerRootView} from 'react-native-gesture-handler'; import Animated, {runOnJS, useAnimatedStyle, useSharedValue} from 'react-native-reanimated'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -71,19 +71,21 @@ function ProgressBar({duration, position, seekPosition}: ProgressBarProps) { const progressBarStyle: ViewStyle = useAnimatedStyle(() => ({width: `${progressWidth.value}%`})); return ( - - - + + + + style={styles.progressBarOutline} + onLayout={onSliderLayout} + > + + - - + + ); } From 544edd804cf002b55ed773c54c8c8061d0d105c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Tue, 9 Apr 2024 21:09:15 +0200 Subject: [PATCH 76/78] Move fix to onbording page --- src/components/OnboardingWelcomeVideo.tsx | 31 ++++++++++--------- .../VideoPlayerControls/ProgressBar/index.tsx | 26 +++++++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/components/OnboardingWelcomeVideo.tsx b/src/components/OnboardingWelcomeVideo.tsx index f38bd4edcc10..257bd1b9c457 100644 --- a/src/components/OnboardingWelcomeVideo.tsx +++ b/src/components/OnboardingWelcomeVideo.tsx @@ -1,6 +1,7 @@ import type {VideoReadyForDisplayEvent} from 'expo-av'; import React, {useCallback, useEffect, useState} from 'react'; import {View} from 'react-native'; +import {GestureHandlerRootView} from 'react-native-gesture-handler'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnboardingLayout from '@hooks/useOnboardingLayout'; @@ -134,22 +135,24 @@ function OnboardingWelcomeVideo() { : {}), }} > - - {getWelcomeVideo()} - - - {translate('onboarding.welcomeVideo.title')} - {translate('onboarding.welcomeVideo.description')} + + + {getWelcomeVideo()} + + + {translate('onboarding.welcomeVideo.title')} + {translate('onboarding.welcomeVideo.description')} + +