Skip to content

Commit

Permalink
Merge pull request #55049 from s77rt/netsuite-quickstart
Browse files Browse the repository at this point in the history
[NoQA] NSQS
  • Loading branch information
yuwenmemon authored Feb 4, 2025
2 parents e159fc3 + 5137770 commit 1526f42
Show file tree
Hide file tree
Showing 56 changed files with 2,082 additions and 73 deletions.
35 changes: 35 additions & 0 deletions assets/images/integrationicons/netsuite-quickstart-icon-square.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 51 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* eslint-disable @typescript-eslint/naming-convention */
import {add as dateAdd} from 'date-fns';
import {sub as dateSubtract} from 'date-fns/sub';
// eslint-disable-next-line lodash/import-scope
import type {Dictionary} from 'lodash';
import invertBy from 'lodash/invertBy';
import Config from 'react-native-config';
import * as KeyCommand from 'react-native-key-command';
import type {ValueOf} from 'type-fest';
Expand Down Expand Up @@ -2173,6 +2176,31 @@ const CONST = {
'_vietNam',
] as string[],

NSQS_EXPORT_DATE: {
LAST_EXPENSE: 'LAST_EXPENSE',
EXPORTED: 'EXPORTED',
SUBMITTED: 'SUBMITTED',
},

NSQS_INTEGRATION_ENTITY_MAP_TYPES: {
NETSUITE_DEFAULT: 'NETSUITE_DEFAULT',
REPORT_FIELD: 'REPORT_FIELD',
TAG: 'TAG',
},

NSQS_CONFIG: {
AUTO_SYNC: 'autoSync',
SYNC_OPTIONS: {
MAPPING: {
CUSTOMERS: 'syncOptions.mapping.customers',
PROJECTS: 'syncOptions.mapping.projects',
},
},
EXPORTER: 'exporter',
EXPORT_DATE: 'exportDate',
APPROVAL_ACCOUNT: 'approvalAccount',
},

