Skip to content

Commit

Permalink
feat: reconnect integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
kosmydel committed Jul 11, 2024
1 parent 233a37a commit 43e5fe1
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
10 changes: 9 additions & 1 deletion src/libs/actions/connections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,12 @@ function getSynchronizationErrorMessage(policy: OnyxEntry<Policy>, connectionNam
}
}

export {removePolicyConnection, updatePolicyConnectionConfig, updateManyPolicyConnectionConfigs, getSynchronizationErrorMessage, syncConnection};
function isAuthenticationError(policy: OnyxEntry<Policy>, connectionName: PolicyConnectionName) {
if (connectionName === CONST.POLICY.CONNECTIONS.NAME.NETSUITE) {
return false;
}
const connection = policy?.connections?.[connectionName];
return connection?.lastSync?.isAuthenticationError === true;
}

export {removePolicyConnection, updatePolicyConnectionConfig, updateManyPolicyConnectionConfigs, getSynchronizationErrorMessage, syncConnection, isAuthenticationError};
51 changes: 42 additions & 9 deletions src/pages/workspace/accounting/PolicyAccountingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,23 @@ import ScrollView from '@components/ScrollView';
import Section from '@components/Section';
import ThreeDotsMenu from '@components/ThreeDotsMenu';
import type ThreeDotsMenuProps from '@components/ThreeDotsMenu/types';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import usePermissions from '@hooks/usePermissions';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {getSynchronizationErrorMessage, removePolicyConnection, syncConnection} from '@libs/actions/connections';
import {getSynchronizationErrorMessage, isAuthenticationError, removePolicyConnection, syncConnection} from '@libs/actions/connections';
import {getXeroSetupLink} from '@libs/actions/connections/ConnectToXero';
import getQuickBooksOnlineSetupLink from '@libs/actions/connections/QuickBooksOnline';
import {findCurrentXeroOrganization, getCurrentXeroOrganizationName, getIntegrationLastSuccessfulDate, getXeroTenants} from '@libs/PolicyUtils';
import Navigation from '@navigation/Navigation';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
import type {AnchorPosition} from '@styles/index';
import * as Link from '@userActions/Link';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand Down Expand Up @@ -137,11 +141,25 @@ function accountingIntegrationData(
}
}

function reconnectPolicyAccountingIntegration(policyID: string, environmentURL: string, integration: PolicyConnectionName) {
switch (integration) {
case CONST.POLICY.CONNECTIONS.NAME.QBO:
Link.openLink(getQuickBooksOnlineSetupLink(policyID), environmentURL);
break;
case CONST.POLICY.CONNECTIONS.NAME.XERO:
Link.openLink(getXeroSetupLink(policyID), environmentURL);
break;
default:
break;
}
}

function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccountingPageProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate, datetimeToRelative: getDatetimeToRelative} = useLocalize();
const {isOffline} = useNetwork();
const {environmentURL} = useEnvironment();
const {canUseNetSuiteIntegration, canUseSageIntacctIntegration} = usePermissions();
const {isSmallScreenWidth, windowWidth} = useWindowDimensions();
const [threeDotsMenuPosition, setThreeDotsMenuPosition] = useState<AnchorPosition>({horizontal: 0, vertical: 0});
Expand All @@ -162,6 +180,8 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting
);

const connectedIntegration = accountingIntegrations.find((integration) => !!policy?.connections?.[integration]) ?? connectionSyncProgress?.connectionName;
const synchronizationError = connectedIntegration && getSynchronizationErrorMessage(policy, connectedIntegration, isSyncInProgress);
const shouldShowEnterCredentials = connectedIntegration && !!synchronizationError && isAuthenticationError(policy, connectedIntegration);
const policyID = policy?.id ?? '-1';
const successfulDate = getIntegrationLastSuccessfulDate(connectedIntegration ? policy?.connections?.[connectedIntegration] : undefined);

Expand All @@ -177,19 +197,32 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting

const overflowMenu: ThreeDotsMenuProps['menuItems'] = useMemo(
() => [
{
icon: Expensicons.Sync,
text: translate('workspace.accounting.syncNow'),
onSelected: () => syncConnection(policyID, connectedIntegration),
disabled: isOffline,
},
...(!shouldShowEnterCredentials
? [
{
icon: Expensicons.Sync,
text: translate('workspace.accounting.syncNow'),
onSelected: () => syncConnection(policyID, connectedIntegration),
disabled: isOffline,
},
]
: [
{
icon: Expensicons.Key,
text: translate('workspace.accounting.enterCredentials'),
onSelected: () => reconnectPolicyAccountingIntegration(policyID, environmentURL, connectedIntegration),
disabled: isOffline,
iconRight: Expensicons.NewWindow,
shouldShowRightIcon: true,
},
]),
{
icon: Expensicons.Trashcan,
text: translate('workspace.accounting.disconnect'),
onSelected: () => setIsDisconnectModalOpen(true),
},
],
[translate, policyID, isOffline, connectedIntegration],
[isAuthenticationError, translate, isOffline, policyID, connectedIntegration, environmentURL],

Check warning on line 225 in src/pages/workspace/accounting/PolicyAccountingPage.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint

React Hook useMemo has a missing dependency: 'shouldShowEnterCredentials'. Either include it or remove the dependency array. Outer scope values like 'isAuthenticationError' aren't valid dependencies because mutating them doesn't re-render the component
);

useEffect(() => {
Expand Down Expand Up @@ -219,7 +252,6 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting
if (!connectedIntegration) {
return [];
}
const synchronizationError = getSynchronizationErrorMessage(policy, connectedIntegration, isSyncInProgress);
const shouldShowSynchronizationError = !!synchronizationError;
const integrationData = accountingIntegrationData(connectedIntegration, policyID, translate);
const iconProps = integrationData?.icon ? {icon: integrationData.icon, iconType: CONST.ICON_TYPE_AVATAR} : {};
Expand Down Expand Up @@ -334,6 +366,7 @@ function PolicyAccountingPage({policy, connectionSyncProgress}: PolicyAccounting
policy,
isSyncInProgress,
connectedIntegration,
synchronizationError,
policyID,
translate,
styles.sectionMenuItemTopDescription,
Expand Down

0 comments on commit 43e5fe1

Please sign in to comment.