From 7cc0499240c9a8c697e9828f7543625d64eb1f34 Mon Sep 17 00:00:00 2001
From: Daniel
Date: Fri, 24 Jan 2025 18:49:22 +0100
Subject: [PATCH] =?UTF-8?q?[Odie]=C2=A0Give=20Wapuu=20a=20chance=20(#98419?=
=?UTF-8?q?)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [Odie] Give Wapuu a chance
* Fix thumbs down issue
* Rename variable from removeDislike to removeDislikeStatus
* Fix autoscroll when using the experiment
* HasUserEverEscalated was lost during merge/conflicts
* Fix TSC error
* Separate logic for show extra contact options and show direct escalation link
---
.../components/message/message-content.tsx | 8 +++++-
.../components/message/messages-container.tsx | 12 ++++++---
.../src/components/message/user-message.tsx | 27 +++++++++++++++----
packages/odie-client/src/context/index.tsx | 17 ++++++++++++
.../src/data/use-send-odie-message.ts | 13 ++++++---
.../odie-client/src/hooks/use-auto-scroll.ts | 6 ++++-
packages/odie-client/src/types.ts | 10 ++++++-
7 files changed, 79 insertions(+), 14 deletions(-)
diff --git a/packages/odie-client/src/components/message/message-content.tsx b/packages/odie-client/src/components/message/message-content.tsx
index 781444323eea4..567731d4b7593 100644
--- a/packages/odie-client/src/components/message/message-content.tsx
+++ b/packages/odie-client/src/components/message/message-content.tsx
@@ -1,6 +1,7 @@
import { useI18n } from '@wordpress/react-i18n';
import clsx from 'clsx';
import Markdown from 'react-markdown';
+import { useOdieAssistantContext } from '../../context';
import { zendeskMessageConverter } from '../../utils';
import ChatWithSupportLabel from '../chat-with-support';
import CustomALink from './custom-a-link';
@@ -24,6 +25,7 @@ export const MessageContent = ( {
displayChatWithSupportLabel?: boolean;
} ) => {
const { __ } = useI18n();
+ const { experimentVariationName } = useOdieAssistantContext();
const messageClasses = clsx(
'odie-chatbox-message',
`odie-chatbox-message-${ message.role }`,
@@ -35,6 +37,9 @@ export const MessageContent = ( {
isNextMessageFromSameSender && 'next-chat-message-same-sender'
);
+ const stopConflatingNegativeRatingWithContactSupport =
+ experimentVariationName === 'give_wapuu_a_chance';
+
const isMessageWithOnlyText =
message.context?.flags?.hide_disclaimer_content ||
message.context?.question_tags?.inquiry_type === 'user-is-greeting';
@@ -97,7 +102,8 @@ export const MessageContent = ( {
) }
- { message.type === 'dislike-feedback' &&
@@ -134,8 +140,8 @@ export const MessagesContainer = ( { currentUser }: ChatMessagesProps ) => {
/>
) ) }
- { chat.status === 'dislike' &&
}
- { [ 'sending', 'dislike', 'transfer' ].includes( chat.status ) && (
+ { chat.status === 'dislike' && ! removeDislikeStatus &&
}
+ { availableStatusWithFeedback.includes( chat.status ) && (
{ chat.status === 'sending' && }
{ chat.status === 'dislike' && }
diff --git a/packages/odie-client/src/components/message/user-message.tsx b/packages/odie-client/src/components/message/user-message.tsx
index 53eea4ceee8ab..13c6a29366ca4 100644
--- a/packages/odie-client/src/components/message/user-message.tsx
+++ b/packages/odie-client/src/components/message/user-message.tsx
@@ -22,17 +22,34 @@ export const UserMessage = ( {
message: Message;
isMessageWithoutEscalationOption?: boolean;
} ) => {
- const { isUserEligibleForPaidSupport, trackEvent, chat } = useOdieAssistantContext();
+ const {
+ isUserEligibleForPaidSupport,
+ hasUserEverEscalatedToHumanSupport,
+ trackEvent,
+ chat,
+ experimentVariationName,
+ } = useOdieAssistantContext();
const hasCannedResponse = message.context?.flags?.canned_response;
- const isRequestingHumanSupport = message.context?.flags?.forward_to_human_support;
+ const isRequestingHumanSupport = message.context?.flags?.forward_to_human_support ?? false;
const hasFeedback = !! message?.rating_value;
const isBot = message.role === 'bot';
const isConnectedToZendesk = chat?.provider === 'zendesk';
const isPositiveFeedback =
hasFeedback && message && message.rating_value && +message.rating_value === 1;
- const showExtraContactOptions =
- ( hasFeedback && ! isPositiveFeedback ) || isRequestingHumanSupport;
+
+ const isExperimentGiveWapuuAChance = experimentVariationName === 'give_wapuu_a_chance';
+
+ let showExtraContactOptions = false;
+ if ( isExperimentGiveWapuuAChance ) {
+ showExtraContactOptions = isRequestingHumanSupport;
+ } else {
+ showExtraContactOptions = ( hasFeedback && ! isPositiveFeedback ) || isRequestingHumanSupport;
+ }
+
+ const showDirectEscalationLink = isExperimentGiveWapuuAChance
+ ? hasUserEverEscalatedToHumanSupport
+ : ! ( hasFeedback && ! isPositiveFeedback ) || isRequestingHumanSupport;
const forwardMessage = isUserEligibleForPaidSupport
? ODIE_FORWARD_TO_ZENDESK_MESSAGE
@@ -83,7 +100,7 @@ export const UserMessage = ( {
}
) }
- { ! showExtraContactOptions &&
}
+ { showDirectEscalationLink &&
}
{ ! isConnectedToZendesk && (
) }
diff --git a/packages/odie-client/src/context/index.tsx b/packages/odie-client/src/context/index.tsx
index 17112afaabcb3..ed05db38321ea 100644
--- a/packages/odie-client/src/context/index.tsx
+++ b/packages/odie-client/src/context/index.tsx
@@ -37,12 +37,15 @@ export const OdieAssistantContext = createContext< OdieAssistantContextInterface
canConnectToZendesk: false,
clearChat: noop,
currentUser: { display_name: 'Me' },
+ experimentVariationName: null,
+ hasUserEverEscalatedToHumanSupport: false,
isChatLoaded: false,
isMinimized: false,
isUserEligibleForPaidSupport: false,
odieBroadcastClientId: '',
setChat: noop,
setChatStatus: noop,
+ setExperimentVariationName: noop,
setMessageLikedStatus: noop,
setWaitAnswerToFirstMessageFromHumanSupport: noop,
trackEvent: noop,
@@ -84,12 +87,23 @@ export const OdieAssistantProvider: React.FC< OdieAssistantProviderProps > = ( {
};
}, [] );
+ const [ experimentVariationName, setExperimentVariationName ] = useState<
+ string | null | undefined
+ >( null );
+
/**
* The main chat thread.
* This is where we manage the state of the chat.
*/
const { mainChatState, setMainChatState } = useGetCombinedChat( canConnectToZendesk );
+ /**
+ * Has the user ever escalated to get human support?
+ */
+ const hasUserEverEscalatedToHumanSupport = mainChatState?.messages.some(
+ ( message ) => message.context?.flags?.forward_to_human_support
+ );
+
/**
* Tracking event.
* Handler to make sure all requests are the same.
@@ -176,13 +190,16 @@ export const OdieAssistantProvider: React.FC< OdieAssistantProviderProps > = ( {
extraContactOptions,
isChatLoaded,
isMinimized,
+ experimentVariationName,
isUserEligibleForPaidSupport,
canConnectToZendesk,
+ hasUserEverEscalatedToHumanSupport,
odieBroadcastClientId,
selectedSiteId,
selectedSiteURL,
userFieldMessage,
setChatStatus,
+ setExperimentVariationName,
setMessageLikedStatus,
setWaitAnswerToFirstMessageFromHumanSupport,
trackEvent,
diff --git a/packages/odie-client/src/data/use-send-odie-message.ts b/packages/odie-client/src/data/use-send-odie-message.ts
index a40ae3aca9842..2978a42589bd0 100644
--- a/packages/odie-client/src/data/use-send-odie-message.ts
+++ b/packages/odie-client/src/data/use-send-odie-message.ts
@@ -34,8 +34,15 @@ export const useSendOdieMessage = () => {
const internal_message_id = generateUUID();
const queryClient = useQueryClient();
- const { botNameSlug, selectedSiteId, version, setChat, odieBroadcastClientId, setChatStatus } =
- useOdieAssistantContext();
+ const {
+ botNameSlug,
+ selectedSiteId,
+ version,
+ setChat,
+ odieBroadcastClientId,
+ setChatStatus,
+ setExperimentVariationName,
+ } = useOdieAssistantContext();
const addMessage = ( message: Message | Message[], props?: Partial< Chat > ) => {
setChat( ( prevChat ) => ( {
@@ -111,7 +118,7 @@ export const useSendOdieMessage = () => {
type: 'message',
context: returnedChat.messages[ 0 ].context,
};
-
+ setExperimentVariationName( returnedChat.experiment_name );
addMessage( botMessage, { odieId: returnedChat.chat_id } );
broadcastOdieMessage( botMessage, odieBroadcastClientId );
},
diff --git a/packages/odie-client/src/hooks/use-auto-scroll.ts b/packages/odie-client/src/hooks/use-auto-scroll.ts
index 54cfc8c1561ae..aada915ad4487 100644
--- a/packages/odie-client/src/hooks/use-auto-scroll.ts
+++ b/packages/odie-client/src/hooks/use-auto-scroll.ts
@@ -2,7 +2,7 @@ import { RefObject, useEffect, useRef } from 'react';
import { useOdieAssistantContext } from '../context';
export const useAutoScroll = ( messagesContainerRef: RefObject< HTMLDivElement > ) => {
- const { chat } = useOdieAssistantContext();
+ const { chat, experimentVariationName } = useOdieAssistantContext();
const debounceTimeoutRef = useRef< number >( 500 );
const debounceTimeoutIdRef = useRef< number | null >( null );
const lastChatStatus = useRef< string | null >( null );
@@ -12,6 +12,10 @@ export const useAutoScroll = ( messagesContainerRef: RefObject< HTMLDivElement >
return;
}
+ if ( experimentVariationName === 'give_wapuu_a_chance' && chat.status === 'dislike' ) {
+ return;
+ }
+
if ( debounceTimeoutIdRef.current ) {
clearTimeout( debounceTimeoutIdRef.current );
}
diff --git a/packages/odie-client/src/types.ts b/packages/odie-client/src/types.ts
index 8827fabe92c37..fef9a56502197 100644
--- a/packages/odie-client/src/types.ts
+++ b/packages/odie-client/src/types.ts
@@ -10,6 +10,8 @@ export type OdieAssistantContextInterface = {
chat: Chat;
clearChat: () => void;
currentUser: CurrentUser;
+ experimentVariationName: string | undefined | null;
+ hasUserEverEscalatedToHumanSupport: boolean;
isMinimized?: boolean;
isUserEligibleForPaidSupport: boolean;
extraContactOptions?: ReactNode;
@@ -18,6 +20,7 @@ export type OdieAssistantContextInterface = {
selectedSiteURL?: string | null;
userFieldMessage?: string | null;
waitAnswerToFirstMessageFromHumanSupport: boolean;
+ setExperimentVariationName: ( variationName: string | null | undefined ) => void;
setMessageLikedStatus: ( message: Message, liked: boolean ) => void;
setChat: ( chat: Chat | SetStateAction< Chat > ) => void;
setChatStatus: ( status: ChatStatus ) => void;
@@ -156,7 +159,12 @@ export type Message = {
export type ChatStatus = 'loading' | 'loaded' | 'sending' | 'dislike' | 'transfer' | 'closed';
-export type ReturnedChat = { chat_id: number; messages: Message[]; wpcom_user_id: number };
+export type ReturnedChat = {
+ chat_id: number;
+ messages: Message[];
+ wpcom_user_id: number;
+ experiment_name: string | undefined | null;
+};
export type OdieChat = {
messages: Message[];