Skip to content

Commit

Permalink
Help Center: Get unread count when new message arrives (#97120)
Browse files Browse the repository at this point in the history
Co-authored-by: heavyweight <[email protected]>
Co-authored-by: Kosta <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent 74a5d54 commit 44fb816
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { HelpCenterSelect } from '@automattic/data-stores';
import { useGetSupportInteractions } from '@automattic/odie-client/src/data';
import { useSelect, useDispatch as useDataStoreDispatch } from '@wordpress/data';
import {
useGetSupportInteractions,
useGetUnreadConversations,
} from '@automattic/odie-client/src/data';
import { useSelect } from '@wordpress/data';
import { sprintf } from '@wordpress/i18n';
import { useI18n } from '@wordpress/react-i18n';
import React, { useEffect, useState } from 'react';
import { HELP_CENTER_STORE } from '../stores';
import { HelpCenterSupportChatMessage } from './help-center-support-chat-message';
import {
calculateUnread,
getConversationsFromSupportInteractions,
getZendeskConversations,
} from './utils';
import { getConversationsFromSupportInteractions, getZendeskConversations } from './utils';
import type { ZendeskConversation } from '@automattic/odie-client';

import './help-center-recent-conversations.scss';
Expand Down Expand Up @@ -40,7 +39,7 @@ const HelpCenterRecentConversations: React.FC = () => {
return { isChatLoaded: store.getIsChatLoaded() };
}, [] );
const sectionName = GetSectionName( unreadConversationsCount );
const { setUnreadCount } = useDataStoreDispatch( HELP_CENTER_STORE );
const getUnreadNotifications = useGetUnreadConversations();

useEffect( () => {
if (
Expand All @@ -58,13 +57,12 @@ const HelpCenterRecentConversations: React.FC = () => {
allConversations,
supportInteractions
);
const { unreadConversations, unreadMessages } = calculateUnread( conversations );
const { unreadConversations, unreadMessages } = getUnreadNotifications( conversations );
setUnreadConversationsCount( unreadConversations );
setUnreadMessagesCount( unreadMessages );
setConversations( conversations );
setUnreadCount( unreadConversations );
}
}, [ isChatLoaded, setUnreadCount, supportInteractionsResolved, supportInteractionsOpen ] );
}, [ isChatLoaded, supportInteractionsResolved, supportInteractionsOpen ] );

