Skip to content

Commit

Permalink
Help Center: add Zendesk to Odie Client
Browse files Browse the repository at this point in the history
  • Loading branch information
arcangelini committed Oct 1, 2024
1 parent 88fd918 commit 5647651
Show file tree
Hide file tree
Showing 22 changed files with 458 additions and 243 deletions.
7 changes: 7 additions & 0 deletions packages/data-stores/src/help-center/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ export const setShowHelpCenter = function* ( show: boolean ) {
} as const;
};

export const setSupportProvider = ( supportProvider: 'odie' | 'zendesk' ) =>
( {
type: 'HELP_CENTER_SET_SUPPORT_PROVIDER',
supportProvider,
} ) as const;

export const setSubject = ( subject: string ) =>
( {
type: 'HELP_CENTER_SET_SUBJECT',
Expand Down Expand Up @@ -145,6 +151,7 @@ export type HelpCenterAction =
| ReturnType<
| typeof setShowMessagingLauncher
| typeof setShowMessagingWidget
| typeof setSupportProvider
| typeof setSubject
| typeof resetStore
| typeof receiveHasSeenWhatsNewModal
Expand Down
8 changes: 7 additions & 1 deletion packages/data-stores/src/help-center/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ export function register(): typeof STORE_KEY {
reducer,
controls: { ...controls, ...wpcomRequestControls },
selectors,
persist: [ 'message', 'userDeclaredSite', 'userDeclaredSiteUrl', 'subject' ],
persist: [
'supportProvider',
'message',
'userDeclaredSite',
'userDeclaredSiteUrl',
'subject',
],
} );
isRegistered = true;
}
Expand Down
11 changes: 11 additions & 0 deletions packages/data-stores/src/help-center/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,18 @@ const odieBotNameSlug: Reducer< string | undefined, HelpCenterAction > = ( state
return state;
};

const supportProvider: Reducer< 'odie' | 'zendesk', HelpCenterAction > = (
state = 'odie',
action
) => {
if ( action.type === 'HELP_CENTER_SET_SUPPORT_PROVIDER' ) {
return action.supportProvider;
}
return state;
};

