Skip to content
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2786,6 +2786,7 @@ const ROUTES = {
SETTINGS_TROUBLESHOOT: 'settings/troubleshoot',
SETTINGS_TROUBLESHOOT_SERVER: 'settings/troubleshoot/server',
SETTINGS_HELP: 'settings/help',
SETTINGS_HELP_TALK_TO_HUMAN: 'settings/help/talk-to-human',

SETTINGS_SAVE_THE_WORLD: 'settings/teachersunite',
SETTINGS_SAVE_THE_WORLD_ADD_PAYMENT_CARD: 'settings/teachersunite/add-payment-card',
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const SCREENS = {
TROUBLESHOOT: 'Settings_Troubleshoot',
TROUBLESHOOT_SERVER: 'Settings_Troubleshoot_Server',
HELP: 'Settings_Help',
HELP_TALK_TO_HUMAN: 'Settings_Help_TalkToHuman',
EMAIL_ISSUE: 'Settings_Email_Issue',
DYNAMIC_VERIFY_ACCOUNT: 'Dynamic_Verify_Account',
DYNAMIC_ADD_BANK_ACCOUNT_VERIFY_ACCOUNT: 'Dynamic_Add_Bank_Account_Verify_Account',
Expand Down
32 changes: 32 additions & 0 deletions src/hooks/useOpenSupportTicket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Growl from '@libs/Growl';
import Navigation from '@libs/Navigation/Navigation';

import {isNoSupportRepAvailableResponse, openSupportTicket} from '@userActions/Report';

import useLocalize from './useLocalize';
import useOpenConciergeAnywhere from './useOpenConciergeAnywhere';

/**
* Returns a callback that opens a support ticket, falling back to Concierge when no support rep is free.
* Shared by the Help page row and the Talk to a human route so both behave the same.
*/
function useOpenSupportTicket() {
const {translate} = useLocalize();
const {openConciergeAnywhere} = useOpenConciergeAnywhere();

const openSupportTicketOrConcierge = () =>
openSupportTicket()
.then((response) => {
if (!isNoSupportRepAvailableResponse(response)) {
return;
}

Growl.error(translate('supportTicket.noSupportRepAvailable'));
Navigation.goBack(undefined, {afterTransition: () => openConciergeAnywhere({forceConcierge: true})});
})
.catch(() => undefined);

return {openSupportTicketOrConcierge};
}

export default useOpenSupportTicket;
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const CENTRAL_PANE_SETTINGS_SCREENS = {
[SCREENS.SETTINGS.AGENTS.ROOT]: withAgentAccessDenied(() => require<ReactComponentModule>('../../../../pages/settings/Agents/AgentsPage').default),
[SCREENS.SETTINGS.RULES.ROOT]: () => require<ReactComponentModule>('../../../../pages/settings/Rules/ExpenseRulesPage').default,
[SCREENS.SETTINGS.HELP]: () => require<ReactComponentModule>('../../../../pages/settings/HelpPage/HelpPage').default,
[SCREENS.SETTINGS.HELP_TALK_TO_HUMAN]: () => require<ReactComponentModule>('../../../../pages/settings/HelpPage/TalkToHumanPage').default,
[SCREENS.SETTINGS.ABOUT]: () => require<ReactComponentModule>('../../../../pages/settings/AboutPage/AboutPage').default,
[SCREENS.SETTINGS.TROUBLESHOOT]: () => require<ReactComponentModule>('../../../../pages/settings/Troubleshoot/TroubleshootPage').default,
[SCREENS.SETTINGS.SAVE_THE_WORLD]: () => require<ReactComponentModule>('../../../../pages/TeachersUnite/SaveTheWorldPage').default,
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2469,6 +2469,10 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
path: ROUTES.SETTINGS_HELP,
exact: true,
},
[SCREENS.SETTINGS.HELP_TALK_TO_HUMAN]: {
path: ROUTES.SETTINGS_HELP_TALK_TO_HUMAN,
exact: true,
},
[SCREENS.SETTINGS.TROUBLESHOOT]: {
path: ROUTES.SETTINGS_TROUBLESHOOT,
exact: true,
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ type SettingsSplitNavigatorParamList = {
[SCREENS.SETTINGS.RULES.ROOT]: undefined;
[SCREENS.SETTINGS.ABOUT]: undefined;
[SCREENS.SETTINGS.HELP]: undefined;
[SCREENS.SETTINGS.HELP_TALK_TO_HUMAN]: undefined;
[SCREENS.SETTINGS.TROUBLESHOOT]: undefined;
[SCREENS.SETTINGS.SAVE_THE_WORLD]: undefined;
[SCREENS.SETTINGS.SUBSCRIPTION.ROOT]?: {
Expand Down
18 changes: 3 additions & 15 deletions src/pages/settings/HelpPage/HelpPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import useOpenConciergeAnywhere from '@hooks/useOpenConciergeAnywhere';
import useOpenSupportTicket from '@hooks/useOpenSupportTicket';
import usePersonalDetailByLogin from '@hooks/usePersonalDetailByLogin';
import {useAllPersonalDetails} from '@hooks/usePersonalDetails';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
Expand All @@ -21,8 +22,7 @@ import useThemeStyles from '@hooks/useThemeStyles';

import {openHelpPage} from '@libs/actions/Help';
import {openExternalLink} from '@libs/actions/Link';
import {isNoSupportRepAvailableResponse, navigateToAndOpenReportWithAccountIDs, openSupportTicket} from '@libs/actions/Report';
import Growl from '@libs/Growl';
import {navigateToAndOpenReportWithAccountIDs} from '@libs/actions/Report';
import Navigation from '@libs/Navigation/Navigation';

import colors from '@styles/theme/colors';
Expand Down Expand Up @@ -64,21 +64,9 @@ function HelpPage() {
const [conciergeChat] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${conciergeReportID}`);
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
const {openConciergeAnywhere} = useOpenConciergeAnywhere();
const {openSupportTicketOrConcierge} = useOpenSupportTicket();
const {isOffline} = useNetwork();

const openSupportTicketOrConcierge = () => {
openSupportTicket()
.then((response) => {
if (!isNoSupportRepAvailableResponse(response)) {
return;
}

Growl.error(translate('supportTicket.noSupportRepAvailable'));
Navigation.goBack(undefined, {afterTransition: () => openConciergeAnywhere({forceConcierge: true})});
})
.catch(() => undefined);
};

// Remove the row's accessibility grouping so native (iOS/Android) screen readers can announce the nested
// Book a call button as its own element; on web this prop is a no-op and the button is reached via keyboard Tab instead
const shouldBeAccessibleWithBookCallButton = (calendarLink: string | undefined) => !calendarLink;
Expand Down
56 changes: 56 additions & 0 deletions src/pages/settings/HelpPage/TalkToHumanPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';

import useNetwork from '@hooks/useNetwork';
import useOpenSupportTicket from '@hooks/useOpenSupportTicket';

import Navigation from '@libs/Navigation/Navigation';
import navigationRef from '@libs/Navigation/navigationRef';

import ROUTES from '@src/ROUTES';

import React, {useEffect, useRef} from 'react';

/**
* Opens a support ticket straight away, so the Talk to a human link in a Concierge message reaches a
* person without the customer having to find the row on the Help page.
*/
function TalkToHumanPage() {
const {openSupportTicketOrConcierge} = useOpenSupportTicket();
const {isOffline} = useNetwork();
const hasRequestedTicket = useRef(false);

useEffect(() => {
// Creating a ticket needs the network, so send the customer to the Help page to try again once they are back online.
if (isOffline) {
Navigation.goBack(ROUTES.SETTINGS_HELP);
return;
}

// A remount would otherwise open a second ticket that a support rep has to close.
if (hasRequestedTicket.current) {
return;
}
hasRequestedTicket.current = true;

// Leave this route before creating the ticket. The ticket stores the route it was opened from as its back target,
// so opening it from here would make Back return to this loader instead of the chat the link was pressed in.
// A direct link has nothing behind it to return to and goBack would then skip afterTransition, so it falls back
// to the Help page and opens the ticket from there.
const fallbackRoute = navigationRef.current?.canGoBack() ? undefined : ROUTES.SETTINGS_HELP;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Ignore the injected sidebar when detecting direct links

On a narrow-layout cold load of settings/help/talk-to-human, SplitRouter.adaptStateIfNecessary() prepends SCREENS.SETTINGS.ROOT (the cold-root behavior is also encoded in tests/navigation/GoBackTests.tsx), so this broad canGoBack() check returns true even though there is no originating page. The fallback is therefore omitted, the first Back pops only to Settings root, and openSupportTicket() records settings rather than the intended Help page as the ticket's Back target; determine whether there is outer/in-app history without counting the split navigator's injected sidebar.

Useful? React with 👍 / 👎.

Navigation.goBack(fallbackRoute, {
afterTransition: () => {
openSupportTicketOrConcierge();
},
});

// openSupportTicketOrConcierge is a new function on every render and hasRequestedTicket already stops a second
// request, so this effect only needs to react to the connection changing.
// eslint-disable-next-line react-hooks/exhaustive-deps
Comment thread
ishpaul777 marked this conversation as resolved.
}, [isOffline]);

return <FullScreenLoadingIndicator shouldUseGoBackButton />;
}

TalkToHumanPage.displayName = 'TalkToHumanPage';

export default TalkToHumanPage;
Loading