From 36163ca71266b733ca8f304b362d0f16d3e61fe3 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 20 Jan 2025 11:23:20 +0200 Subject: [PATCH 1/3] Fix undefined inside backTo parameter for export accounts --- .../intacct/export/SageIntacctExportPage.tsx | 3 ++- .../export/NetSuiteExportConfigurationPage.tsx | 3 ++- .../qbo/export/QuickbooksExportConfigurationPage.tsx | 3 ++- .../xero/export/XeroExportConfigurationPage.tsx | 3 ++- src/types/utils/isEmptyString.ts | 11 +++++++++++ 5 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 src/types/utils/isEmptyString.ts diff --git a/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx b/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx index 479f43a7bab2..5c4b38715c02 100644 --- a/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx +++ b/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx @@ -14,6 +14,7 @@ import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import isEmptyValue from '@src/types/utils/isEmptyString'; function SageIntacctExportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -22,7 +23,7 @@ function SageIntacctExportPage({policy}: WithPolicyProps) { const route = useRoute>(); const backTo = route?.params?.backTo; const {export: exportConfig, pendingFields, errorFields} = policy?.connections?.intacct?.config ?? {}; - const shouldGoBackToSpecificRoute = exportConfig?.reimbursable === CONST.SAGE_INTACCT_REIMBURSABLE_EXPENSE_TYPE.EXPENSE_REPORT && backTo; + const shouldGoBackToSpecificRoute = exportConfig?.reimbursable === CONST.SAGE_INTACCT_REIMBURSABLE_EXPENSE_TYPE.EXPENSE_REPORT && !isEmptyValue(backTo); const sections = useMemo( () => [ diff --git a/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx b/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx index 8a053b615790..29e44444d285 100644 --- a/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx @@ -37,6 +37,7 @@ import {clearNetSuiteErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import isEmptyValue from '@src/types/utils/isEmptyString'; type MenuItemWithSubscribedSettings = Pick & {subscribedSettings?: string[]}; @@ -54,7 +55,7 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (config?.reimbursableExpensesExportDestination === CONST.NETSUITE_EXPORT_DESTINATION.EXPENSE_REPORT || config?.nonreimbursableExpensesExportDestination === CONST.NETSUITE_EXPORT_DESTINATION.EXPENSE_REPORT) && - backTo; + !isEmptyValue(backTo); const {subsidiaryList, receivableList, taxAccountsList, items} = policy?.connections?.netsuite?.options?.data ?? {}; const selectedSubsidiary = useMemo(() => (subsidiaryList ?? []).find((subsidiary) => subsidiary.internalID === config?.subsidiaryID), [subsidiaryList, config?.subsidiaryID]); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx index 21bd07d33bd5..869dfca92b7f 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx @@ -17,6 +17,7 @@ import {openExternalLink} from '@userActions/Link'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import isEmptyValue from '@src/types/utils/isEmptyString'; function QuickbooksExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); @@ -32,7 +33,7 @@ function QuickbooksExportConfigurationPage({policy}: WithPolicyConnectionsProps) () => qboConfig?.nonReimbursableExpensesExportDestination === CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL, [qboConfig?.nonReimbursableExpensesExportDestination], ); - const shouldGoBackToSpecificRoute = shouldShowVendorMenuItems && backTo; + const shouldGoBackToSpecificRoute = shouldShowVendorMenuItems && !isEmptyValue(backTo); const menuItems = [ { diff --git a/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx b/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx index dad62ccb1848..7b1b2ff1bdb5 100644 --- a/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx @@ -14,6 +14,7 @@ import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; +import isEmptyValue from '@src/types/utils/isEmptyString'; function XeroExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); @@ -24,7 +25,7 @@ function XeroExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const policyOwner = policy?.owner ?? ''; const {export: exportConfiguration, errorFields, pendingFields} = policy?.connections?.xero?.config ?? {}; - const shouldGoBackToSpecificRoute = !exportConfiguration?.nonReimbursableAccount && backTo; + const shouldGoBackToSpecificRoute = !exportConfiguration?.nonReimbursableAccount && !isEmptyValue(backTo); const {bankAccounts} = policy?.connections?.xero?.data ?? {}; const selectedBankAccountName = useMemo(() => { diff --git a/src/types/utils/isEmptyString.ts b/src/types/utils/isEmptyString.ts new file mode 100644 index 000000000000..b5e169a36365 --- /dev/null +++ b/src/types/utils/isEmptyString.ts @@ -0,0 +1,11 @@ +function isEmptyValue(value?: T): boolean { + switch (value) { + case 'undefined': + case 'null': + case '': + return true; + default: + return false; + } +} +export default isEmptyValue; From 10995188ea1797154902452ecf5b78b65e141580 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 20 Jan 2025 11:26:21 +0200 Subject: [PATCH 2/3] check for normal null and undefined as well --- src/types/utils/isEmptyString.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/utils/isEmptyString.ts b/src/types/utils/isEmptyString.ts index b5e169a36365..951ccf923e88 100644 --- a/src/types/utils/isEmptyString.ts +++ b/src/types/utils/isEmptyString.ts @@ -1,4 +1,7 @@ function isEmptyValue(value?: T): boolean { + if (!value) { + return true; + } switch (value) { case 'undefined': case 'null': From 568eab62fe596cb4791fb3e0e3d9d07160cd5f84 Mon Sep 17 00:00:00 2001 From: Nicolay Arefyeu Date: Mon, 20 Jan 2025 13:35:08 +0200 Subject: [PATCH 3/3] move logic to getUrlWithBackToParam --- src/ROUTES.ts | 14 +++++++------- .../intacct/export/SageIntacctExportPage.tsx | 3 +-- .../export/NetSuiteExportConfigurationPage.tsx | 3 +-- .../export/QuickbooksExportConfigurationPage.tsx | 3 +-- .../xero/export/XeroExportConfigurationPage.tsx | 3 +-- src/types/utils/isEmptyString.ts | 14 -------------- 6 files changed, 11 insertions(+), 29 deletions(-) delete mode 100644 src/types/utils/isEmptyString.ts diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 7bf1bf1c9e07..ca869eb54d4b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -13,8 +13,8 @@ import type AssertTypesNotEqual from './types/utils/AssertTypesNotEqual'; /** * Builds a URL with an encoded URI component for the `backTo` param which can be added to the end of URLs */ -function getUrlWithBackToParam(url: TUrl, backTo?: string): `${TUrl}` { - const backToParam = backTo ? (`${url.includes('?') ? '&' : '?'}backTo=${encodeURIComponent(backTo)}` as const) : ''; +function getUrlWithBackToParam(url: TUrl, backTo?: string, shouldEncodeURIComponent = true): `${TUrl}` { + const backToParam = backTo ? (`${url.includes('?') ? '&' : '?'}backTo=${shouldEncodeURIComponent ? encodeURIComponent(backTo) : backTo}` as const) : ''; return `${url}${backToParam}` as `${TUrl}`; } @@ -777,7 +777,7 @@ const ROUTES = { }, POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export', - getRoute: (policyID: string, backTo?: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/export?backTo=${backTo}` as const, + getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/accounting/quickbooks-online/export` as const, backTo, false), }, POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/export/company-card-expense-account', @@ -1270,7 +1270,7 @@ const ROUTES = { WORKSPACE_COMPANY_CARD_EXPORT: { route: 'settings/workspaces/:policyID/company-cards/:bank/:cardID/edit/export', getRoute: (policyID: string, cardID: string, bank: string, backTo?: string) => - `settings/workspaces/${policyID}/company-cards/${bank}/${cardID}/edit/export?backTo=${backTo}` as const, + getUrlWithBackToParam(`settings/workspaces/${policyID}/company-cards/${bank}/${cardID}/edit/export`, backTo, false), }, WORKSPACE_EXPENSIFY_CARD: { route: 'settings/workspaces/:policyID/expensify-card', @@ -1562,7 +1562,7 @@ const ROUTES = { }, POLICY_ACCOUNTING_XERO_EXPORT: { route: 'settings/workspaces/:policyID/accounting/xero/export', - getRoute: (policyID: string, backTo?: string) => `settings/workspaces/${policyID}/accounting/xero/export?backTo=${backTo}` as const, + getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/accounting/xero/export` as const, backTo, false), }, POLICY_ACCOUNTING_XERO_PREFERRED_EXPORTER_SELECT: { route: 'settings/workspaces/:policyID/connections/xero/export/preferred-exporter/select', @@ -1687,7 +1687,7 @@ const ROUTES = { }, POLICY_ACCOUNTING_NETSUITE_EXPORT: { route: 'settings/workspaces/:policyID/connections/netsuite/export/', - getRoute: (policyID: string, backTo?: string) => `settings/workspaces/${policyID}/connections/netsuite/export?backTo=${backTo}` as const, + getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/connections/netsuite/export/` as const, backTo, false), }, POLICY_ACCOUNTING_NETSUITE_PREFERRED_EXPORTER_SELECT: { route: 'settings/workspaces/:policyID/connections/netsuite/export/preferred-exporter/select', @@ -1825,7 +1825,7 @@ const ROUTES = { }, POLICY_ACCOUNTING_SAGE_INTACCT_EXPORT: { route: 'settings/workspaces/:policyID/accounting/sage-intacct/export', - getRoute: (policyID: string, backTo?: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/export?backTo=${backTo}` as const, + getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/accounting/sage-intacct/export` as const, backTo, false), }, POLICY_ACCOUNTING_SAGE_INTACCT_PREFERRED_EXPORTER: { route: 'settings/workspaces/:policyID/accounting/sage-intacct/export/preferred-exporter', diff --git a/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx b/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx index 5c4b38715c02..479f43a7bab2 100644 --- a/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx +++ b/src/pages/workspace/accounting/intacct/export/SageIntacctExportPage.tsx @@ -14,7 +14,6 @@ import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import isEmptyValue from '@src/types/utils/isEmptyString'; function SageIntacctExportPage({policy}: WithPolicyProps) { const {translate} = useLocalize(); @@ -23,7 +22,7 @@ function SageIntacctExportPage({policy}: WithPolicyProps) { const route = useRoute>(); const backTo = route?.params?.backTo; const {export: exportConfig, pendingFields, errorFields} = policy?.connections?.intacct?.config ?? {}; - const shouldGoBackToSpecificRoute = exportConfig?.reimbursable === CONST.SAGE_INTACCT_REIMBURSABLE_EXPENSE_TYPE.EXPENSE_REPORT && !isEmptyValue(backTo); + const shouldGoBackToSpecificRoute = exportConfig?.reimbursable === CONST.SAGE_INTACCT_REIMBURSABLE_EXPENSE_TYPE.EXPENSE_REPORT && backTo; const sections = useMemo( () => [ diff --git a/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx b/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx index 29e44444d285..8a053b615790 100644 --- a/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx @@ -37,7 +37,6 @@ import {clearNetSuiteErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import isEmptyValue from '@src/types/utils/isEmptyString'; type MenuItemWithSubscribedSettings = Pick & {subscribedSettings?: string[]}; @@ -55,7 +54,7 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing (config?.reimbursableExpensesExportDestination === CONST.NETSUITE_EXPORT_DESTINATION.EXPENSE_REPORT || config?.nonreimbursableExpensesExportDestination === CONST.NETSUITE_EXPORT_DESTINATION.EXPENSE_REPORT) && - !isEmptyValue(backTo); + backTo; const {subsidiaryList, receivableList, taxAccountsList, items} = policy?.connections?.netsuite?.options?.data ?? {}; const selectedSubsidiary = useMemo(() => (subsidiaryList ?? []).find((subsidiary) => subsidiary.internalID === config?.subsidiaryID), [subsidiaryList, config?.subsidiaryID]); diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx index 869dfca92b7f..21bd07d33bd5 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportConfigurationPage.tsx @@ -17,7 +17,6 @@ import {openExternalLink} from '@userActions/Link'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import isEmptyValue from '@src/types/utils/isEmptyString'; function QuickbooksExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); @@ -33,7 +32,7 @@ function QuickbooksExportConfigurationPage({policy}: WithPolicyConnectionsProps) () => qboConfig?.nonReimbursableExpensesExportDestination === CONST.QUICKBOOKS_NON_REIMBURSABLE_EXPORT_ACCOUNT_TYPE.VENDOR_BILL, [qboConfig?.nonReimbursableExpensesExportDestination], ); - const shouldGoBackToSpecificRoute = shouldShowVendorMenuItems && !isEmptyValue(backTo); + const shouldGoBackToSpecificRoute = shouldShowVendorMenuItems && backTo; const menuItems = [ { diff --git a/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx b/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx index 7b1b2ff1bdb5..dad62ccb1848 100644 --- a/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/xero/export/XeroExportConfigurationPage.tsx @@ -14,7 +14,6 @@ import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import isEmptyValue from '@src/types/utils/isEmptyString'; function XeroExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); @@ -25,7 +24,7 @@ function XeroExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const policyOwner = policy?.owner ?? ''; const {export: exportConfiguration, errorFields, pendingFields} = policy?.connections?.xero?.config ?? {}; - const shouldGoBackToSpecificRoute = !exportConfiguration?.nonReimbursableAccount && !isEmptyValue(backTo); + const shouldGoBackToSpecificRoute = !exportConfiguration?.nonReimbursableAccount && backTo; const {bankAccounts} = policy?.connections?.xero?.data ?? {}; const selectedBankAccountName = useMemo(() => { diff --git a/src/types/utils/isEmptyString.ts b/src/types/utils/isEmptyString.ts deleted file mode 100644 index 951ccf923e88..000000000000 --- a/src/types/utils/isEmptyString.ts +++ /dev/null @@ -1,14 +0,0 @@ -function isEmptyValue(value?: T): boolean { - if (!value) { - return true; - } - switch (value) { - case 'undefined': - case 'null': - case '': - return true; - default: - return false; - } -} -export default isEmptyValue;