const reducer = combineReducers( {
supportProvider,
showHelpCenter,
showMessagingLauncher,
showMessagingWidget,
Expand Down
1 change: 1 addition & 0 deletions packages/data-stores/src/help-center/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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 getSupportProvider = ( state: State ) => state.supportProvider;
export const getSubject = ( state: State ) => state.subject;
export const getMessage = ( state: State ) => state.message;
export const getUserDeclaredSiteUrl = ( state: State ) => state.userDeclaredSiteUrl;
Expand Down
1 change: 0 additions & 1 deletion packages/help-center/src/components/help-center-footer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CardFooter } from '@wordpress/components';
import { Route, Routes } from 'react-router-dom';
import { HelpCenterContactButton } from './help-center-contact-page';

import './help-center-footer.scss';

const HelpCenterFooter: React.FC = () => {
Expand Down
46 changes: 35 additions & 11 deletions packages/help-center/src/components/help-center-odie.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,43 @@
/**
* Styles for '/odie' route.
*/
.help-center .help-center__container .help-center__container-content .help-center__container-content-wrapper .help-center__container-content-odie {
display: flex;
height: 100%;
max-height: 752px;
flex-direction: column;
max-width: 410px;
padding: 0;
.help-center__container-content-odie {
padding-bottom: 72px;
}

.help-center__container-footer.chat-footer {
background-color: var(--studio-white);
position: fixed;
bottom: 0;
left: 0;
right: 0;
border-top: 1px solid var(--studio-gray-5);

.odie-chat-message-input-container {
border-radius: 0;
.help-center__container-odie-send-button {
width: 100%;
display: flex;
flex-direction: row;
gap: 10px;

textarea {
box-sizing: border-box;
height: 40px;
padding: 10px 16px;
border: 1px solid var(--studio-gray-5);
border-radius: 2px;
flex: 2;
}

@media screen and (max-width: 660px) {
max-width: 100%;
button {
box-sizing: border-box;
display: flex;
width: 40px;
height: 40px;
padding: 8px 10px;
justify-content: center;
align-items: center;
background-color: var(--studio-wordpress-blue);
border-radius: 2px;
}
}
}
100 changes: 68 additions & 32 deletions packages/help-center/src/components/help-center-odie.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,31 @@
import { recordTracksEvent } from '@automattic/calypso-analytics';
import { Gridicon } from '@automattic/components';
import OdieAssistantProvider, {
OdieAssistant,
useOdieAssistantContext,
EllipsisMenu,
isOdieAllowedBot,
useOdieSendMessage,
MessagesContainer,
} from '@automattic/odie-client';
import { useSelect } from '@wordpress/data';
import { useSelect, useDispatch } from '@wordpress/data';
import { useI18n } from '@wordpress/react-i18n';
import React, { useCallback } from 'react';
import { useNavigate, Navigate } from 'react-router-dom';
import React, {
useCallback,
useEffect,
useState,
type KeyboardEvent,
type MouseEvent,
} from 'react';
import { Navigate } from 'react-router-dom';
import PopoverMenuItem from 'calypso/components/popover-menu/item';
import { useHelpCenterContext } from '../contexts/HelpCenterContext';
import { useShouldUseWapuu } from '../hooks';
import { SendIcon } from '../icons/send';
import { HELP_CENTER_STORE } from '../stores';
/**
* Internal Dependencies
*/
import { BackButtonHeader } from './back-button';
import { ExtraContactOptions } from './help-center-extra-contact-option';
import './help-center-odie.scss';
import type { HelpCenterSelect } from '@automattic/data-stores';
import type { OdieAllowedBots } from '@automattic/odie-client/src/types/index';
Expand All @@ -33,6 +40,53 @@ interface ProtectedRouteProps {
children: React.ReactNode;
}

export const HelpCenterSendButton = () => {
const { setSupportProvider } = useDispatch( HELP_CENTER_STORE );
const { provider } = useOdieAssistantContext();
const [ messageString, setMessageString ] = useState< string >( '' );
const { mutateAsync: sendOdieMessage } = useOdieSendMessage();

useEffect( () => {
setSupportProvider( provider );
}, [ provider ] );

const handleSendMessage = async (
event: MouseEvent< HTMLButtonElement > | KeyboardEvent< HTMLTextAreaElement >
) => {
const isButtonClick = event.type === 'click';
const isEnterKey = ( event as KeyboardEvent ).key === 'Enter' && ! event.shiftKey;

if ( messageString.trim().length > 0 && ( isEnterKey || isButtonClick ) ) {
event.preventDefault();
setMessageString( '' );
await sendOdieMessage( {
message: {
content: messageString as string,
role: 'user',
type: 'message',
},
} );
}
};

return (
<div className="help-center__container-odie-send-button">
<textarea
className="odie-send-message-input"
rows={ 1 }
value={ messageString }
onChange={ ( event: React.ChangeEvent< HTMLTextAreaElement > ) =>
setMessageString( event.currentTarget.value )
}
onKeyDown={ handleSendMessage }
/>
<button onClick={ handleSendMessage }>
<SendIcon />
</button>
</div>
);
};

// Prevent not eligible users from accessing odie/wapuu.
const ProtectedRoute: React.FC< ProtectedRouteProps > = ( {
condition,
Expand Down Expand Up @@ -79,7 +133,6 @@ export function HelpCenterOdie( {
isUserEligible: boolean;
searchTerm: string;
} ): JSX.Element {
const navigate = useNavigate();
const shouldUseWapuu = useShouldUseWapuu();
const preventOdieAccess = ! shouldUseWapuu && ! isUserEligible;
const { currentUser, site } = useHelpCenterContext();
Expand All @@ -98,23 +151,6 @@ export function HelpCenterOdie( {
};
}, [] );

const navigateToSupportDocs = useCallback(
( blogId: string, postId: string, title: string, link: string ) => {
navigate(
`/post?blogId=${ blogId }&postId=${ postId }&title=${ title }&link=${ link }&backUrl=/odie`
);
},
[ navigate ]
);

const navigateToContactOptions = useCallback( () => {
if ( isUserEligible ) {
navigate( '/contact-options' );
} else {
navigate( '/contact-form?mode=FORUM' );
}
}, [ navigate, isUserEligible ] );

const trackEvent = useCallback(
( eventName: string, properties: Record< string, unknown > = {} ) => {
recordTracksEvent( eventName, properties );
Expand All @@ -135,18 +171,18 @@ export function HelpCenterOdie( {
logger={ trackEvent }
loggerEventNamePrefix="calypso_odie"
selectedSiteId={ site?.ID as number }
extraContactOptions={ <ExtraContactOptions isUserEligible={ isUserEligible } /> }
navigateToContactOptions={ navigateToContactOptions }
navigateToSupportDocs={ navigateToSupportDocs }
isUserEligible={ isUserEligible }
>
<div className="help-center__container-odie-header">
<BackButtonHeader className="help-center__container-odie-back-button">
<OdieEllipsisMenu />
</BackButtonHeader>
</div>
<div className="help-center__container-content-odie">
<div className="help-center__container-odie-header">
<BackButtonHeader className="help-center__container-odie-back-button">
<OdieEllipsisMenu />
</BackButtonHeader>
</div>
<OdieAssistant />
<MessagesContainer currentUser={ currentUser } />
</div>
<div className="help-center__container-footer chat-footer">
<HelpCenterSendButton />
</div>
</OdieAssistantProvider>
</ProtectedRoute>
Expand Down
48 changes: 35 additions & 13 deletions packages/help-center/src/components/help-center.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* External Dependencies
*/
import { initializeAnalytics } from '@automattic/calypso-analytics';
import { useZendeskMessagingBindings, useLoadZendeskMessaging } from '@automattic/zendesk-client';
import { useSelect } from '@wordpress/data';
import { useLoadZendeskMessaging, useSmooch } from '@automattic/zendesk-client';
import { useSelect, useDispatch } from '@wordpress/data';
import { createPortal, useEffect, useRef } from '@wordpress/element';
/**
* Internal Dependencies
Expand All @@ -28,13 +28,15 @@ const HelpCenter: React.FC< Container > = ( {
currentRoute = window.location.pathname + window.location.search,
} ) => {
const portalParent = useRef( document.createElement( 'div' ) ).current;
const { isHelpCenterShown, isMinimized } = useSelect( ( select ) => {
const { isHelpCenterShown, isMinimized, supportProvider } = useSelect( ( select ) => {
const helpCenterSelect: HelpCenterSelect = select( HELP_CENTER_STORE );
return {
isHelpCenterShown: helpCenterSelect.isHelpCenterShown(),
isMinimized: helpCenterSelect.getIsMinimized(),
supportProvider: helpCenterSelect.getSupportProvider(),
};
}, [] );
const { setUnreadCount } = useDispatch( HELP_CENTER_STORE );

const { currentUser } = useHelpCenterContext();

Expand All @@ -46,14 +48,31 @@ const HelpCenter: React.FC< Container > = ( {

useActionHooks();

const { hasActiveChats, isEligibleForChat } = useChatStatus();
const { isEligibleForChat } = useChatStatus();
const { isMessagingScriptLoaded } = useLoadZendeskMessaging(
'zendesk_support_chat_key',
( isHelpCenterShown && isEligibleForChat ) || hasActiveChats,
isEligibleForChat || hasActiveChats
isHelpCenterShown && isEligibleForChat,
isEligibleForChat
);
const { init, initSmooch, destroy, addUnreadCountListener } = useSmooch();
const ref = useRef( null );

useZendeskMessagingBindings( HELP_CENTER_STORE, hasActiveChats, isMessagingScriptLoaded );
useEffect( () => {
if ( isMessagingScriptLoaded && ref?.current ) {
initSmooch( ref.current );
}
return () => {
destroy();
};
}, [ isMessagingScriptLoaded, ref?.current ] );

useEffect( () => {
if ( init && supportProvider ) {
addUnreadCountListener( ( unreadCount: number ) => {
setUnreadCount( unreadCount );
} );
}
}, [ init, setUnreadCount, supportProvider ] );

const openingCoordinates = useOpeningCoordinates( isHelpCenterShown, isMinimized );

Expand All @@ -73,12 +92,15 @@ const HelpCenter: React.FC< Container > = ( {
}, [ portalParent, handleClose ] );

return createPortal(
<HelpCenterContainer
handleClose={ handleClose }
hidden={ hidden }
currentRoute={ currentRoute }
openingCoordinates={ openingCoordinates }
/>,
<>
<HelpCenterContainer
handleClose={ handleClose }
hidden={ hidden }
currentRoute={ currentRoute }
openingCoordinates={ openingCoordinates }
/>
<div ref={ ref } style={ { display: 'none' } }></div>
</>,
portalParent
);
};
Expand Down
10 changes: 10 additions & 0 deletions packages/help-center/src/icons/send.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const SendIcon = () => (
<svg width="24" height="24" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.33236 0.748331C1.30236 0.322331 0.272363 1.35533 0.700363 2.38433L2.40236 6.31433L9.88336 6.88933C10.0064 6.89933 10.0064 7.07933 9.88336 7.08933L2.40036 7.66433L0.700363 11.5733C0.271363 12.6023 1.30236 13.6353 2.33236 13.2093L14.5974 8.13333C15.6274 7.70733 15.6274 6.24933 14.5974 5.82333L2.33236 0.748331Z"
fill="white"
/>
</svg>
);
Loading

0 comments on commit 5647651

Please sign in to comment.