Skip to content

Commit

Permalink
Merge pull request #51850 from hoangzinh/51640-handle-errors-graceful…
Browse files Browse the repository at this point in the history
…ly-qbd-setup-page

[QBD] Handle errors gracefully if the setup link cannot be obtained
  • Loading branch information
lakchote authored Nov 6, 2024
2 parents 2699cbe + 1dc585e commit 573162f
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 7 deletions.
6 changes: 6 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2477,6 +2477,10 @@ const translations = {
setupPage: {
title: 'Open this link to connect',
body: 'To complete setup, open the following link on the computer where QuickBooks Desktop is running.',
setupErrorTitle: 'Something went wrong',
setupErrorBody1: "The QuickBooks Desktop connection isn't working at the moment. Please try again later or",
setupErrorBody2: 'if the problem persists.',
setupErrorBodyContactConcierge: 'reach out to Concierge',
},
importDescription: 'Choose which coding configurations to import from QuickBooks Desktop to Expensify.',
classes: 'Classes',
Expand Down Expand Up @@ -3658,6 +3662,8 @@ const translations = {
return "Can't connect to Xero.";
case CONST.POLICY.CONNECTIONS.NAME.NETSUITE:
return "Can't connect to NetSuite.";
case CONST.POLICY.CONNECTIONS.NAME.QBD:
return "Can't connect to QuickBooks Desktop.";
default: {
return "Can't connect to integration.";
}
Expand Down
6 changes: 6 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2502,6 +2502,10 @@ const translations = {
setupPage: {
title: 'Abre este enlace para conectar',
body: 'Para completar la configuración, abre el siguiente enlace en la computadora donde se está ejecutando QuickBooks Desktop.',
setupErrorTitle: '¡Ups! Ha ocurrido un error',
setupErrorBody1: 'La conexión con QuickBooks Desktop no está funcionando en este momento. Por favor, inténtalo de nuevo más tarde o',
setupErrorBody2: 'si el problema persiste.',
setupErrorBodyContactConcierge: 'contacta con Concierge',
},
importDescription: 'Elige que configuraciónes de codificación son importadas desde QuickBooks Desktop a Expensify.',
classes: 'Clases',
Expand Down Expand Up @@ -3663,6 +3667,8 @@ const translations = {
return 'No se puede conectar a Xero.';
case CONST.POLICY.CONNECTIONS.NAME.NETSUITE:
return 'No se puede conectar a NetSuite.';
case CONST.POLICY.CONNECTIONS.NAME.QBD:
return 'No se puede conectar a QuickBooks Desktop.';
default: {
return 'No se ha podido conectar a la integración.';
}
Expand Down
16 changes: 16 additions & 0 deletions src/libs/actions/connections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,21 @@ function isConnectionUnverified(policy: OnyxEntry<Policy>, connectionName: Polic
return !(policy?.connections?.[connectionName]?.lastSync?.isConnected ?? true);
}

function setConnectionError(policyID: string, connectionName: PolicyConnectionName, errorMessage?: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {
connections: {
[connectionName]: {
lastSync: {
isSuccessful: false,
isConnected: false,
errorDate: new Date().toISOString(),
errorMessage,
},
},
},
});
}

function copyExistingPolicyConnection(connectedPolicyID: string, targetPolicyID: string, connectionName: ConnectionName) {
let stageInProgress;
switch (connectionName) {
Expand Down Expand Up @@ -389,4 +404,5 @@ export {
isConnectionUnverified,
isConnectionInProgress,
hasSynchronizationErrorMessage,
setConnectionError,
};
54 changes: 47 additions & 7 deletions src/pages/workspace/accounting/qbd/QuickBooksDesktopSetupPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,22 @@ import CopyTextToClipboard from '@components/CopyTextToClipboard';
import FixedFooter from '@components/FixedFooter';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import Icon from '@components/Icon';
import * as Illustrations from '@components/Icon/Illustrations';
import ImageSVG from '@components/ImageSVG';
import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import {setConnectionError} from '@libs/actions/connections';
import * as QuickbooksDesktop from '@libs/actions/connections/QuickbooksDesktop';
import Navigation from '@libs/Navigation/Navigation';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import * as PolicyAction from '@userActions/Policy/Policy';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';

Expand All @@ -26,20 +32,32 @@ type RequireQuickBooksDesktopModalProps = StackScreenProps<SettingsNavigatorPara
function RequireQuickBooksDesktopModal({route}: RequireQuickBooksDesktopModalProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {environmentURL} = useEnvironment();
const policyID: string = route.params.policyID;
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);
const [codatSetupLink, setCodatSetupLink] = useState<string>('');
const hasResultOfFetchingSetupLink = !!codatSetupLink || hasError;

const ContentWrapper = codatSetupLink ? ({children}: React.PropsWithChildren) => children : FullPageOfflineBlockingView;
const ContentWrapper = hasResultOfFetchingSetupLink ? ({children}: React.PropsWithChildren) => children : FullPageOfflineBlockingView;

const fetchSetupLink = useCallback(() => {
setIsLoading(true);
setHasError(false);
// eslint-disable-next-line rulesdir/no-thenable-actions-in-views
QuickbooksDesktop.getQuickbooksDesktopCodatSetupLink(policyID).then((response) => {
setCodatSetupLink(String(response?.setupUrl ?? ''));
if (response?.jsonCode) {
if (response.jsonCode === CONST.JSON_CODE.SUCCESS) {
setCodatSetupLink(String(response?.setupUrl ?? ''));
} else {
setConnectionError(policyID, CONST.POLICY.CONNECTIONS.NAME.QBD, translate('workspace.qbd.setupPage.setupErrorTitle'));
setHasError(true);
}
}

setIsLoading(false);
});
}, [policyID]);
}, [policyID, translate]);

useEffect(() => {
// Since QBD doesn't support Taxes, we should disable them from the LHN when connecting to QBD
Expand All @@ -52,13 +70,16 @@ function RequireQuickBooksDesktopModal({route}: RequireQuickBooksDesktopModalPro

useNetwork({
onReconnect: () => {
if (codatSetupLink) {
if (hasResultOfFetchingSetupLink) {
return;
}
fetchSetupLink();
},
});

const shouldShowLoading = isLoading || !hasResultOfFetchingSetupLink;
const shouldShowError = !shouldShowLoading && hasError;

return (
<ScreenWrapper
shouldEnablePickerAvoiding={false}
Expand All @@ -71,9 +92,28 @@ function RequireQuickBooksDesktopModal({route}: RequireQuickBooksDesktopModalPro
onBackButtonPress={() => Navigation.dismissModal()}
/>
<ContentWrapper>
{isLoading || !codatSetupLink ? (
<FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />
) : (
{shouldShowLoading && <FullScreenLoadingIndicator style={[styles.flex1, styles.pRelative]} />}
{shouldShowError && (
<View style={[styles.flex1, styles.justifyContentCenter, styles.alignItemsCenter, styles.ph5, styles.mb9]}>
<Icon
src={Illustrations.BrokenMagnifyingGlass}
width={116}
height={168}
/>
<Text style={[styles.textHeadlineLineHeightXXL, styles.mt3]}>{translate('workspace.qbd.setupPage.setupErrorTitle')}</Text>
<Text style={[styles.textSupporting, styles.ph5, styles.mv3, styles.textAlignCenter]}>
{translate('workspace.qbd.setupPage.setupErrorBody1')}{' '}
<TextLink
href={`${environmentURL}/${ROUTES.CONCIERGE}`}
style={styles.link}
>
{translate('workspace.qbd.setupPage.setupErrorBodyContactConcierge')}
</TextLink>{' '}
{translate('workspace.qbd.setupPage.setupErrorBody2')}
</Text>
</View>
)}
{!shouldShowLoading && !shouldShowError && (
<View style={[styles.flex1, styles.ph5]}>
<View style={[styles.alignSelfCenter, styles.computerIllustrationContainer, styles.pv6]}>
<ImageSVG src={Computer} />
Expand Down

0 comments on commit 573162f

Please sign in to comment.