Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 89 additions & 74 deletions src/pages/workspace/accounting/qbd/QuickBooksDesktopSetupPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useState} from 'react';
import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import ActivityIndicator from '@components/ActivityIndicator';
import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
Expand Down Expand Up @@ -28,102 +28,71 @@ import type SCREENS from '@src/SCREENS';

type RequireQuickBooksDesktopModalProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL>;

type SetupLinkFetchStatus = {status: 'loading'} | {status: 'success'; setupLink: string} | {status: 'error'};

function RequireQuickBooksDesktopModal({route}: RequireQuickBooksDesktopModalProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const {environmentURL} = useEnvironment();
const illustrations = useMemoizedLazyIllustrations(['BrokenMagnifyingGlass', 'LaptopWithSecondScreenSync']);
const policyID: string = route.params.policyID;
const [hasError, setHasError] = useState(false);
const [codatSetupLink, setCodatSetupLink] = useState<string>('');
const hasResultOfFetchingSetupLink = !!codatSetupLink || hasError;
const [setupLinkFetchStatus, setSetupLinkFetchStatus] = useState<SetupLinkFetchStatus>({status: 'loading'});

const isLoading = setupLinkFetchStatus.status === 'loading';
const shouldShowError = setupLinkFetchStatus.status === 'error';
const codatSetupLink = setupLinkFetchStatus.status === 'success' ? setupLinkFetchStatus.setupLink : '';

const ContentWrapper = isLoading
? ({children}: React.PropsWithChildren) => <FullPageOfflineBlockingView addBottomSafeAreaPadding>{children}</FullPageOfflineBlockingView>
: ({children}: React.PropsWithChildren) => children;

useEffect(() => {
let shouldIgnoreResponse = false;

// Since QBD doesn't support Taxes, we should disable them from the LHN when connecting to QBD
enablePolicyTaxes(policyID, false);

setSetupLinkFetchStatus({status: 'loading'});

const fetchSetupLink = useCallback(() => {
setHasError(false);
// eslint-disable-next-line rulesdir/no-thenable-actions-in-views
getQuickbooksDesktopCodatSetupLink(policyID).then((response) => {
if (!response?.jsonCode) {
if (shouldIgnoreResponse || !response?.jsonCode) {
return;
}

if (response.jsonCode === CONST.JSON_CODE.SUCCESS) {
setCodatSetupLink(String(response?.setupUrl ?? ''));
setSetupLinkFetchStatus({status: 'success', setupLink: String(response?.setupUrl ?? '')});
} else {
setConnectionError(policyID, CONST.POLICY.CONNECTIONS.NAME.QBD, translate('workspace.qbd.setupPage.setupErrorTitle'));
setHasError(true);
setSetupLinkFetchStatus({status: 'error'});
}
});
}, [policyID, translate]);

useEffect(() => {
// Since QBD doesn't support Taxes, we should disable them from the LHN when connecting to QBD
enablePolicyTaxes(policyID, false);

fetchSetupLink();
// disabling this rule, as we want this to run only on the first render
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return () => {
shouldIgnoreResponse = true;
};
}, [policyID, translate]);

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

const shouldShowError = hasError;

const children = (
<>
{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>
<View style={[styles.renderHTML, styles.ph5, styles.mv3]}>
<RenderHTML html={translate('workspace.qbd.setupPage.setupErrorBody', {conciergeLink: `${environmentURL}/${ROUTES.CONCIERGE}`})} />
</View>
</View>
)}
{!shouldShowError && (
<View style={[styles.flex1, styles.ph5]}>
<View style={[styles.alignSelfCenter, styles.computerIllustrationContainer, styles.pv6]}>
<ImageSVG src={illustrations.LaptopWithSecondScreenSync} />
</View>
// eslint-disable-next-line rulesdir/no-thenable-actions-in-views
getQuickbooksDesktopCodatSetupLink(policyID).then((response) => {
if (!response?.jsonCode) {
return;
}

<Text style={[styles.textHeadlineH1, styles.pt5]}>{translate('workspace.qbd.setupPage.title')}</Text>
<Text style={[styles.textSupporting, styles.textNormal, styles.pt4]}>{translate('workspace.qbd.setupPage.body')}</Text>
<View style={[styles.qbdSetupLinkBox, styles.mt5]}>
{!hasResultOfFetchingSetupLink ? (
<ActivityIndicator />
) : (
<CopyTextToClipboard
text={codatSetupLink}
textStyles={[styles.textSupporting]}
/>
)}
</View>
<FixedFooter
style={[styles.mtAuto, styles.ph0]}
addBottomSafeAreaPadding
>
<Button
success
text={translate('common.done')}
onPress={() => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_TRIGGER_FIRST_SYNC.getRoute(policyID))}
pressOnEnter
large
/>
</FixedFooter>
</View>
)}
</>
);
if (response.jsonCode === CONST.JSON_CODE.SUCCESS) {
setSetupLinkFetchStatus({status: 'success', setupLink: String(response?.setupUrl ?? '')});
} else {
setConnectionError(policyID, CONST.POLICY.CONNECTIONS.NAME.QBD, translate('workspace.qbd.setupPage.setupErrorTitle'));
setSetupLinkFetchStatus({status: 'error'});
}
});
},
});

return (
<ScreenWrapper
Expand All @@ -136,7 +105,53 @@ function RequireQuickBooksDesktopModal({route}: RequireQuickBooksDesktopModalPro
shouldShowBackButton
onBackButtonPress={() => Navigation.dismissModal()}
/>
{hasResultOfFetchingSetupLink ? children : <FullPageOfflineBlockingView addBottomSafeAreaPadding>{children}</FullPageOfflineBlockingView>}
<ContentWrapper>
{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>
<View style={[styles.renderHTML, styles.ph5, styles.mv3]}>
<RenderHTML html={translate('workspace.qbd.setupPage.setupErrorBody', {conciergeLink: `${environmentURL}/${ROUTES.CONCIERGE}`})} />
</View>
</View>
)}
{!shouldShowError && (
<View style={[styles.flex1, styles.ph5]}>
<View style={[styles.alignSelfCenter, styles.computerIllustrationContainer, styles.pv6]}>
<ImageSVG src={illustrations.LaptopWithSecondScreenSync} />
</View>

<Text style={[styles.textHeadlineH1, styles.pt5]}>{translate('workspace.qbd.setupPage.title')}</Text>
<Text style={[styles.textSupporting, styles.textNormal, styles.pt4]}>{translate('workspace.qbd.setupPage.body')}</Text>
<View style={[styles.qbdSetupLinkBox, styles.mt5]}>
{isLoading ? (
<ActivityIndicator />
) : (
<CopyTextToClipboard
text={codatSetupLink}
textStyles={[styles.textSupporting]}
/>
)}
</View>
<FixedFooter
style={[styles.mtAuto, styles.ph0]}
addBottomSafeAreaPadding
>
<Button
success
text={translate('common.done')}
onPress={() => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_DESKTOP_TRIGGER_FIRST_SYNC.getRoute(policyID))}
pressOnEnter
large
/>
</FixedFooter>
</View>
)}
</ContentWrapper>
</ScreenWrapper>
);
}
Expand Down
Loading