Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { isCSATMessage } from '../../../utils';
import {
hasFeedbackForm,
isAttachment,
isTransitionToSupportMessage,
isZendeskChatStartedMessage,
isZendeskIntroMessage,
} from '../../../utils/csat';
import ChatWithSupportLabel from '../../chat-with-support';
Expand Down Expand Up @@ -112,7 +112,7 @@ export function MessagesClusterizer( { messages }: { messages: Message[] } ) {
const { currentUser } = useOdieAssistantContext();

return groups.map( ( group ) => {
const startingHumanSupport = group.messages.some( isTransitionToSupportMessage );
const startingHumanSupport = group.messages.some( isZendeskChatStartedMessage );
const endingHumanSupport = group.messages.some( isCSATMessage );

const messageHeader = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
.odie-chatbox-message {
margin-bottom: 16px;
}

.odie-chatbox-message-meta {
margin-bottom: 0;
}
}

&.role-business {
Expand Down
18 changes: 11 additions & 7 deletions packages/odie-client/src/components/message/messages-container.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { isTestModeEnvironment } from '@automattic/zendesk-client';
import { Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import clx from 'classnames';
import { useEffect, useRef, useState } from 'react';
import { NavigationType, useNavigate, useNavigationType, useSearchParams } from 'react-router-dom';
Expand Down Expand Up @@ -27,6 +29,7 @@ interface ChatMessagesProps {
export const MessagesContainer = ( { currentUser }: ChatMessagesProps ) => {
const { chat, isChatLoaded, isUserEligibleForPaidSupport, forceEmailSupport } =
useOdieAssistantContext();
const isTestMode = isTestModeEnvironment();
const createZendeskConversation = useCreateZendeskConversation();
const [ searchParams, setSearchParams ] = useSearchParams();
const navigate = useNavigate();
Expand Down Expand Up @@ -143,13 +146,14 @@ export const MessagesContainer = ( { currentUser }: ChatMessagesProps ) => {
{ chat.messages?.length > 0 && <MessagesClusterizer messages={ chat.messages } /> }
<JumpToRecent containerReference={ messagesContainerRef } />

{ chat.provider === 'odie' && chat.status === 'sending' && (
<div
className="odie-chatbox__action-message"
ref={ ( div ) => div?.scrollIntoView( { behavior: 'smooth', block: 'end' } ) }
>
<ThinkingPlaceholder />
</div>
{ chat.provider === 'odie' && chat.status === 'sending' && <ThinkingPlaceholder /> }
{ chat.provider === 'odie' && chat.status === 'transfer' && (
<ThinkingPlaceholder
content={
__( 'Requesting human support', __i18n_text_domain__ ) +
( isTestMode ? '… (ZENDESK STAGING)' : '…' )
}
/>
) }
{ chat.provider.startsWith( 'zendesk' ) && (
<ZendeskTypingIndicator conversationId={ chat.conversationId } />
Expand Down
4 changes: 4 additions & 0 deletions packages/odie-client/src/components/message/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ $blueberry-color: #3858e9;
display: none;
}
}

.odie-chatbox-thinking-placeholder {
align-items: center;
}
}

.odie-chatbox-message {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { ThinkingMessage } from '@automattic/agenttic-ui';

export const ThinkingPlaceholder = () => {
export const ThinkingPlaceholder = ( { content }: { content?: string } ) => {
return (
<div className="agenttic">
<ThinkingMessage />
<div
className="odie-chatbox__action-message"
ref={ ( div ) => div?.scrollIntoView( { behavior: 'smooth', block: 'end' } ) }
>
<div className="odie-chatbox-thinking-placeholder agenttic">
<ThinkingMessage content={ content } />
</div>
</div>
);
};
32 changes: 19 additions & 13 deletions packages/odie-client/src/components/message/user-message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,31 @@ export const UserMessage = ( {
const showGetSupport = isLastBotMessage && ( isRequestingHumanSupport || isErrorMessage );
const showActionButtons = ! isRequestingHumanSupport && ! isErrorMessage;

const shouldOverrideWithForwardMessage = isRequestingHumanSupport && chat.provider !== 'zendesk';
const messageContent = () => {
if ( ! isRequestingHumanSupport ) {
return message.content;
}

const messageContent = shouldOverrideWithForwardMessage
? getDisplayMessage(
!! hasRecentOpenConversation,
isUserEligibleForPaidSupport,
canConnectToZendesk,
forceEmailSupport,
isChatRestricted,
message?.context?.flags?.is_error_message,
isChatLoaded
)
: message.content;
if ( chat.provider === 'zendesk' ) {
return '';
}

return getDisplayMessage(
!! hasRecentOpenConversation,
isUserEligibleForPaidSupport,
canConnectToZendesk,
forceEmailSupport,
isChatRestricted,
message?.context?.flags?.is_error_message,
isChatLoaded
);
};

return (
<>
<div className="odie-chatbox-message__content">
<MarkdownOrChildren
messageContent={ messageContent }
messageContent={ messageContent() }
components={ {
a: ( props: React.ComponentProps< 'a' > ) => <CustomALink { ...props } />,
} }
Expand Down
38 changes: 15 additions & 23 deletions packages/odie-client/src/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function getFlowFromBotSlug( botSlug?: OdieAllBotSlugs ): string {
return 'wpcom';
}

export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] => {
export const getOdieTransferMessages = ( botSlug?: OdieAllBotSlugs ): Message[] => {
const isTestMode = isTestModeEnvironment();
const flow = getFlowFromBotSlug( botSlug );

Expand All @@ -73,7 +73,6 @@ export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] =
context: {
flags: {
hide_disclaimer_content: true,
show_contact_support_msg: true,
show_ai_avatar: false,
},
site_id: null,
Expand All @@ -91,7 +90,6 @@ export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] =
context: {
flags: {
hide_disclaimer_content: true,
show_contact_support_msg: false,
show_ai_avatar: false,
},
site_id: null,
Expand All @@ -111,7 +109,6 @@ export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] =
context: {
flags: {
hide_disclaimer_content: true,
show_contact_support_msg: true,
show_ai_avatar: false,
},
site_id: null,
Expand All @@ -132,7 +129,6 @@ export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] =
context: {
flags: {
hide_disclaimer_content: true,
show_contact_support_msg: true,
show_ai_avatar: false,
},
site_id: null,
Expand All @@ -148,7 +144,6 @@ export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] =
context: {
flags: {
hide_disclaimer_content: true,
show_contact_support_msg: true,
show_ai_avatar: false,
},
site_id: null,
Expand All @@ -157,22 +152,6 @@ export const getOdieTransferMessage = ( botSlug?: OdieAllBotSlugs ): Message[] =
];
};

export const getOdieOnErrorTransferMessage = (): Message[] => [
{
content: getOdieErrorMessage(),
role: 'bot',
type: 'message',
context: {
flags: {
hide_disclaimer_content: true,
show_contact_support_msg: false,
show_ai_avatar: true,
},
site_id: null,
},
},
];

export const getOdieThirdPartyMessageContent = (): string =>
`${ __(
'I’m happy to connect you to a human! However, it looks like 3rd party cookies are disabled in your browser. Please turn them on for our live chat to work properly. [Use our guide](https://wordpress.com/support/third-party-cookies/)',
Expand Down Expand Up @@ -203,7 +182,6 @@ export const getOdieEmailFallbackMessage = (): Message => ( {
type: 'message',
context: {
flags: {
show_contact_support_msg: false,
forward_to_human_support: true,
},
question_tags: {
Expand Down Expand Up @@ -330,6 +308,20 @@ export const getOdieZendeskConnectionErrorMessage = (): Message => {
};
};

export const getZendeskChatStartedMetaMessage = (): Message => ( {
content: null,
role: 'bot',
type: 'meta',
internal_message_id: 'zendesk-chat-started',
context: {
site_id: null,
flags: {
hide_disclaimer_content: true,
show_ai_avatar: false,
},
},
} );

export const ODIE_THUMBS_DOWN_RATING_VALUE = 0;
export const ODIE_THUMBS_UP_RATING_VALUE = 1;

Expand Down
1 change: 0 additions & 1 deletion packages/odie-client/src/data/use-send-odie-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ const getErrorMessageForSiteIdAndInternalMessageId = (
flags: {
forward_to_human_support: true,
hide_disclaimer_content: false,
show_contact_support_msg: true,
show_ai_avatar: true,
is_error_message: true,
},
Expand Down
19 changes: 8 additions & 11 deletions packages/odie-client/src/hooks/use-create-zendesk-conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import { useUpdateZendeskUserFields, type ZendeskConversation } from '@automatti
import { useLocation, useNavigate } from 'react-router-dom';
import Smooch from 'smooch';
import {
getOdieOnErrorTransferMessage,
getOdieTransferMessage,
getErrorTryAgainLaterMessage,
getOdieTransferMessages,
getZendeskChatStartedMetaMessage,
} from '../constants';
import { useOdieAssistantContext } from '../context';
import { useManageSupportInteraction } from '../data';
import { useCurrentSupportInteraction } from '../data/use-current-support-interaction';
import type { OdieAllBotSlugs } from '../types';

export const useCreateZendeskConversation = () => {
const {
Expand Down Expand Up @@ -81,10 +80,9 @@ export const useCreateZendeskConversation = () => {
active_interaction_id: activeInteractionId || null,
is_chat_loaded: isChatLoaded,
} );
const errorMessageObj = getErrorTryAgainLaterMessage();

setChat( {
messages: [ ...previousMessages, errorMessageObj ],
messages: [ ...previousMessages, getErrorTryAgainLaterMessage() ],
status: 'loaded',
provider: previousProvider,
conversationId: previousConversationId,
Expand All @@ -94,14 +92,8 @@ export const useCreateZendeskConversation = () => {
} );
};

// Get transfer messages to identify and remove them on error
const transferMessages = isFromError
? getOdieOnErrorTransferMessage()
: getOdieTransferMessage( currentSupportInteraction?.bot_slug as OdieAllBotSlugs );

setChat( ( prevChat ) => ( {
...prevChat,
messages: [ ...prevChat.messages, ...transferMessages ],
status: 'transfer',
} ) );

Expand Down Expand Up @@ -186,6 +178,11 @@ export const useCreateZendeskConversation = () => {
setChat( ( prevChat ) => ( {
...prevChat,
conversationId: conversationId,
messages: [
...prevChat.messages,
...getOdieTransferMessages( currentSupportInteraction?.bot_slug ),
getZendeskChatStartedMetaMessage(),
],
provider: 'zendesk',
status: 'loaded',
} ) );
Expand Down
9 changes: 4 additions & 5 deletions packages/odie-client/src/hooks/use-get-combined-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useIsMutating } from '@tanstack/react-query';
import { useSelect } from '@wordpress/data';
import { useState, useEffect, useRef } from '@wordpress/element';
import { getMessageUniqueIdentifier } from '../components/message/utils/get-message-unique-identifier';
import { getOdieTransferMessage } from '../constants';
import { getOdieTransferMessages, getZendeskChatStartedMetaMessage } from '../constants';
import { emptyChat } from '../context';
import { useGetZendeskConversation, useManageSupportInteraction, useOdieChat } from '../data';
import { useCurrentSupportInteraction } from '../data/use-current-support-interaction';
Expand All @@ -14,7 +14,7 @@ import {
getOdieIdFromInteraction,
getIsRequestingHumanSupport,
} from '../utils';
import type { Chat, Message, OdieAllBotSlugs } from '../types';
import type { Chat, Message } from '../types';

function isEqual( message1: Message, message2: Message ) {
const message1Id = getMessageUniqueIdentifier( message1 );
Expand Down Expand Up @@ -142,9 +142,8 @@ export const useGetCombinedChat = (
conversationId: conversation.id,
messages: [
...( odieChat ? filteredOdieMessages : [] ),
...getOdieTransferMessage(
currentSupportInteraction?.bot_slug as OdieAllBotSlugs
),
...getOdieTransferMessages( currentSupportInteraction?.bot_slug ),
getZendeskChatStartedMetaMessage(),
...( deduplicateZDMessages( [
// During connection recovery, the user queued messages can be deleted. This ensure they remain. And `deduplicateZDMessages` takes of duplication.
...( isSameConversation
Expand Down
1 change: 0 additions & 1 deletion packages/odie-client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ export type Context = {
failed_zendesk_connection?: boolean;
forward_to_human_support?: boolean;
hide_disclaimer_content?: boolean;
show_contact_support_msg?: boolean;
show_ai_avatar?: boolean;
is_error_message?: boolean;
};
Expand Down
4 changes: 2 additions & 2 deletions packages/odie-client/src/utils/csat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export const isAttachment = ( message: Message ) =>
export const isZendeskIntroMessage = ( message: Message | ZendeskMessage ) =>
'source' in message && message.source?.type === 'zd:answerBot';

export const isTransitionToSupportMessage = ( message: Message ) =>
!! message?.context?.flags?.show_contact_support_msg;
export const isZendeskChatStartedMessage = ( message: Message ) =>
message?.internal_message_id === 'zendesk-chat-started';

export const hasCSATMessage = ( chat: Chat ) => {
return chat?.messages.some( isCSATMessage );
Expand Down