diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-help-center.php b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-help-center.php
index 42aab9f212f15..6a029e99ddeda 100644
--- a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-help-center.php
+++ b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-help-center.php
@@ -207,8 +207,12 @@ public function register_rest_api() {
$controller = new WP_REST_Help_Center_Forum();
$controller->register_rest_route();
- require_once __DIR__ . '/class-wp-rest-help-center-support-history.php';
- $controller = new WP_REST_Help_Center_Support_History();
+ require_once __DIR__ . '/class-wp-rest-help-center-support-activity.php';
+ $controller = new WP_REST_Help_Center_Support_Activity();
+ $controller->register_rest_route();
+
+ require_once __DIR__ . '/class-wp-rest-help-center-user-fields.php';
+ $controller = new WP_REST_Help_Center_User_Fields();
$controller->register_rest_route();
}
/**
diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-authenticate.php b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-authenticate.php
index 44976558f3bb2..c47826d21d5f5 100644
--- a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-authenticate.php
+++ b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-authenticate.php
@@ -32,16 +32,37 @@ public function register_rest_route() {
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'get_chat_authentication' ),
'permission_callback' => array( $this, 'permission_callback' ),
+ 'args' => array(
+ 'type' => array(
+ 'type' => 'string',
+ 'default' => 'happychat',
+ 'required' => false,
+ ),
+ 'test_mode' => array(
+ 'type' => 'boolean',
+ 'default' => false,
+ 'required' => false,
+ ),
+ ),
)
);
}
/**
* Callback to authorize user for chat.
+ *
+ * @param \WP_REST_Request $request The request sent to the API.
+ *
+ * @return WP_REST_Response
*/
- public function get_chat_authentication() {
+ public function get_chat_authentication( \WP_REST_Request $request ) {
+ $query_parameters = array(
+ 'test_mode' => $request['test_mode'],
+ 'type' => $request['type'],
+ );
+
$body = Client::wpcom_json_api_request_as_user(
- 'help/authenticate/chat',
+ 'help/authenticate/chat?' . http_build_query( $query_parameters ),
'2',
array(
'method' => 'POST',
diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-activity.php b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-activity.php
new file mode 100644
index 0000000000000..10cdc0cd14c6f
--- /dev/null
+++ b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-activity.php
@@ -0,0 +1,53 @@
+namespace = 'help-center';
+ $this->rest_base = '/support-activity';
+ }
+
+ /**
+ * Register available routes.
+ */
+ public function register_rest_route() {
+ register_rest_route(
+ $this->namespace,
+ $this->rest_base,
+ array(
+ 'methods' => \WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_support_activity' ),
+ 'permission_callback' => 'is_user_logged_in',
+ )
+ );
+ }
+
+ /**
+ * Get support activity through Jetpack.
+ */
+ public function get_support_activity() {
+ $body = Client::wpcom_json_api_request_as_user( '/support-activity' );
+
+ if ( is_wp_error( $body ) ) {
+ return $body;
+ }
+
+ $response = json_decode( wp_remote_retrieve_body( $body ) );
+
+ return rest_ensure_response( $response );
+ }
+}
diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-availability.php b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-availability.php
index c2817c86dfed2..43df6f3a6d25d 100644
--- a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-availability.php
+++ b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-availability.php
@@ -44,6 +44,26 @@ public function register_rest_route() {
'permission_callback' => array( $this, 'permission_callback' ),
)
);
+
+ register_rest_route(
+ $this->namespace,
+ $this->rest_base . '/messaging',
+ array(
+ 'methods' => \WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_messaging_support_eligibility' ),
+ 'permission_callback' => array( $this, 'permission_callback' ),
+ 'args' => array(
+ 'group' => array(
+ 'type' => 'string',
+ 'required' => true,
+ ),
+ 'environment' => array(
+ 'type' => 'string',
+ 'required' => true,
+ ),
+ ),
+ )
+ );
}
/**
@@ -88,6 +108,27 @@ public function get_all_support_eligibility() {
return rest_ensure_response( $response );
}
+ /**
+ * Should return messaging eligibility
+ *
+ * @param \WP_REST_Request $request The request sent to the API.
+ *
+ * @return WP_REST_Response
+ */
+ public function get_messaging_support_eligibility( \WP_REST_Request $request ) {
+ $query_parameters = array(
+ 'group' => $request['group'],
+ 'environment' => $request['environment'],
+ );
+ $body = Client::wpcom_json_api_request_as_user( 'help/messaging/is-available?' . http_build_query( $query_parameters ) );
+ if ( is_wp_error( $body ) ) {
+ return $body;
+ }
+ $response = json_decode( wp_remote_retrieve_body( $body ) );
+
+ return rest_ensure_response( $response );
+ }
+
/**
* Callback to determine whether the request can proceed.
*
diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-history.php b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-history.php
deleted file mode 100644
index 6156af39aae01..0000000000000
--- a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-support-history.php
+++ /dev/null
@@ -1,72 +0,0 @@
-namespace = 'help-center';
- $this->rest_base = '/support-history';
- }
-
- /**
- * Register available routes.
- */
- public function register_rest_route() {
- register_rest_route(
- $this->namespace,
- $this->rest_base . '/ticket',
- array(
- 'methods' => \WP_REST_Server::READABLE,
- 'callback' => array( $this, 'support_history_ticket' ),
- 'permission_callback' => 'is_user_logged_in',
- 'args' => array(
- 'email' => array(
- 'type' => 'string',
- ),
- ),
- )
- );
- }
-
- /**
- * Get support history tickets through Jetpack.
- *
- * @param \WP_REST_Request $request Request object.
- */
- public function support_history_ticket( $request ) {
- if ( isset( $request['email'] ) ) {
- $params = array( 'email' => $request['email'] );
- } else {
- $params = array();
- }
-
- $body = Client::wpcom_json_api_request_as_user(
- '/support-history/ticket?' . http_build_query( $params ),
- '2',
- array(
- 'method' => 'GET',
- )
- );
-
- if ( is_wp_error( $body ) ) {
- return $body;
- }
-
- $response = json_decode( wp_remote_retrieve_body( $body ) );
-
- return rest_ensure_response( $response );
- }
-}
diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-user-fields.php b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-user-fields.php
new file mode 100644
index 0000000000000..e14a16efb5c28
--- /dev/null
+++ b/apps/editing-toolkit/editing-toolkit-plugin/help-center/class-wp-rest-help-center-user-fields.php
@@ -0,0 +1,75 @@
+namespace = 'help-center';
+ $this->rest_base = '/zendesk/user-fields';
+ }
+
+ /**
+ * Register available routes.
+ */
+ public function register_rest_route() {
+ register_rest_route(
+ $this->namespace,
+ $this->rest_base,
+ array(
+ 'methods' => \WP_REST_Server::CREATABLE,
+ 'callback' => array( $this, 'update_user_fields' ),
+ 'permission_callback' => array( $this, 'permission_callback' ),
+ 'args' => array(
+ 'fields' => array(
+ 'type' => 'object',
+ 'required' => true,
+ ),
+ ),
+ )
+ );
+ }
+
+ /**
+ * Callback to update user fields in Zendesk
+ *
+ * @param \WP_REST_Request $request The request sent to the API.
+ *
+ * @return WP_REST_Response
+ */
+ public function update_user_fields( \WP_REST_Request $request ) {
+ $body = Client::wpcom_json_api_request_as_user(
+ 'help/zendesk/update-user-fields',
+ '2',
+ array(
+ 'method' => 'POST',
+ ),
+ $request['fields']
+ );
+
+ if ( is_wp_error( $body ) ) {
+ return $body;
+ }
+ $response = json_decode( wp_remote_retrieve_body( $body ) );
+ return rest_ensure_response( $response );
+ }
+
+ /**
+ * Callback to determine whether the user has permission to access.
+ */
+ public function permission_callback() {
+ return is_user_logged_in();
+ }
+}
diff --git a/apps/editing-toolkit/editing-toolkit-plugin/help-center/src/config.js b/apps/editing-toolkit/editing-toolkit-plugin/help-center/src/config.js
index 10c344ff98457..ab1ac348b0a45 100644
--- a/apps/editing-toolkit/editing-toolkit-plugin/help-center/src/config.js
+++ b/apps/editing-toolkit/editing-toolkit-plugin/help-center/src/config.js
@@ -1,7 +1,8 @@
window.configData = {
- env_id: 'development',
+ env_id: 'production',
i18n_default_locale_slug: 'en',
google_analytics_key: 'UA-10673494-15',
+ zendesk_support_chat_key: 'cec07bc9-4da6-4dd2-afa7-c7e01ae73584',
client_slug: 'browser',
twemoji_cdn_url: 'https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/',
site_filter: [],
@@ -39,7 +40,7 @@ window.configData = {
is_running_in_jetpack_site: false,
gutenboarding_url: '/new',
features: {
- happychat: true,
+ happychat: false,
},
signup_url: '/',
discover_blog_id: 53424024,
diff --git a/apps/happychat/src/index.ejs b/apps/happychat/src/index.ejs
index b7864cf30b271..48853f0fa109b 100644
--- a/apps/happychat/src/index.ejs
+++ b/apps/happychat/src/index.ejs
@@ -39,7 +39,7 @@
gutenboarding_url: '/new',
hostname: 'widgets.wp.com',
features: {
- happychat: true,
+ happychat: false,
},
};
diff --git a/client/components/jetpack/jetpack-presales-chat-widget/index.tsx b/client/components/jetpack/jetpack-presales-chat-widget/index.tsx
index b62d09209ecfa..424634461b783 100644
--- a/client/components/jetpack/jetpack-presales-chat-widget/index.tsx
+++ b/client/components/jetpack/jetpack-presales-chat-widget/index.tsx
@@ -30,7 +30,7 @@ function get_config_chat_key( keyType: KeyType ): keyof ConfigData {
export const ZendeskJetpackChat: React.VFC< { keyType: KeyType } > = ( { keyType } ) => {
const [ error, setError ] = useState( false );
- const { data: isStaffed } = useJpPresalesAvailabilityQuery( setError );
+ const { data: isStaffed } = useJpPresalesAvailabilityQuery( true, setError );
const zendeskChatKey: string | false = useMemo( () => {
return config( get_config_chat_key( keyType ) );
}, [ keyType ] );
diff --git a/client/components/presales-zendesk-chat/index.tsx b/client/components/presales-zendesk-chat/index.tsx
index 222ad05acf09e..66a5dbc0316fb 100644
--- a/client/components/presales-zendesk-chat/index.tsx
+++ b/client/components/presales-zendesk-chat/index.tsx
@@ -5,16 +5,22 @@ interface Props {
chatKey: string | false;
}
+const ZENDESK_SCRIPT_ID = 'ze-snippet';
+
const ZendeskChat = ( { chatKey }: Props ) => {
useEffect( () => {
if ( ! chatKey ) {
return;
}
+ if ( document.getElementById( ZENDESK_SCRIPT_ID ) ) {
+ return;
+ }
+
loadScript(
'https://static.zdassets.com/ekr/snippet.js?key=' + encodeURIComponent( chatKey ),
undefined,
- { id: 'ze-snippet' }
+ { id: ZENDESK_SCRIPT_ID }
);
}, [ chatKey ] );
diff --git a/client/lib/jetpack/use-jp-presales-availability-query.ts b/client/lib/jetpack/use-jp-presales-availability-query.ts
index cb024d63e08bc..0bf857673ed2f 100644
--- a/client/lib/jetpack/use-jp-presales-availability-query.ts
+++ b/client/lib/jetpack/use-jp-presales-availability-query.ts
@@ -31,7 +31,10 @@ async function fetchWithRetry(
}
}
-export function useJpPresalesAvailabilityQuery( setError?: Dispatch< SetStateAction< boolean > > ) {
+export function useJpPresalesAvailabilityQuery(
+ enabled = true,
+ setError?: Dispatch< SetStateAction< boolean > >
+) {
//adding a safeguard to ensure if there's an unkown error with the widget it won't crash the whole app
try {
return useQuery< boolean, Error >(
@@ -58,6 +61,7 @@ export function useJpPresalesAvailabilityQuery( setError?: Dispatch< SetStateAct
return data.is_available;
},
{
+ enabled,
meta: { persist: false },
}
);
diff --git a/client/me/happychat/index.jsx b/client/me/happychat/index.jsx
index e956131b35831..91cb06715c3ea 100644
--- a/client/me/happychat/index.jsx
+++ b/client/me/happychat/index.jsx
@@ -1,25 +1,11 @@
-import config from '@automattic/calypso-config';
-import { translate } from 'i18n-calypso';
import page from 'page';
import { makeLayout, render as clientRender } from 'calypso/controller';
-import PageViewTracker from 'calypso/lib/analytics/page-view-tracker';
import { sidebar } from 'calypso/me/controller';
-import { setDocumentHeadTitle } from 'calypso/state/document-head/actions';
-import Happychat from './main';
-const renderChat = ( context, next ) => {
- context.store.dispatch( setDocumentHeadTitle( translate( 'Chat', { textOnly: true } ) ) );
- context.primary = (
-
- );
- next();
+const redirectToHelp = () => {
+ page.redirect( '/help' );
};
export default () => {
- if ( config.isEnabled( 'happychat' ) ) {
- page( '/me/chat', sidebar, renderChat, makeLayout, clientRender );
- }
+ page( '/me/chat', sidebar, redirectToHelp, makeLayout, clientRender );
};
diff --git a/client/my-sites/checkout/composite-checkout/components/checkout-help-link.tsx b/client/my-sites/checkout/composite-checkout/components/checkout-help-link.tsx
index a4cf4234131ae..dac8f723dec66 100644
--- a/client/my-sites/checkout/composite-checkout/components/checkout-help-link.tsx
+++ b/client/my-sites/checkout/composite-checkout/components/checkout-help-link.tsx
@@ -146,7 +146,6 @@ export default function CheckoutHelpLink() {
const translate = useTranslate();
const { setShowHelpCenter } = useDataStoreDispatch( HELP_CENTER_STORE );
const isEnglishLocale = useIsEnglishLocale();
- const { data: isJpPresalesStaffed } = useJpPresalesAvailabilityQuery();
const cartKey = useCartKey();
const { responseCart } = useShoppingCart( cartKey );
@@ -165,6 +164,9 @@ export default function CheckoutHelpLink() {
supportVariation: getSupportVariation( state ),
};
} );
+ const { data: isJpPresalesStaffed } = useJpPresalesAvailabilityQuery(
+ presalesZendeskChatAvailable
+ );
const userAllowedToHelpCenter = config.isEnabled( 'calypso/help-center' );
diff --git a/config/_shared.json b/config/_shared.json
index a21649b25e498..a329bd0d725fe 100644
--- a/config/_shared.json
+++ b/config/_shared.json
@@ -39,6 +39,7 @@
"zendesk_presales_chat_key_akismet": false,
"zendesk_presales_chat_key_jp_checkout": false,
"zendesk_presales_chat_key_jp_agency_dashboard": false,
+ "zendesk_support_chat_key": false,
"upwork_support_locales": [
"de",
"de-at",
diff --git a/config/development.json b/config/development.json
index 691014994e075..9a167004e5e7b 100644
--- a/config/development.json
+++ b/config/development.json
@@ -27,6 +27,7 @@
"zendesk_presales_chat_key": "216bf91d-f10f-4f66-bf65-a0cba220cd38",
"zendesk_presales_chat_key_akismet": "7ce13115-7b34-4069-9d64-228d90f148d1",
"zendesk_presales_chat_key_jp_checkout": "7c42153f-f579-49ba-a33e-246b2d27fb93",
+ "zendesk_support_chat_key": "cec07bc9-4da6-4dd2-afa7-c7e01ae73584",
"features": {
"ad-tracking": false,
"akismet/siteless-checkout": true,
@@ -68,7 +69,7 @@
"google-drive": true,
"google-my-business": true,
"gutenboarding/alpha-templates": false,
- "happychat": true,
+ "happychat": false,
"help": true,
"help/gpt-response": true,
"home/layout-dev": true,
diff --git a/config/production.json b/config/production.json
index 00b5341935d1e..687aa0a9c59ed 100644
--- a/config/production.json
+++ b/config/production.json
@@ -17,6 +17,7 @@
"zendesk_presales_chat_key": "216bf91d-f10f-4f66-bf65-a0cba220cd38",
"zendesk_presales_chat_key_akismet": "7ce13115-7b34-4069-9d64-228d90f148d1",
"zendesk_presales_chat_key_jp_checkout": "7c42153f-f579-49ba-a33e-246b2d27fb93",
+ "zendesk_support_chat_key": "cec07bc9-4da6-4dd2-afa7-c7e01ae73584",
"features": {
"ad-tracking": true,
"akismet/siteless-checkout": true,
@@ -45,7 +46,7 @@
"fullstory": true,
"cookie-banner": true,
"google-my-business": true,
- "happychat": true,
+ "happychat": false,
"help": true,
"help/gpt-response": false,
"hosting-onboarding-i2": false,
diff --git a/config/stage.json b/config/stage.json
index c28fd1e4b76a8..9de90ef716af0 100644
--- a/config/stage.json
+++ b/config/stage.json
@@ -15,6 +15,7 @@
"zendesk_presales_chat_key": "216bf91d-f10f-4f66-bf65-a0cba220cd38",
"zendesk_presales_chat_key_akismet": "7ce13115-7b34-4069-9d64-228d90f148d1",
"zendesk_presales_chat_key_jp_checkout": "7c42153f-f579-49ba-a33e-246b2d27fb93",
+ "zendesk_support_chat_key": "cec07bc9-4da6-4dd2-afa7-c7e01ae73584",
"features": {
"ad-tracking": false,
"akismet/siteless-checkout": true,
@@ -43,7 +44,7 @@
"fullstory": true,
"cookie-banner": false,
"google-my-business": true,
- "happychat": true,
+ "happychat": false,
"help": true,
"help/gpt-response": true,
"i18n/empathy-mode": true,
diff --git a/config/wpcalypso.json b/config/wpcalypso.json
index 6e04856462ef7..311ee4c8bb06b 100644
--- a/config/wpcalypso.json
+++ b/config/wpcalypso.json
@@ -15,6 +15,7 @@
"zendesk_presales_chat_key": "216bf91d-f10f-4f66-bf65-a0cba220cd38",
"zendesk_presales_chat_key_akismet": "7ce13115-7b34-4069-9d64-228d90f148d1",
"zendesk_presales_chat_key_jp_checkout": "7c42153f-f579-49ba-a33e-246b2d27fb93",
+ "zendesk_support_chat_key": "cec07bc9-4da6-4dd2-afa7-c7e01ae73584",
"features": {
"ad-tracking": false,
"akismet/siteless-checkout": true,
@@ -50,7 +51,7 @@
"cookie-banner": true,
"google-my-business": true,
"gutenboarding/alpha-templates": false,
- "happychat": true,
+ "happychat": false,
"help": true,
"help/gpt-response": true,
"home/layout-dev": true,
diff --git a/packages/data-stores/src/help-center/actions.ts b/packages/data-stores/src/help-center/actions.ts
index ac06d0e2876bc..6f6f9314f6cb4 100644
--- a/packages/data-stores/src/help-center/actions.ts
+++ b/packages/data-stores/src/help-center/actions.ts
@@ -61,10 +61,24 @@ export const setIsMinimized = ( minimized: boolean ) =>
minimized,
} as const );
+export const setShowMessagingLauncher = ( show: boolean ) =>
+ ( {
+ type: 'HELP_CENTER_SET_SHOW_MESSAGING_LAUNCHER',
+ show,
+ } as const );
+
+export const setShowMessagingWidget = ( show: boolean ) =>
+ ( {
+ type: 'HELP_CENTER_SET_SHOW_MESSAGING_WIDGET',
+ show,
+ } as const );
+
export const setShowHelpCenter = function* ( show: boolean ) {
if ( ! show ) {
yield setInitialRoute( undefined );
yield setIsMinimized( false );
+ } else {
+ yield setShowMessagingWidget( false );
}
return {
@@ -128,6 +142,8 @@ export const resetStore = () =>
export type HelpCenterAction =
| ReturnType<
+ | typeof setShowMessagingLauncher
+ | typeof setShowMessagingWidget
| typeof setSite
| typeof setSubject
| typeof resetStore
diff --git a/packages/data-stores/src/help-center/reducer.ts b/packages/data-stores/src/help-center/reducer.ts
index f4596b6035abf..292df98dda622 100644
--- a/packages/data-stores/src/help-center/reducer.ts
+++ b/packages/data-stores/src/help-center/reducer.ts
@@ -13,6 +13,25 @@ const showHelpCenter: Reducer< boolean | undefined, HelpCenterAction > = ( state
return state;
};
+const showMessagingLauncher: Reducer< boolean | undefined, HelpCenterAction > = (
+ state,
+ action
+) => {
+ switch ( action.type ) {
+ case 'HELP_CENTER_SET_SHOW_MESSAGING_LAUNCHER':
+ return action.show;
+ }
+ return state;
+};
+
+const showMessagingWidget: Reducer< boolean | undefined, HelpCenterAction > = ( state, action ) => {
+ switch ( action.type ) {
+ case 'HELP_CENTER_SET_SHOW_MESSAGING_WIDGET':
+ return action.show;
+ }
+ return state;
+};
+
const hasSeenWhatsNewModal: Reducer< boolean | undefined, HelpCenterAction > = (
state,
action
@@ -119,6 +138,8 @@ const initialRoute: Reducer< InitialEntry | undefined, HelpCenterAction > = ( st
const reducer = combineReducers( {
showHelpCenter,
+ showMessagingLauncher,
+ showMessagingWidget,
site,
subject,
message,
diff --git a/packages/data-stores/src/help-center/selectors.ts b/packages/data-stores/src/help-center/selectors.ts
index d40f8d0873d1f..ec439d44333cf 100644
--- a/packages/data-stores/src/help-center/selectors.ts
+++ b/packages/data-stores/src/help-center/selectors.ts
@@ -1,6 +1,8 @@
import type { State } from './reducer';
export const isHelpCenterShown = ( state: State ) => state.showHelpCenter;
+export const isMessagingLauncherShown = ( state: State ) => state.showMessagingLauncher;
+export const isMessagingWidgetShown = ( state: State ) => state.showMessagingWidget;
export const getSite = ( state: State ) => state.site;
export const getSubject = ( state: State ) => state.subject;
export const getMessage = ( state: State ) => state.message;
diff --git a/packages/data-stores/src/index.ts b/packages/data-stores/src/index.ts
index 7a0f14619cde9..f3f2ddff1a1ce 100644
--- a/packages/data-stores/src/index.ts
+++ b/packages/data-stores/src/index.ts
@@ -21,7 +21,8 @@ export { useSiteIntent } from './queries/use-site-intent';
export { useSupportAvailability } from './support-queries/use-support-availability';
export { useSubmitTicketMutation } from './support-queries/use-submit-support-ticket';
export { useSubmitForumsMutation } from './support-queries/use-submit-forums-topic';
-export { useHasActiveSupport } from './support-queries/use-support-history';
+export { useUpdateZendeskUserFieldsMutation } from './support-queries/use-update-zendesk-user-fields';
+export { useSupportActivity } from './support-queries/use-support-activity';
export * from './starter-designs-queries';
export * from './support-queries/types';
export * from './site/types';
diff --git a/packages/data-stores/src/support-queries/types.ts b/packages/data-stores/src/support-queries/types.ts
index b32367d6d6bab..36ef0789ef61e 100644
--- a/packages/data-stores/src/support-queries/types.ts
+++ b/packages/data-stores/src/support-queries/types.ts
@@ -27,13 +27,10 @@ export interface OtherSupportAvailability {
is_user_eligible_for_chat: boolean;
}
-export interface SupportSession {
- id?: number;
+export interface SupportActivity {
+ id: number;
status: string;
subject: string;
- time: Date;
timestamp: number;
- type: string;
- url: string;
- when: string;
+ channel: string;
}
diff --git a/packages/data-stores/src/support-queries/use-support-activity.ts b/packages/data-stores/src/support-queries/use-support-activity.ts
new file mode 100644
index 0000000000000..db27e0c15b1c1
--- /dev/null
+++ b/packages/data-stores/src/support-queries/use-support-activity.ts
@@ -0,0 +1,36 @@
+import { useQuery } from '@tanstack/react-query';
+import apiFetch, { APIFetchOptions } from '@wordpress/api-fetch';
+import wpcomRequest, { canAccessWpcomApis } from 'wpcom-proxy-request';
+import type { SupportActivity } from './types';
+
+const ACTIVE_STATUSES = [ 'New', 'Open', 'Hold' ];
+
+export function useSupportActivity( enabled = true ) {
+ return useQuery(
+ [ 'help-support-activity' ],
+ () =>
+ canAccessWpcomApis()
+ ? wpcomRequest< SupportActivity[] >( {
+ path: 'support-activity',
+ apiNamespace: 'wpcom/v2/',
+ apiVersion: '2',
+ } )
+ : apiFetch< SupportActivity[] >( {
+ path: 'help-center/support-activity',
+ global: true,
+ } as APIFetchOptions ),
+ {
+ refetchOnWindowFocus: false,
+ keepPreviousData: false,
+ refetchOnMount: true,
+ enabled,
+ select: ( activities ) => {
+ return activities.filter( ( activity ) => ACTIVE_STATUSES.includes( activity.status ) );
+ },
+ staleTime: 30 * 60 * 1000,
+ meta: {
+ persist: false,
+ },
+ }
+ );
+}
diff --git a/packages/data-stores/src/support-queries/use-support-history.ts b/packages/data-stores/src/support-queries/use-support-history.ts
deleted file mode 100644
index 0d5ff4707ca55..0000000000000
--- a/packages/data-stores/src/support-queries/use-support-history.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { useQuery } from '@tanstack/react-query';
-import apiFetch, { APIFetchOptions } from '@wordpress/api-fetch';
-import wpcomRequest, { canAccessWpcomApis } from 'wpcom-proxy-request';
-import type { SupportSession } from './types';
-
-interface Response {
- data: SupportSession[];
-}
-
-const ACTIVE_STATUSES = [ 'New', 'Open', 'Hold' ];
-
-/**
- * Checks if the user has an active support session or a recent ticket.
- *
- * NOTE: Chat mode isn't functional at the moment.
- */
-export function useHasActiveSupport( type: 'chat' | 'ticket', email: string, show = true ) {
- return useQuery(
- [ 'help-support-history', type, email ],
- () =>
- canAccessWpcomApis()
- ? wpcomRequest< Response >( {
- path: `support-history/${ encodeURIComponent( type ) }`,
- apiNamespace: 'wpcom/v2/',
- apiVersion: '2',
- query: email ? `email=${ encodeURIComponent( email ) }` : '',
- } )
- : apiFetch< Response >( {
- path:
- `help-center/support-history/${ encodeURIComponent( type ) }/` +
- ( email ? `?email=${ encodeURIComponent( email ) }` : '' ),
- global: true,
- } as APIFetchOptions ),
- {
- refetchOnWindowFocus: false,
- keepPreviousData: false,
- refetchOnMount: true,
- enabled: show,
- select: ( response ) => {
- const recentSession = response.data[ 0 ];
- return ACTIVE_STATUSES.includes( recentSession.status ) ? recentSession : null;
- },
- staleTime: 30 * 60 * 1000,
- }
- );
-}
diff --git a/packages/data-stores/src/support-queries/use-update-zendesk-user-fields.ts b/packages/data-stores/src/support-queries/use-update-zendesk-user-fields.ts
new file mode 100644
index 0000000000000..82082face3241
--- /dev/null
+++ b/packages/data-stores/src/support-queries/use-update-zendesk-user-fields.ts
@@ -0,0 +1,29 @@
+import { useMutation } from '@tanstack/react-query';
+import apiFetch, { APIFetchOptions } from '@wordpress/api-fetch';
+import wpcomRequest, { canAccessWpcomApis } from 'wpcom-proxy-request';
+
+type ZendeskUserFields = {
+ messaging_initial_message?: string;
+ messaging_plan?: string;
+ messaging_source?: string;
+ messaging_url?: string;
+};
+
+export function useUpdateZendeskUserFieldsMutation() {
+ return useMutation( ( userFields: ZendeskUserFields ) => {
+ return canAccessWpcomApis()
+ ? wpcomRequest( {
+ path: 'help/zendesk/update-user-fields',
+ apiNamespace: 'wpcom/v2/',
+ apiVersion: '2',
+ method: 'POST',
+ body: { fields: userFields },
+ } )
+ : apiFetch( {
+ global: true,
+ path: '/help-center/ticket/new',
+ method: 'POST',
+ data: { fields: userFields },
+ } as APIFetchOptions );
+ } );
+}
diff --git a/packages/help-center/src/components/help-center-contact-form.tsx b/packages/help-center/src/components/help-center-contact-form.tsx
index 490ec50abfc95..4f1417c873207 100644
--- a/packages/help-center/src/components/help-center-contact-form.tsx
+++ b/packages/help-center/src/components/help-center-contact-form.tsx
@@ -9,12 +9,14 @@ import { FormInputValidation, Popover } from '@automattic/components';
import {
useSubmitTicketMutation,
useSubmitForumsMutation,
+ useUpdateZendeskUserFieldsMutation,
useSiteAnalysis,
useUserSites,
AnalysisReport,
SiteDetails,
HelpCenterSite,
useJetpackSearchAIQuery,
+ useSupportAvailability,
} from '@automattic/data-stores';
import { useLocale } from '@automattic/i18n-utils';
import { SitePickerDropDown, SitePickerSite } from '@automattic/site-picker';
@@ -35,6 +37,7 @@ import { getSectionName } from 'calypso/state/ui/selectors';
/**
* Internal Dependencies
*/
+import useZendeskConfig from '../hooks/use-zendesk-config';
import { HELP_CENTER_STORE } from '../stores';
import { getSupportVariationFromMode } from '../support-variations';
import { SitePicker } from '../types';
@@ -42,6 +45,7 @@ import { BackButton } from './back-button';
import { HelpCenterGPT } from './help-center-gpt';
import { HelpCenterOwnershipNotice } from './help-center-notice';
import HelpCenterSearchResults from './help-center-search-results';
+import ThirdPartyCookiesNotice from './help-center-third-party-cookies-notice';
import type { HelpCenterSelect } from '@automattic/data-stores';
import './help-center-contact-form.scss';
@@ -160,6 +164,8 @@ export const HelpCenterContactForm = () => {
const locale = useLocale();
const { isLoading: submittingTicket, mutateAsync: submitTicket } = useSubmitTicketMutation();
const { isLoading: submittingTopic, mutateAsync: submitTopic } = useSubmitForumsMutation();
+ const { isLoading: submittingZendeskUserFields, mutateAsync: submitZendeskUserFields } =
+ useUpdateZendeskUserFieldsMutation();
const userId = useSelector( getCurrentUserId );
const { data: userSites } = useUserSites( userId );
const userWithNoSites = userSites?.sites.length === 0;
@@ -185,8 +191,14 @@ export const HelpCenterContactForm = () => {
setUserDeclaredSite,
setSubject,
setMessage,
+ setShowHelpCenter,
+ setShowMessagingLauncher,
+ setShowMessagingWidget,
} = useDispatch( HELP_CENTER_STORE );
+ const { data: chatStatus } = useSupportAvailability( 'CHAT' );
+ const { status: zendeskStatus } = useZendeskConfig( Boolean( chatStatus?.is_user_eligible ) );
+
useEffect( () => {
const supportVariation = getSupportVariationFromMode( mode );
recordTracksEvent( 'calypso_inlinehelp_contact_view', {
@@ -213,7 +225,7 @@ export const HelpCenterContactForm = () => {
);
const ownershipStatusLoading = ownershipResult?.result === 'LOADING';
- const isSubmitting = submittingTicket || submittingTopic;
+ const isSubmitting = submittingTicket || submittingTopic || submittingZendeskUserFields;
// if the user picked a site from the picker, we don't need to analyze the ownership
if ( currentSite && sitePickerChoice === 'CURRENT_SITE' ) {
@@ -348,7 +360,7 @@ export const HelpCenterContactForm = () => {
case 'CHAT':
if ( supportSite ) {
recordTracksEvent( 'calypso_inlinehelp_contact_submit', {
- support_variation: 'happychat',
+ support_variation: 'messaging',
force_site_id: true,
location: 'help-center',
section: sectionName,
@@ -361,7 +373,22 @@ export const HelpCenterContactForm = () => {
location: 'help-center',
section: sectionName,
} );
- navigate( '/inline-chat' );
+
+ submitZendeskUserFields( {
+ messaging_source: sectionName,
+ messaging_initial_message: message,
+ messaging_plan: '', // Will be filled out by backend
+ messaging_url: supportSite?.URL,
+ } )
+ .then( () => {
+ setShowHelpCenter( false );
+ setShowMessagingLauncher( true );
+ setShowMessagingWidget( true );
+ resetStore();
+ } )
+ .catch( () => {
+ setHasSubmittingError( true );
+ } );
break;
}
break;
@@ -542,6 +569,10 @@ export const HelpCenterContactForm = () => {
return isSubmitting ? formTitles.buttonSubmittingLabel : formTitles.buttonLabel;
};
+ if ( mode === 'CHAT' && zendeskStatus === 'error' ) {
+ return ;
+ }
+
// TODO: A/B test
if ( enableGPTResponse && showingGPTResponse ) {
return (
diff --git a/packages/help-center/src/components/help-center-contact-page.tsx b/packages/help-center/src/components/help-center-contact-page.tsx
index 3ce3e3dd68dde..3140d8ead3d18 100644
--- a/packages/help-center/src/components/help-center-contact-page.tsx
+++ b/packages/help-center/src/components/help-center-contact-page.tsx
@@ -5,9 +5,8 @@
import { recordTracksEvent } from '@automattic/calypso-analytics';
import config from '@automattic/calypso-config';
import { Spinner, GMClosureNotice } from '@automattic/components';
-import { useSupportAvailability, useHasActiveSupport } from '@automattic/data-stores';
+import { useSupportAvailability, useSupportActivity } from '@automattic/data-stores';
import { isDefaultLocale, getLanguage, useLocale } from '@automattic/i18n-utils';
-import { Notice } from '@wordpress/components';
import { useEffect, useMemo } from '@wordpress/element';
import { hasTranslation, sprintf } from '@wordpress/i18n';
import { comment, Icon } from '@wordpress/icons';
@@ -16,7 +15,6 @@ import classnames from 'classnames';
import { FC } from 'react';
import { useSelector } from 'react-redux';
import { Link, LinkProps } from 'react-router-dom';
-import { getCurrentUserEmail } from 'calypso/state/current-user/selectors';
import { getSectionName } from 'calypso/state/ui/selectors';
/**
* Internal Dependencies
@@ -41,13 +39,9 @@ export const HelpCenterContactPage: FC = () => {
const renderEmail = useShouldRenderEmailOption();
const renderChat = useShouldRenderChatOption();
- const email = useSelector( getCurrentUserEmail );
- const { data: hasActiveTickets, isLoading: isLoadingTickets } = useHasActiveSupport(
- 'ticket',
- email
- );
+ const { data: supportActivity, isLoading: isLoadingSupportActivity } = useSupportActivity();
const { data: supportAvailability } = useSupportAvailability( 'CHAT' );
- const isLoading = renderChat.isLoading || renderEmail.isLoading || isLoadingTickets;
+ const isLoading = renderChat.isLoading || renderEmail.isLoading || isLoadingSupportActivity;
useEffect( () => {
if ( isLoading ) {
@@ -121,7 +115,7 @@ export const HelpCenterContactPage: FC = () => {
{ __( 'Contact our WordPress.com experts', __i18n_text_domain__ ) }
- { hasActiveTickets &&
}
+ { supportActivity &&
}
{ /* Easter */ }
{
reopensAt="2023-04-10 07:00Z"
enabled={ hasAccessToLivechat }
/>
- { renderChat.env === 'staging' && (
-
- Targeting HappyChat staging
-
- ) }
@@ -159,10 +143,7 @@ export const HelpCenterContactPage: FC = () => {
{ renderChat.render && (
-
+
= ( { draggable, ...props
return
;
};
-const RedirectAssigned = ( { status }: { status?: string } ) => {
- const navigate = useNavigate();
- const { pathname } = useLocation();
- const assigned = status === 'assigned';
-
- useEffect( () => {
- if ( assigned && ! pathname.startsWith( '/inline-chat' ) ) {
- navigate( '/inline-chat?session=continued', { replace: true } );
- }
- }, [ assigned, navigate, pathname ] );
-
- return null;
-};
-
const HelpCenterContainer: React.FC< Container > = ( { handleClose, hidden } ) => {
const { show, isMinimized, initialRoute } = useSelect(
( select ) => ( {
@@ -63,8 +47,6 @@ const HelpCenterContainer: React.FC< Container > = ( { handleClose, hidden } ) =
const classNames = classnames( 'help-center__container', isMobile ? 'is-mobile' : 'is-desktop', {
'is-minimized': isMinimized,
} );
- const { data: supportAvailability } = useSupportAvailability( 'CHAT' );
- const { data } = useHappychatAvailable( Boolean( supportAvailability?.is_user_eligible ) );
const onDismiss = () => {
setIsVisible( false );
@@ -94,7 +76,6 @@ const HelpCenterContainer: React.FC< Container > = ( { handleClose, hidden } ) =
return (
-
( null );
-
- useEffect( () => {
- if ( ! container.current ) {
- return;
- }
- const containerElement = container.current;
-
- let isMouseDown = false;
-
- function handler( event: MouseEvent | ResizeObserverEntry[] | UIEvent | null ) {
- // when it's an array, it means it came from ResizeObserver
- if ( isMouseDown || Array.isArray( event ) || event?.type === 'resize' ) {
- const box = containerElement.getBoundingClientRect();
- theIframe.style.display = 'block';
- theIframe.style.left = box.left + 'px';
- theIframe.style.top = box.top + 'px';
- theIframe.style.width = box.width + 'px';
- theIframe.style.height = box.height + 'px';
- }
- }
-
- handler( [] );
-
- // this is the only I could come up with to monitor dragging
- // since React-draggable is not propagating the drag event.
- function mouseDownHandler() {
- isMouseDown = true;
- }
-
- function mouseUpHandler() {
- isMouseDown = false;
- }
-
- window.addEventListener( 'resize', handler );
- window.addEventListener( 'mousemove', handler );
- window.addEventListener( 'mouseup', mouseUpHandler );
- window.addEventListener( 'mousedown', mouseDownHandler );
-
- const resizeObserver = new ResizeObserver( handler );
- resizeObserver.observe( containerElement );
-
- return () => {
- theIframe.style.display = 'none';
- window.removeEventListener( 'resize', handler );
- window.removeEventListener( 'mousemove', handler );
- window.removeEventListener( 'mouseup', mouseUpHandler );
- window.removeEventListener( 'mousedown', mouseDownHandler );
- resizeObserver.unobserve( containerElement );
- };
- }, [ container ] );
-
- useEffect( () => {
- setIframe( theIframe );
- // rewriting the same src will reload the iframe
- if ( theIframe.src !== src ) {
- theIframe.src = src;
- }
- }, [ src, setIframe ] );
-
- return ;
-}
-
const InlineChat: React.FC = () => {
- const { search } = useLocation();
- const params = new URLSearchParams( search );
- const session = params.get( 'session' ) === 'continued' ? 'continued' : 'new';
- // "ref" is used to track where the user came from so we can show the right message
- // See happychat/getUserInfo for more info.
- const ref = new URLSearchParams( window.location.search ).get( 'ref' ) || '';
-
- return (
-
- );
+ const { setShowMessagingLauncher } = useDispatch( HELP_CENTER_STORE );
+ const { setShowMessagingWidget } = useDispatch( HELP_CENTER_STORE );
+ const { setShowHelpCenter } = useDispatch( HELP_CENTER_STORE );
+ setShowMessagingLauncher( true );
+ setShowMessagingWidget( true );
+ setShowHelpCenter( false );
+
+ return null;
};
export default InlineChat;
diff --git a/packages/help-center/src/components/help-center-notice.tsx b/packages/help-center/src/components/help-center-notice.tsx
index 4b9fe3507cc17..414a84224b18b 100644
--- a/packages/help-center/src/components/help-center-notice.tsx
+++ b/packages/help-center/src/components/help-center-notice.tsx
@@ -1,4 +1,4 @@
-import { SupportSession } from '@automattic/data-stores';
+import { SupportActivity } from '@automattic/data-stores';
import { localizeUrl, useLocale, getRelativeTimeString } from '@automattic/i18n-utils';
import { ExternalLink } from '@wordpress/components';
import { createInterpolateElement } from '@wordpress/element';
@@ -97,7 +97,7 @@ export function HelpCenterOwnershipNotice( { ownershipResult }: Props ) {
export function HelpCenterActiveTicketNotice( {
tickets,
}: {
- tickets: SupportSession[] | undefined;
+ tickets: SupportActivity[] | undefined;
} ) {
const locale = useLocale();
diff --git a/packages/help-center/src/components/help-center-search.scss b/packages/help-center/src/components/help-center-search.scss
index 04bd231326165..b475faebbb069 100644
--- a/packages/help-center/src/components/help-center-search.scss
+++ b/packages/help-center/src/components/help-center-search.scss
@@ -455,6 +455,17 @@
}
}
+ /**
+ * Third Party Cookies Notice
+ */
+ .help-center-third-party-cookies-notice {
+ h1 {
+ font-size: $font-body;
+ font-weight: 500;
+ margin: 1em 0;
+ }
+ }
+
/**
* ARTICLE EMBED
*/
diff --git a/packages/help-center/src/components/help-center-third-party-cookies-notice.tsx b/packages/help-center/src/components/help-center-third-party-cookies-notice.tsx
new file mode 100644
index 0000000000000..2b63290b2e145
--- /dev/null
+++ b/packages/help-center/src/components/help-center-third-party-cookies-notice.tsx
@@ -0,0 +1,46 @@
+/* eslint-disable no-restricted-imports */
+import { recordTracksEvent } from '@automattic/calypso-analytics';
+import { useEffect } from '@wordpress/element';
+import { useI18n } from '@wordpress/react-i18n';
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { getSectionName } from 'calypso/state/ui/selectors';
+import { BackButton } from './back-button';
+
+const ThirdPartyCookiesNotice: React.FC = () => {
+ const { __ } = useI18n();
+ const sectionName = useSelector( getSectionName );
+
+ useEffect( () => {
+ recordTracksEvent( 'calypso_helpcenter_third_party_cookies_notice_open', {
+ force_site_id: true,
+ location: 'help-center',
+ section: sectionName,
+ } );
+ }, [] ); // Dependencies do not include sectionName on purpose - we just care about reporting it once
+
+ return (
+
+ );
+};
+
+export default ThirdPartyCookiesNotice;
diff --git a/packages/help-center/src/components/help-center.tsx b/packages/help-center/src/components/help-center.tsx
index 335b8644996bf..dae68079e0774 100644
--- a/packages/help-center/src/components/help-center.tsx
+++ b/packages/help-center/src/components/help-center.tsx
@@ -2,51 +2,128 @@
/**
* External Dependencies
*/
-import { useSupportAvailability } from '@automattic/data-stores';
-import { useHappychatAvailable } from '@automattic/happychat-connection';
+import config from '@automattic/calypso-config';
+import { useSupportAvailability, useSupportActivity } from '@automattic/data-stores';
+import { loadScript } from '@automattic/load-script';
import { useSelect, useDispatch } from '@wordpress/data';
-import { createPortal, useEffect, useRef } from '@wordpress/element';
+import { createPortal, useEffect, useRef, useState } from '@wordpress/element';
import { useSelector } from 'react-redux';
import getPrimarySiteId from 'calypso/state/selectors/get-primary-site-id';
import { getSelectedSiteId } from 'calypso/state/ui/selectors';
/**
* Internal Dependencies
*/
-import { useHCWindowCommunicator } from '../happychat-window-communicator';
+import useMessagingAuth from '../hooks/use-messaging-auth';
import { useStillNeedHelpURL } from '../hooks/use-still-need-help-url';
+import useZendeskConfig from '../hooks/use-zendesk-config';
import { HELP_CENTER_STORE, USER_STORE, SITE_STORE } from '../stores';
import { Container } from '../types';
import HelpCenterContainer from './help-center-container';
import type { HelpCenterSelect, SiteSelect, UserSelect } from '@automattic/data-stores';
import '../styles.scss';
+const ZENDESK_SCRIPT_ID = 'ze-snippet';
+
const HelpCenter: React.FC< Container > = ( { handleClose, hidden } ) => {
const portalParent = useRef( document.createElement( 'div' ) ).current;
const { data: chatStatus } = useSupportAvailability( 'CHAT' );
- const { data } = useHappychatAvailable( Boolean( chatStatus?.is_user_eligible ) );
- const { setShowHelpCenter } = useDispatch( HELP_CENTER_STORE );
- const { setUnreadCount } = useDispatch( HELP_CENTER_STORE );
const { setSite } = useDispatch( HELP_CENTER_STORE );
+ const { setShowMessagingLauncher } = useDispatch( HELP_CENTER_STORE );
+ const { setShowMessagingWidget } = useDispatch( HELP_CENTER_STORE );
+ const [ isMessagingScriptLoaded, setMessagingScriptLoaded ] = useState( false );
- const { show, isMinimized } = useSelect(
- ( select ) => ( {
- isMinimized: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).getIsMinimized(),
- show: ( select( HELP_CENTER_STORE ) as HelpCenterSelect ).isHelpCenterShown(),
- } ),
- []
- );
+ useEffect( () => {
+ if ( ! chatStatus?.is_user_eligible ) {
+ return;
+ }
+
+ const zendeskKey: string | false = config( 'zendesk_support_chat_key' );
+ if ( ! zendeskKey ) {
+ return;
+ }
- const { unreadCount, closeChat } = useHCWindowCommunicator( isMinimized || ! show );
+ if ( document.getElementById( ZENDESK_SCRIPT_ID ) ) {
+ return;
+ }
+
+ function setUpMessagingEventHandlers() {
+ setMessagingScriptLoaded( true );
+ if ( typeof window.zE !== 'function' ) {
+ return;
+ }
+
+ window.zE( 'messenger', 'hide' );
+
+ window.zE( 'messenger:on', 'open', function () {
+ setShowMessagingWidget( true );
+ } );
+ window.zE( 'messenger:on', 'close', function () {
+ setShowMessagingWidget( false );
+ } );
+ window.zE( 'messenger:on', 'unreadMessages', function ( count ) {
+ if ( Number( count ) > 0 ) {
+ setShowMessagingLauncher( true );
+ }
+ } );
+ }
+ loadScript(
+ 'https://static.zdassets.com/ekr/snippet.js?key=' + encodeURIComponent( zendeskKey ),
+ setUpMessagingEventHandlers,
+ { id: ZENDESK_SCRIPT_ID }
+ );
+ }, [ setShowMessagingLauncher, setShowMessagingWidget, chatStatus ] );
+
+ const { data: messagingAuth } = useMessagingAuth( Boolean( chatStatus?.is_user_eligible ) );
useEffect( () => {
- setUnreadCount( unreadCount );
- }, [ unreadCount, setUnreadCount ] );
+ const jwt = messagingAuth?.user.jwt;
+ if ( typeof window.zE !== 'function' || ! jwt || ! isMessagingScriptLoaded ) {
+ return;
+ }
+
+ window.zE( 'messenger', 'loginUser', function ( callback ) {
+ callback( jwt );
+ } );
+ }, [ messagingAuth, isMessagingScriptLoaded ] );
+
+ const { showMessagingLauncher, showMessagingWidget } = useSelect( ( select ) => {
+ const helpCenterSelect: HelpCenterSelect = select( HELP_CENTER_STORE );
+ return {
+ showMessagingLauncher: helpCenterSelect.isMessagingLauncherShown(),
+ showMessagingWidget: helpCenterSelect.isMessagingWidgetShown(),
+ };
+ }, [] );
+
+ useEffect( () => {
+ if ( typeof window.zE !== 'function' || ! isMessagingScriptLoaded ) {
+ return;
+ }
+ if ( showMessagingLauncher ) {
+ window.zE( 'messenger', 'show' );
+ } else {
+ window.zE( 'messenger', 'hide' );
+ }
+ }, [ showMessagingLauncher, isMessagingScriptLoaded ] );
useEffect( () => {
- if ( data?.status === 'assigned' ) {
- setShowHelpCenter( true );
+ if ( typeof window.zE !== 'function' || ! isMessagingScriptLoaded ) {
+ return;
}
- }, [ data, setShowHelpCenter ] );
+ if ( showMessagingWidget ) {
+ window.zE( 'messenger', 'open' );
+ } else {
+ window.zE( 'messenger', 'close' );
+ }
+ }, [ showMessagingWidget, isMessagingScriptLoaded ] );
+
+ const { data: supportActivity } = useSupportActivity( Boolean( chatStatus?.is_user_eligible ) );
+ useEffect( () => {
+ if ( supportActivity?.some( ( ticket ) => ticket.channel === 'Messaging' ) ) {
+ setShowMessagingLauncher( true );
+ }
+ }, [ setShowMessagingLauncher, supportActivity ] );
+
+ useZendeskConfig( Boolean( chatStatus?.is_user_eligible ) ); // Pre-fetch
const siteId = useSelector( ( state ) => getSelectedSiteId( state ) );
const primarySiteId = useSelector( ( state ) => getPrimarySiteId( state ) );
@@ -60,7 +137,6 @@ const HelpCenter: React.FC< Container > = ( { handleClose, hidden } ) => {
);
setSite( currentSite ? currentSite : site );
- useSupportAvailability( 'CHAT' );
useStillNeedHelpURL();
@@ -75,7 +151,6 @@ const HelpCenter: React.FC< Container > = ( { handleClose, hidden } ) => {
return () => {
document.body.removeChild( portalParent );
- closeChat();
handleClose();
};
}, [ portalParent ] );
diff --git a/packages/help-center/src/components/types.d.ts b/packages/help-center/src/components/types.d.ts
index eb3fc9b5f18e4..054a2e10b81dc 100644
--- a/packages/help-center/src/components/types.d.ts
+++ b/packages/help-center/src/components/types.d.ts
@@ -2,4 +2,9 @@
declare const __i18n_text_domain__: string;
interface Window {
helpCenterData: any;
+ zE?: (
+ action: string,
+ value: string,
+ handler?: ( callback: ( data: string | number ) => void ) => void
+ ) => void;
}
diff --git a/packages/help-center/src/hooks/use-messaging-auth.ts b/packages/help-center/src/hooks/use-messaging-auth.ts
new file mode 100644
index 0000000000000..23410796143f3
--- /dev/null
+++ b/packages/help-center/src/hooks/use-messaging-auth.ts
@@ -0,0 +1,37 @@
+import config from '@automattic/calypso-config';
+import { useQuery } from '@tanstack/react-query';
+import apiFetch from '@wordpress/api-fetch';
+import { addQueryArgs } from '@wordpress/url';
+import wpcomRequest, { canAccessWpcomApis } from 'wpcom-proxy-request';
+import type { MessagingAuth } from '../types';
+
+interface APIFetchOptions {
+ global: boolean;
+ path: string;
+}
+
+function requestMessagingAuth() {
+ const currentEnvironment = config( 'env_id' );
+ const params = { type: 'zendesk', test_mode: String( currentEnvironment === 'development' ) };
+ const wpcomParams = new URLSearchParams( params );
+ return canAccessWpcomApis()
+ ? wpcomRequest< MessagingAuth >( {
+ path: '/help/authenticate/chat',
+ query: wpcomParams.toString(),
+ apiNamespace: 'wpcom/v2',
+ apiVersion: '2',
+ method: 'POST',
+ } )
+ : apiFetch< MessagingAuth >( {
+ path: addQueryArgs( '/help-center/authenticate/chat', params ),
+ method: 'POST',
+ global: true,
+ } as APIFetchOptions );
+}
+
+export default function useMessagingAuth( enabled: boolean ) {
+ return useQuery< MessagingAuth >( [ 'getMessagingAuth' ], requestMessagingAuth, {
+ staleTime: 7 * 24 * 60 * 60 * 1000, // 1 week (JWT is actually 2 weeks, but lets be on the safe side)
+ enabled,
+ } );
+}
diff --git a/packages/help-center/src/hooks/use-messaging-availability.ts b/packages/help-center/src/hooks/use-messaging-availability.ts
new file mode 100644
index 0000000000000..89bc1274b5d31
--- /dev/null
+++ b/packages/help-center/src/hooks/use-messaging-availability.ts
@@ -0,0 +1,47 @@
+import config from '@automattic/calypso-config';
+import { useQuery } from '@tanstack/react-query';
+import apiFetch from '@wordpress/api-fetch';
+import { addQueryArgs } from '@wordpress/url';
+import wpcomRequest, { canAccessWpcomApis } from 'wpcom-proxy-request';
+import type { MessagingAvailability } from '../types';
+
+interface APIFetchOptions {
+ global: boolean;
+ path: string;
+}
+
+function requestMessagingAvailability() {
+ const currentEnvironment = config( 'env_id' );
+ const params = {
+ group: 'wpcom_messaging',
+ environment: currentEnvironment === 'development' ? 'development' : 'production',
+ };
+ const wpcomParams = new URLSearchParams( params );
+ return canAccessWpcomApis()
+ ? wpcomRequest< MessagingAvailability >( {
+ path: '/help/messaging/is-available',
+ query: wpcomParams.toString(),
+ apiNamespace: 'wpcom/v2',
+ apiVersion: '2',
+ method: 'GET',
+ } )
+ : apiFetch< MessagingAvailability >( {
+ path: addQueryArgs( '/help-center/support-availability/messaging', params ),
+ method: 'GET',
+ global: true,
+ } as APIFetchOptions );
+}
+
+export default function useMessagingAvailability( enabled = true ) {
+ return useQuery< MessagingAvailability >(
+ [ 'getMessagingAvailability' ],
+ requestMessagingAvailability,
+ {
+ staleTime: 60 * 1000, // 1 minute
+ meta: {
+ persist: false,
+ },
+ enabled,
+ }
+ );
+}
diff --git a/packages/help-center/src/hooks/use-should-render-chat-option.tsx b/packages/help-center/src/hooks/use-should-render-chat-option.tsx
index 5e539ae708835..c6a9fabe5d324 100644
--- a/packages/help-center/src/hooks/use-should-render-chat-option.tsx
+++ b/packages/help-center/src/hooks/use-should-render-chat-option.tsx
@@ -1,22 +1,24 @@
-import { useSupportAvailability } from '@automattic/data-stores';
-import { useHappychatAvailable } from '@automattic/happychat-connection';
+import { useSupportAvailability, useSupportActivity } from '@automattic/data-stores';
+import useMessagingAvailability from './use-messaging-availability';
type Result = {
render: boolean;
state: 'AVAILABLE' | 'UNAVAILABLE' | 'CLOSED';
isLoading: boolean;
eligible: boolean;
- env?: 'staging' | 'production';
+ to: string;
};
export function useShouldRenderChatOption(): Result {
const { data: chatStatus } = useSupportAvailability( 'CHAT' );
- // when the user is looking at the help page, we want to be extra sure they don't start a chat without available operators
- // so in this case, let's make stale time 1 minute.
- const { data, isLoading } = useHappychatAvailable(
- Boolean( chatStatus?.is_user_eligible ),
- 60 * 1000
+ const { data, isLoading: isLoadingAvailability } = useMessagingAvailability(
+ Boolean( chatStatus?.is_user_eligible )
);
+ const { data: supportActivity, isLoading: isLoadingSupportActivity } = useSupportActivity(
+ Boolean( chatStatus?.is_user_eligible )
+ );
+
+ const isLoading = isLoadingAvailability || isLoadingSupportActivity;
if ( ! chatStatus?.is_user_eligible ) {
return {
@@ -24,7 +26,7 @@ export function useShouldRenderChatOption(): Result {
isLoading,
state: chatStatus?.is_chat_closed ? 'CLOSED' : 'UNAVAILABLE',
eligible: false,
- env: data?.env,
+ to: '',
};
} else if ( chatStatus?.is_chat_closed ) {
return {
@@ -32,15 +34,17 @@ export function useShouldRenderChatOption(): Result {
state: 'CLOSED',
isLoading,
eligible: true,
- env: data?.env,
+ to: '',
};
- } else if ( data?.available ) {
+ } else if ( data?.is_available ) {
+ const hasActiveChats = supportActivity?.some( ( ticket ) => ticket.channel === 'Messaging' );
+ const to = hasActiveChats ? '/inline-chat' : '/contact-form?mode=CHAT';
return {
render: true,
state: 'AVAILABLE',
isLoading,
eligible: true,
- env: data.env,
+ to,
};
}
return {
@@ -48,6 +52,6 @@ export function useShouldRenderChatOption(): Result {
state: 'UNAVAILABLE',
isLoading,
eligible: true,
- env: data?.env,
+ to: '',
};
}
diff --git a/packages/help-center/src/hooks/use-zendesk-config.ts b/packages/help-center/src/hooks/use-zendesk-config.ts
new file mode 100644
index 0000000000000..95e3764a80357
--- /dev/null
+++ b/packages/help-center/src/hooks/use-zendesk-config.ts
@@ -0,0 +1,19 @@
+import { useQuery } from '@tanstack/react-query';
+
+function requestZendeskConfig() {
+ return window.fetch( 'https://wpcom.zendesk.com/embeddable/config' );
+}
+
+export default function useZendeskConfig( enabled: boolean ) {
+ return useQuery( [ 'getZendeskConfig' ], requestZendeskConfig, {
+ staleTime: Infinity,
+ retry: false,
+ refetchOnMount: false,
+ retryOnMount: false,
+ refetchOnWindowFocus: false,
+ meta: {
+ persist: false,
+ },
+ enabled,
+ } );
+}
diff --git a/packages/help-center/src/index.ts b/packages/help-center/src/index.ts
index 239b70f422f74..4c71f8eb6c08b 100644
--- a/packages/help-center/src/index.ts
+++ b/packages/help-center/src/index.ts
@@ -4,7 +4,6 @@ export { SuccessIcon } from './components/success-icon';
export { SuccessScreen } from './components/ticket-success-screen';
export { BackButton } from './components/back-button';
export { HelpCenterContactForm } from './components/help-center-contact-form';
-export { useHCWindowCommunicator } from './happychat-window-communicator';
export { default as Mail } from './icons/mail';
export { default as NewReleases } from './icons/new-releases';
export * from './support-variations';
diff --git a/packages/help-center/src/types.ts b/packages/help-center/src/types.ts
index cd36b7d88c5da..ce0f928f208e8 100644
--- a/packages/help-center/src/types.ts
+++ b/packages/help-center/src/types.ts
@@ -60,3 +60,13 @@ export interface SupportTicket {
url: string;
when: string;
}
+
+export interface MessagingAuth {
+ user: {
+ jwt: string;
+ };
+}
+
+export interface MessagingAvailability {
+ is_available: boolean;
+}