QUICKBOOKS_EXPORT_DATE: {
LAST_EXPENSE: 'LAST_EXPENSE',
REPORT_EXPORTED: 'REPORT_EXPORTED',
Expand Down Expand Up @@ -2659,17 +2687,20 @@ const CONST = {
QBD: 'quickbooksDesktop',
XERO: 'xero',
NETSUITE: 'netsuite',
NSQS: 'netsuiteQuickStart',
SAGE_INTACCT: 'intacct',
},
ROUTE: {
QBO: 'quickbooks-online',
XERO: 'xero',
NETSUITE: 'netsuite',
NSQS: 'nsqs',
SAGE_INTACCT: 'sage-intacct',
QBD: 'quickbooks-desktop',
},
NAME_USER_FRIENDLY: {
netsuite: 'NetSuite',
netsuiteQuickStart: 'NSQS',
quickbooksOnline: 'QuickBooks Online',
quickbooksDesktop: 'QuickBooks Desktop',
xero: 'Xero',
Expand Down Expand Up @@ -2747,6 +2778,12 @@ const CONST = {
NETSUITE_SYNC_EXPENSIFY_REIMBURSED_REPORTS: 'netSuiteSyncExpensifyReimbursedReports',
NETSUITE_SYNC_IMPORT_VENDORS_TITLE: 'netSuiteImportVendorsTitle',
NETSUITE_SYNC_IMPORT_CUSTOM_LISTS_TITLE: 'netSuiteImportCustomListsTitle',
NSQS_SYNC_CONNECTION: 'nsqsSyncConnection',
NSQS_SYNC_ACCOUNTS: 'nsqsSyncAccounts',
NSQS_SYNC_EMPLOYEES: 'nsqsSyncEmployees',
NSQS_SYNC_CUSTOMERS: 'nsqsSyncCustomers',
NSQS_SYNC_PROJECTS: 'nsqsSyncProjects',
NSQS_SYNC_CURRENCY: 'nsqsSyncCurrency',
SAGE_INTACCT_SYNC_CHECK_CONNECTION: 'intacctCheckConnection',
SAGE_INTACCT_SYNC_IMPORT_TITLE: 'intacctImportTitle',
SAGE_INTACCT_SYNC_IMPORT_DATA: 'intacctImportData',
Expand All @@ -2755,6 +2792,19 @@ const CONST = {
SAGE_INTACCT_SYNC_IMPORT_SYNC_REIMBURSED_REPORTS: 'intacctImportSyncBillPayments',
},
SYNC_STAGE_TIMEOUT_MINUTES: 20,

// Map each connection to its designated display connection
get MULTI_CONNECTIONS_MAPPING() {
return {
[this.NAME.NETSUITE]: this.NAME.NETSUITE,
[this.NAME.NSQS]: this.NAME.NETSUITE,
} as Record<ValueOf<typeof this.NAME>, ValueOf<typeof this.NAME> | undefined>;
},

// Get linked connections by the designated display connection
get MULTI_CONNECTIONS_MAPPING_INVERTED() {
return invertBy(this.MULTI_CONNECTIONS_MAPPING) as Dictionary<Array<ValueOf<typeof this.NAME>> | undefined>;
},
},
ACCESS_VARIANTS: {
PAID: 'paid',
Expand Down Expand Up @@ -5045,6 +5095,7 @@ const CONST = {
quickbooksOnline: 'QuickBooks Online',
xero: 'Xero',
netsuite: 'NetSuite',
netsuiteQuickStart: 'NSQS',
intacct: 'Sage Intacct',
quickbooksDesktop: 'QuickBooks Desktop',
},
Expand Down
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@ const ONYXKEYS = {
NETSUITE_TOKEN_INPUT_FORM_DRAFT: 'netsuiteTokenInputFormDraft',
NETSUITE_CUSTOM_FORM_ID_FORM: 'netsuiteCustomFormIDForm',
NETSUITE_CUSTOM_FORM_ID_FORM_DRAFT: 'netsuiteCustomFormIDFormDraft',
NSQS_OAUTH2_FORM: 'nsqsOAuth2Form',
NSQS_OAUTH2_FORM_DRAFT: 'nsqsOAuth2FormDraft',
SAGE_INTACCT_DIMENSION_TYPE_FORM: 'sageIntacctDimensionTypeForm',
SAGE_INTACCT_DIMENSION_TYPE_FORM_DRAFT: 'sageIntacctDimensionTypeFormDraft',
SEARCH_ADVANCED_FILTERS_FORM: 'searchAdvancedFiltersForm',
Expand Down Expand Up @@ -837,6 +839,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.NETSUITE_CUSTOM_SEGMENT_ADD_FORM]: FormTypes.NetSuiteCustomFieldForm;
[ONYXKEYS.FORMS.NETSUITE_TOKEN_INPUT_FORM]: FormTypes.NetSuiteTokenInputForm;
[ONYXKEYS.FORMS.NETSUITE_CUSTOM_FORM_ID_FORM]: FormTypes.NetSuiteCustomFormIDForm;
[ONYXKEYS.FORMS.NSQS_OAUTH2_FORM]: FormTypes.NSQSOAuth2Form;
[ONYXKEYS.FORMS.SAGE_INTACCT_DIMENSION_TYPE_FORM]: FormTypes.SageIntacctDimensionForm;
[ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM]: FormTypes.SearchAdvancedFiltersForm;
[ONYXKEYS.FORMS.TEXT_PICKER_MODAL_FORM]: FormTypes.TextPickerModalForm;
Expand Down
66 changes: 66 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,28 @@ const ROUTES = {
getRoute: (policyID: string, connection?: ValueOf<typeof CONST.POLICY.CONNECTIONS.ROUTE>) =>
`settings/workspaces/${policyID}/accounting/${connection as string}/card-reconciliation/account` as const,
},
WORKSPACE_ACCOUNTING_MULTI_CONNECTION_SELECTOR: {
route: 'settings/workspaces/:policyID/accounting/:connection/connection-selector',
getRoute: (
policyID: string,
connection: ValueOf<typeof CONST.POLICY.CONNECTIONS.ROUTE>,
integrationToDisconnect?: ConnectionName,
shouldDisconnectIntegrationBeforeConnecting?: boolean,
) => {
const searchParams = new URLSearchParams();

if (integrationToDisconnect) {
searchParams.append('integrationToDisconnect', integrationToDisconnect);
}
if (shouldDisconnectIntegrationBeforeConnecting !== undefined) {
searchParams.append('shouldDisconnectIntegrationBeforeConnecting', shouldDisconnectIntegrationBeforeConnecting.toString());
}

const queryParams = searchParams.size ? `?${searchParams.toString()}` : '';

return `settings/workspaces/${policyID}/accounting/${connection}/connection-selector${queryParams}` as const;
},
},
WORKSPACE_CATEGORIES: {
route: 'settings/workspaces/:policyID/categories',
getRoute: (policyID: string | undefined) => {
Expand Down Expand Up @@ -1942,6 +1964,50 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/connections/netsuite/advanced/autosync/accounting-method',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/connections/netsuite/advanced/autosync/accounting-method` as const,
},
POLICY_ACCOUNTING_NSQS_SETUP: {
route: 'settings/workspaces/:policyID/accounting/nsqs/setup',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/setup` as const,
},
POLICY_ACCOUNTING_NSQS_IMPORT: {
route: 'settings/workspaces/:policyID/accounting/nsqs/import',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/import` as const,
},
POLICY_ACCOUNTING_NSQS_IMPORT_CUSTOMERS: {
route: 'settings/workspaces/:policyID/accounting/nsqs/import/customers',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/import/customers` as const,
},
POLICY_ACCOUNTING_NSQS_IMPORT_CUSTOMERS_DISPLAYED_AS: {
route: 'settings/workspaces/:policyID/accounting/nsqs/import/customers/displayed-as',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/import/customers/displayed-as` as const,
},
POLICY_ACCOUNTING_NSQS_IMPORT_PROJECTS: {
route: 'settings/workspaces/:policyID/accounting/nsqs/import/projects',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/import/projects` as const,
},
POLICY_ACCOUNTING_NSQS_IMPORT_PROJECTS_DISPLAYED_AS: {
route: 'settings/workspaces/:policyID/accounting/nsqs/import/projects/displayed-as',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/import/projects/displayed-as` as const,
},
POLICY_ACCOUNTING_NSQS_EXPORT: {
route: 'settings/workspaces/:policyID/accounting/nsqs/export',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/export` as const,
},
POLICY_ACCOUNTING_NSQS_EXPORT_PREFERRED_EXPORTER: {
route: 'settings/workspaces/:policyID/accounting/nsqs/export/preferred-exporter',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/export/preferred-exporter` as const,
},
POLICY_ACCOUNTING_NSQS_EXPORT_DATE: {
route: 'settings/workspaces/:policyID/accounting/nsqs/export/date',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/export/date` as const,
},
POLICY_ACCOUNTING_NSQS_ADVANCED: {
route: 'settings/workspaces/:policyID/accounting/nsqs/advanced',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/advanced` as const,
},
POLICY_ACCOUNTING_NSQS_ADVANCED_APPROVAL_ACCOUNT: {
route: 'settings/workspaces/:policyID/accounting/nsqs/advanced/approval-account',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/nsqs/advanced/approval-account` as const,
},
POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES: {
route: 'settings/workspaces/:policyID/accounting/sage-intacct/prerequisites',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/sage-intacct/prerequisites` as const,
Expand Down
12 changes: 12 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,17 @@ const SCREENS = {
NETSUITE_CUSTOM_FORM_ID: 'Policy_Accounting_NetSuite_Custom_Form_ID',
NETSUITE_AUTO_SYNC: 'Policy_Accounting_NetSuite_Auto_Sync',
NETSUITE_ACCOUNTING_METHOD: 'Policy_Accounting_NetSuite_Accounting_Method',
NSQS_SETUP: 'Policy_Accounting_NSQS_Setup',
NSQS_IMPORT: 'Policy_Accounting_NSQS_Import',
NSQS_IMPORT_CUSTOMERS: 'Policy_Accounting_NSQS_Import_Customers',
NSQS_IMPORT_CUSTOMERS_DISPLAYED_AS: 'Policy_Accounting_NSQS_Import_Customers_Displayed_As',
NSQS_IMPORT_PROJECTS: 'Policy_Accounting_NSQS_Import_Projects',
NSQS_IMPORT_PROJECTS_DISPLAYED_AS: 'Policy_Accounting_NSQS_Import_Projects_Displayed_As',
NSQS_EXPORT: 'Policy_Accounting_NSQS_Export',
NSQS_EXPORT_PREFERRED_EXPORTER: 'Policy_Accounting_NSQS_Export_Preferred_Exporter',
NSQS_EXPORT_DATE: 'Policy_Accounting_NSQS_Export_Date',
NSQS_ADVANCED: 'Policy_Accounting_NSQS_Advanced',
NSQS_ADVANCED_APPROVAL_ACCOUNT: 'Policy_Accounting_NSQS_Advanced_Approval_Account',
SAGE_INTACCT_PREREQUISITES: 'Policy_Accounting_Sage_Intacct_Prerequisites',
ENTER_SAGE_INTACCT_CREDENTIALS: 'Policy_Enter_Sage_Intacct_Credentials',
EXISTING_SAGE_INTACCT_CONNECTIONS: 'Policy_Existing_Sage_Intacct_Connections',
Expand All @@ -454,6 +465,7 @@ const SCREENS = {
SAGE_INTACCT_PAYMENT_ACCOUNT: 'Policy_Accounting_Sage_Intacct_Payment_Account',
CARD_RECONCILIATION: 'Policy_Accounting_Card_Reconciliation',
RECONCILIATION_ACCOUNT_SETTINGS: 'Policy_Accounting_Reconciliation_Account_Settings',
MULTI_CONNECTION_SELECTOR: 'Policy_Accounting_Multi_Connection_Selector',
},
INITIAL: 'Workspace_Initial',
PROFILE: 'Workspace_Profile',
Expand Down
15 changes: 15 additions & 0 deletions src/components/ConnectToNSQSFlow/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {useEffect} from 'react';
import Navigation from '@libs/Navigation/Navigation';
import ROUTES from '@src/ROUTES';
import type {ConnectToNSQSFlowProps} from './types';

function ConnectToNSQSFlow({policyID}: ConnectToNSQSFlowProps) {
useEffect(() => {
Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NSQS_SETUP.getRoute(policyID));
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, []);

return null;
}

export default ConnectToNSQSFlow;
10 changes: 10 additions & 0 deletions src/components/ConnectToNSQSFlow/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type {PolicyConnectionName} from '@src/types/onyx/Policy';

type ConnectToNSQSFlowProps = {
policyID: string;
shouldDisconnectIntegrationBeforeConnecting?: boolean;
integrationToDisconnect?: PolicyConnectionName;
};

// eslint-disable-next-line import/prefer-default-export
export type {ConnectToNSQSFlowProps};
8 changes: 6 additions & 2 deletions src/components/ConnectToNetSuiteFlow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) {
const {translate} = useLocalize();

const hasPoliciesConnectedToNetSuite = !!getAdminPoliciesConnectedToNetSuite()?.length;
const {shouldUseNarrowLayout} = useResponsiveLayout();

// We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to use the correct modal type
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {isSmallScreenWidth} = useResponsiveLayout();

const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false);
const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState<AnchorPosition>({horizontal: 0, vertical: 0});
const {popoverAnchorRefs} = useAccountingContext();
Expand Down Expand Up @@ -57,7 +61,7 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) {
}, []);

if (threeDotsMenuContainerRef) {
if (!shouldUseNarrowLayout) {
if (!isSmallScreenWidth) {
threeDotsMenuContainerRef.current?.measureInWindow((x, y, width, height) => {
const horizontal = x + width;
const vertical = y + height;
Expand Down
4 changes: 2 additions & 2 deletions src/components/ConnectionLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as PolicyUtils from '@libs/PolicyUtils';
import {getPolicy} from '@libs/PolicyUtils';
import type {AccessVariant} from '@pages/workspace/AccessOrNotFoundWrapper';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import type {TranslationPaths} from '@src/languages/types';
Expand Down Expand Up @@ -106,7 +106,7 @@ function ConnectionLayout({
}: ConnectionLayoutProps) {
const {translate} = useLocalize();

const policy = PolicyUtils.getPolicy(policyID);
const policy = getPolicy(policyID);
const isConnectionEmpty = isEmpty(policy?.connections?.[connectionName]);

const renderSelectionContent = useMemo(
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ import ImageCropSquareMask from '@assets/images/image-crop-square-mask.svg';
import Inbox from '@assets/images/inbox.svg';
import Info from '@assets/images/info.svg';
import NetSuiteSquare from '@assets/images/integrationicons/netsuite-icon-square.svg';
import NSQSSquare from '@assets/images/integrationicons/netsuite-quickstart-icon-square.svg';
import QBDSquare from '@assets/images/integrationicons/qbd-icon-square.svg';
import QBOCircle from '@assets/images/integrationicons/qbo-icon-circle.svg';
import QBOSquare from '@assets/images/integrationicons/qbo-icon-square.svg';
Expand Down Expand Up @@ -406,6 +407,7 @@ export {
CheckCircle,
CheckmarkCircle,
NetSuiteSquare,
NSQSSquare,
XeroCircle,
QBOCircle,
Filters,
Expand Down
6 changes: 5 additions & 1 deletion src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {ImageContentFit} from 'expo-image';
import type {ReactElement, ReactNode} from 'react';
import type {ReactElement, ReactNode, Ref} from 'react';
import React, {forwardRef, useContext, useMemo} from 'react';
import type {GestureResponderEvent, StyleProp, TextStyle, ViewStyle} from 'react-native';
import {ActivityIndicator, View} from 'react-native';
Expand Down Expand Up @@ -60,6 +60,10 @@ type NoIcon = {
};

type MenuItemBaseProps = {
/* View ref */
/* eslint-disable-next-line react/no-unused-prop-types */
ref?: Ref<View>;

/** Function to fire when component is pressed */
onPress?: (event: GestureResponderEvent | KeyboardEvent) => void | Promise<void>;

Expand Down
Loading

0 comments on commit 1526f42

Please sign in to comment.