if ( ! conversations.length ) {
return null;
Expand Down
31 changes: 24 additions & 7 deletions packages/help-center/src/components/help-center-smooch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { recordTracksEvent } from '@automattic/calypso-analytics';
import config from '@automattic/calypso-config';
import { HelpCenterSelect } from '@automattic/data-stores';
import { useGetUnreadConversations } from '@automattic/odie-client/src/data';
import {
useLoadZendeskMessaging,
useAuthenticateZendeskMessaging,
Expand All @@ -10,11 +11,11 @@ import {
SMOOCH_INTEGRATION_ID_STAGING,
} from '@automattic/zendesk-client/src/constants';
import { useSelect, useDispatch as useDataStoreDispatch } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { useCallback, useEffect, useRef } from '@wordpress/element';
import Smooch from 'smooch';
import { useChatStatus } from '../hooks';
import { HELP_CENTER_STORE } from '../stores';
import { calculateUnread, getClientId, getZendeskConversations } from './utils';
import { getClientId, getZendeskConversations } from './utils';

const destroy = () => {
Smooch.destroy();
Expand Down Expand Up @@ -57,8 +58,19 @@ const HelpCenterSmooch: React.FC< { enableAuth: boolean } > = ( { enableAuth } )
isEligibleForChat && enableAuth,
true
);
const { setIsChatLoaded, setUnreadCount, setZendeskClientId } =
useDataStoreDispatch( HELP_CENTER_STORE );
const { setIsChatLoaded, setZendeskClientId } = useDataStoreDispatch( HELP_CENTER_STORE );
const getUnreadNotifications = useGetUnreadConversations();

const getUnreadListener = useCallback(
( message: unknown, data: { conversation: { id: string } } ) => {
if ( isHelpCenterShown ) {
return;
}

Smooch.getConversationById( data?.conversation?.id ).then( () => getUnreadNotifications() );
},
[ isHelpCenterShown ]
);

// Initialize Smooch which communicates with Zendesk
useEffect( () => {
Expand Down Expand Up @@ -93,11 +105,16 @@ const HelpCenterSmooch: React.FC< { enableAuth: boolean } > = ( { enableAuth } )
useEffect( () => {
if ( isChatLoaded && getZendeskConversations ) {
const allConversations = getZendeskConversations();
const { unreadConversations } = calculateUnread( allConversations );
setUnreadCount( unreadConversations );
getUnreadNotifications( allConversations );
setZendeskClientId( getClientId( allConversations ) );
Smooch.on( 'message:received', getUnreadListener );
}
}, [ isChatLoaded, setUnreadCount, setZendeskClientId ] );

return () => {
// @ts-expect-error -- 'off' is not part of the def.
Smooch?.off?.( 'message:received', getUnreadListener );
};
}, [ getUnreadListener, isChatLoaded, getUnreadNotifications, setZendeskClientId ] );

return <div ref={ smoochRef } style={ { display: 'none' } }></div>;
};
Expand Down
18 changes: 1 addition & 17 deletions packages/help-center/src/components/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const getLastMessage = ( { conversation }: { conversation: ZendeskConvers
};

export const getZendeskConversations = () => {
const conversations = Smooch.getConversations();
const conversations = Smooch?.getConversations?.() ?? [];
return conversations as unknown as ZendeskConversation[];
};

Expand Down Expand Up @@ -90,22 +90,6 @@ export const getSortedRecentAndArchivedConversations = ( {
};
};

export const calculateUnread = ( conversations: ZendeskConversation[] ) => {
let unreadConversations = 0;
let unreadMessages = 0;

conversations.forEach( ( conversation ) => {
const unreadCount = conversation.participants[ 0 ]?.unreadCount ?? 0;

if ( unreadCount > 0 ) {
unreadConversations++;
unreadMessages += unreadCount;
}
} );

return { unreadConversations, unreadMessages };
};

export const getClientId = ( conversations: ZendeskConversation[] ): string =>
conversations
.flatMap( ( conversation ) => conversation.messages )
Expand Down
3 changes: 2 additions & 1 deletion packages/odie-client/src/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { handleSupportInteractionsFetch } from './handle-support-interactions-fetch';
export { useGetSupportInteractions } from './use-get-support-interactions';
export { getZendeskConversation } from './use-get-zendesk-conversation';
export { useGetZendeskConversation } from './use-get-zendesk-conversation';
export { useGetUnreadConversations } from './use-get-unread-conversations';
export { useManageSupportInteraction } from './use-manage-support-interaction';
export {
broadcastOdieMessage,
Expand Down
32 changes: 32 additions & 0 deletions packages/odie-client/src/data/use-get-unread-conversations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { HELP_CENTER_STORE } from '@automattic/help-center/src/stores';
import { useDispatch as useDataStoreDispatch } from '@wordpress/data';
import Smooch from 'smooch';
import { ZendeskConversation } from '../types';

const calculateUnread = ( conversations: Conversation[] | ZendeskConversation[] ) => {
let unreadConversations = 0;
let unreadMessages = 0;

conversations.forEach( ( conversation ) => {
const unreadCount = conversation.participants[ 0 ]?.unreadCount ?? 0;

if ( unreadCount > 0 ) {
unreadConversations++;
unreadMessages += unreadCount;
}
} );

return { unreadConversations, unreadMessages };
};

export const useGetUnreadConversations = () => {
const { setUnreadCount } = useDataStoreDispatch( HELP_CENTER_STORE );

return ( conversations?: Conversation[] | ZendeskConversation[] ) => {
const conversationsToCheck = conversations ? conversations : Smooch.getConversations();
const { unreadConversations, unreadMessages } = calculateUnread( conversationsToCheck );
setUnreadCount( unreadConversations );

return { unreadConversations, unreadMessages };
};
};
60 changes: 33 additions & 27 deletions packages/odie-client/src/data/use-get-zendesk-conversation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Smooch from 'smooch';
import { zendeskMessageConverter } from '../utils';
import { useGetUnreadConversations } from './use-get-unread-conversations';
import type { ZendeskMessage } from '../types';

const parseResponse = ( conversation: Conversation ) => {
Expand All @@ -18,34 +19,39 @@ const parseResponse = ( conversation: Conversation ) => {
/**
* Get the conversation for the Zendesk conversation.
*/
export const getZendeskConversation = ( {
chatId,
conversationId,
}: {
chatId: number | string | null | undefined;
conversationId?: string | null | undefined;
} ) => {
if ( ! chatId ) {
return null;
}

const conversation = Smooch.getConversations().find( ( conversation ) => {
if ( conversationId ) {
return conversation.id === conversationId;
export const useGetZendeskConversation = () => {
const getUnreadNotifications = useGetUnreadConversations();

return ( {
chatId,
conversationId,
}: {
chatId: number | string | null | undefined;
conversationId?: string | null | undefined;
} ) => {
if ( ! chatId ) {
return null;
}

return Number( conversation.metadata[ 'odieChatId' ] ) === Number( chatId );
} );
const conversation = Smooch.getConversations().find( ( conversation ) => {
if ( conversationId ) {
return conversation.id === conversationId;
}

return Number( conversation.metadata[ 'odieChatId' ] ) === Number( chatId );
} );

if ( ! conversation ) {
return null;
}

if ( ! conversation ) {
return null;
}

// We need to ensure that more than one message is loaded
return Smooch.getConversationById( conversation.id )
.then( ( conversation ) => {
Smooch.markAllAsRead( conversation.id );
return parseResponse( conversation );
} )
.catch( () => parseResponse( conversation ) );
// We need to ensure that more than one message is loaded
return Smooch.getConversationById( conversation.id )
.then( ( conversation ) => {
Smooch.markAllAsRead( conversation.id );
getUnreadNotifications();
return parseResponse( conversation );
} )
.catch( () => parseResponse( conversation ) );
};
};
4 changes: 2 additions & 2 deletions packages/odie-client/src/hooks/use-get-combined-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSelect } from '@wordpress/data';
import { useState, useEffect } from '@wordpress/element';
import { getOdieTransferMessageConstant } from '../constants';
import { emptyChat } from '../context';
import { getZendeskConversation, useOdieChat } from '../data';
import { useGetZendeskConversation, useOdieChat } from '../data';
import type { Chat, Message } from '../types';

/**
Expand All @@ -24,7 +24,7 @@ export const useGetCombinedChat = (
}, [] );

const [ mainChatState, setMainChatState ] = useState< Chat >( emptyChat );

const getZendeskConversation = useGetZendeskConversation();
// Get the current odie chat
const odieId =
currentSupportInteraction?.events.find( ( event ) => event.event_source === 'odie' )
Expand Down
32 changes: 22 additions & 10 deletions packages/odie-client/src/hooks/use-zendesk-message-listener.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HelpCenterSelect } from '@automattic/data-stores';
import { HELP_CENTER_STORE } from '@automattic/help-center/src/stores';
import { useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { useCallback, useEffect } from '@wordpress/element';
import Smooch from 'smooch';
import { useOdieAssistantContext } from '../context';
import { zendeskMessageConverter } from '../utils';
Expand All @@ -25,12 +25,8 @@ export const useZendeskMessageListener = () => {
( event ) => event.event_source === 'zendesk'
)?.event_external_id;

useEffect( () => {
if ( ! isChatLoaded ) {
return;
}

Smooch.on( 'message:received', ( message, data ) => {
const messageListener = useCallback(
( message: unknown, data: { conversation: { id: string } } ) => {
const zendeskMessage = message as ZendeskMessage;

if ( data.conversation.id === chat.conversationId ) {
Expand All @@ -42,11 +38,27 @@ export const useZendeskMessageListener = () => {
} ) );
Smooch.markAllAsRead( data.conversation.id );
}
} );
},
[ chat.conversationId, setChat ]
);

useEffect( () => {
if ( ! isChatLoaded ) {
return;
}

Smooch.on( 'message:received', messageListener );

return () => {
// @ts-expect-error -- 'off' is not part of the def.
Smooch?.off( 'message:received' );
Smooch?.off?.( 'message:received', messageListener );
};
}, [ isChatLoaded, currentZendeskConversationId, chat, setChat, currentSupportInteraction ] );
}, [
isChatLoaded,
currentZendeskConversationId,
chat,
setChat,
currentSupportInteraction,
messageListener,
] );
};

0 comments on commit 44fb816

Please sign in to comment.