Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions components/Chatbot/Chatbot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import ChatbotHeader from '../Interface-Chatbot/ChatbotHeader';
import ChatbotHeaderTab from '../Interface-Chatbot/ChatbotHeaderTab';
import ChatbotTextField from '../Interface-Chatbot/ChatbotTextField';
import MessageList from '../Interface-Chatbot/Messages/MessageList';
import NotificationPage from '../Interface-Chatbot/NotificationPage';
import StarterQuestions from '../Interface-Chatbot/Messages/StarterQuestions';

// Utils
Expand Down Expand Up @@ -88,16 +89,15 @@ function Chatbot({ chatSessionId, tabSessionId }: ChatbotProps) {
const dispatch = useAppDispatch();

// State management
const { show_widget_form, greetingMessage, isToggledrawer, chatsLoading, messageIds, subThreadId, helloMsgIds } = useCustomSelector((state) => {
const { show_widget_form, isToggledrawer, chatsLoading, subThreadId, showNotificationView, notificationsCount } = useCustomSelector((state) => {
const widgetInfo = state.Hello?.[chatSessionId]?.widgetInfo
return ({
show_widget_form: typeof widgetInfo?.show_widget_form === 'boolean' ? widgetInfo?.show_widget_form : state.Hello?.[chatSessionId]?.showWidgetForm,
greetingMessage: state.Hello?.[chatSessionId]?.greeting as any,
isToggledrawer: state.Chat.isToggledrawer,
chatsLoading: state.Chat.chatsLoading,
messageIds: state.Chat.messageIds,
subThreadId: state.Chat.subThreadId,
helloMsgIds: state.Chat.helloMsgIds
notificationsCount: (state.Chat.notifications || []).length,
showNotificationView: state.appInfo?.[tabSessionId]?.showNotificationView || false,
})
});

Expand All @@ -109,8 +109,6 @@ function Chatbot({ chatSessionId, tabSessionId }: ChatbotProps) {

const { isHelloUser, currentChatId, isDefaultNavigateToChatScreen } = useReduxStateManagement({ chatSessionId, tabSessionId });

// Initialize RTLayer event listeners

// Effect to open drawer for new human users
useEffect(() => {
if (isHelloUser && !currentChatId && !mountedRef.current) {
Expand Down Expand Up @@ -138,12 +136,6 @@ function Chatbot({ chatSessionId, tabSessionId }: ChatbotProps) {
timeoutIdRef
]);

// Check if chat is empty
const isChatEmpty = isHelloUser
? (!subThreadId || helloMsgIds[subThreadId]?.length === 0) &&
(!greetingMessage || (!greetingMessage.text && !greetingMessage?.options?.length))
: !subThreadId || messageIds[subThreadId]?.length === 0;

return (
<MessageContext.Provider value={contextValue}>
<div className="flex h-screen w-full overflow-hidden relative">
Expand All @@ -170,17 +162,30 @@ function Chatbot({ chatSessionId, tabSessionId }: ChatbotProps) {
</div>
)}

{/* Form and UI components */}
{isHelloUser && show_widget_form && (
<FormComponent />
{/* Form / Call / Tab overlays — hide when user is browsing notification list
to prevent "Enter your details" form from covering notification content */}
{!(showNotificationView && notificationsCount > 0) && (
<>
{isHelloUser && show_widget_form && (
<FormComponent />
)}
<CallUI />
<ChatbotHeaderTab />
</>
)}
<CallUI />
<ChatbotHeaderTab />

{isChatEmpty ? (
<EmptyChatView />
) : (
{/* Main view routing:
1. showNotificationView + notifications → NotificationPage (list of push notifications)
2. subThreadId truthy → ActiveChatView (real channel OR notification-launched chat)
3. else → EmptyChatView (new chat / idle state) */}
{showNotificationView && notificationsCount > 0 ? (
<NotificationPage />
) : subThreadId ? (
// A thread is selected (real channel OR notification-launched chat) → active chat
<ActiveChatView isSmallScreen={isSmallScreen} />
) : (
// Fresh state, nothing selected → empty / new chat view
<EmptyChatView />
)}
</div>
</div>
Expand Down
76 changes: 58 additions & 18 deletions components/Chatbot/hooks/useHelloEffects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import useSocket from '@/hooks/socket';
import useSocketEvents from '@/hooks/socketEventHandler';
import socketManager from '@/hooks/socketManager';
import { setDataInAppInfoReducer } from '@/store/appInfo/appInfoSlice';
import { setHelloEventMessage, setOpenHelloForm } from '@/store/chat/chatSlice';
import { setAgentTeams, setGreeting, setHelloClientInfo, setHelloKeysData, setJwtToken, setUnReadCount, setWidgetInfo } from '@/store/hello/helloSlice';
import { GetSessionStorageData, SetSessionStorage } from '@/utils/ChatbotUtility';
import { useCustomSelector } from '@/utils/deepCheckSelector';
import { emitEventToParent } from '@/utils/emitEventsToParent/emitEventsToParent';
import { cleanObject, getLocalStorage } from '@/utils/utilities';
import { cleanObject, generateNewId, getLocalStorage } from '@/utils/utilities';
import debounce from 'lodash.debounce';
import { useCallback, useContext, useEffect } from 'react';
import { useDispatch } from 'react-redux';
Expand All @@ -22,17 +23,6 @@ import { useScreenSize } from './useScreenSize';
import { useTabVisibility } from './useTabVisibility';
import { useReplyContext } from '@/components/Interface-Chatbot/contexts/ReplyContext';

interface HelloMessage {
role: string;
message_id?: string;
from_name?: string;
content: string;
id?: string;
chat_id?: string;
urls?: string[];
channel?: string;
}

interface UseHelloIntegrationProps {
messageRef: React.RefObject<HTMLInputElement | HTMLTextAreaElement | null>
chatSessionId: string;
Expand All @@ -50,7 +40,7 @@ export const useHelloEffects = ({ chatSessionId, messageRef, tabSessionId }: Use

const { currentChannelId, isHelloUser } = useReduxStateManagement({ chatSessionId, tabSessionId });

const { companyId, botId, reduxChatSessionId, totalNoOfUnreadMsgs, isToggledrawer, isChatbotOpen, isChatbotMinimized, unReadCountInCurrentChannel, callToken, demo_widget, helloVariables } = useCustomSelector((state) => ({
const { companyId, botId, reduxChatSessionId, totalNoOfUnreadMsgs, isToggledrawer, isChatbotOpen, isChatbotMinimized, unReadCountInCurrentChannel, callToken, demo_widget, helloVariables, unreadNotificationCount } = useCustomSelector((state) => ({
companyId: state.Hello?.[chatSessionId]?.widgetInfo?.company_id || '',
botId: state.Hello?.[chatSessionId]?.widgetInfo?.bot_id || '',
reduxChatSessionId: state.draftData?.chatSessionId,
Expand All @@ -61,6 +51,7 @@ export const useHelloEffects = ({ chatSessionId, messageRef, tabSessionId }: Use
}, 0);
return unreadCount;
})(),
unreadNotificationCount: (state.Chat?.notifications || []).filter((n: any) => !n.read).length,
isToggledrawer: state.Chat?.isToggledrawer,
isChatbotOpen: state.appInfo?.[tabSessionId]?.isChatbotOpen,
isChatbotMinimized: state.draftData?.isChatbotMinimized,
Expand Down Expand Up @@ -92,9 +83,10 @@ export const useHelloEffects = ({ chatSessionId, messageRef, tabSessionId }: Use

useEffect(() => {
if (!demo_widget) {
emitEventToParent('SET_BADGE_COUNT', { badgeCount: totalNoOfUnreadMsgs > 99 ? '99+' : totalNoOfUnreadMsgs, channelId: '*' })
const combined = (totalNoOfUnreadMsgs || 0) + (unreadNotificationCount || 0);
emitEventToParent('SET_BADGE_COUNT', { badgeCount: combined > 99 ? '99+' : combined, channelId: '*' })
}
}, [totalNoOfUnreadMsgs, demo_widget])
}, [totalNoOfUnreadMsgs, unreadNotificationCount, demo_widget])

useSocketEvents({ messageRef, fetchChannels, chatSessionId, setLoading, tabSessionId });
useNotificationSocketEventHandler({ chatSessionId })
Expand Down Expand Up @@ -167,6 +159,56 @@ export const useHelloEffects = ({ chatSessionId, messageRef, tabSessionId }: Use
clearReply();
}, [currentChannelId]);

// Handle OPEN_WITH_NOTIFICATION messages from parent widget
// When user clicks the launcher message preview popup, the parent script posts
// 'OPEN_WITH_NOTIFICATION' with the raw notification HTML. This opens a fresh
// chat thread and inserts the notification as a bot-side message (rendered via
// ShadowDomComponent) so the user can reply to the campaign notification.
useEffect(() => {
const handleNotificationMessage = (event: MessageEvent) => {
if (event?.data?.type === 'OPEN_WITH_NOTIFICATION') {
const content = event?.data?.data?.content || '';
// Generate a fresh sub-thread key so this new chat has its own bucket
const newSubThreadId = `notification-${generateNewId()}`;
// Reset to a fresh channel and close notification view
dispatch(setDataInAppInfoReducer({
subThreadId: newSubThreadId,
currentTeamId: '',
currentChannelId: '',
currentChatId: '',
overrideChannelId: '',
showNotificationView: false,
}));
// Bypass "Enter your details" form popup BEFORE the message is added
dispatch(setOpenHelloForm(false));
// Push the notification as a bot-side message on the LEFT in the new chat
// (rendered via ShadowDomComponent for pushNotification message_type)
dispatch(setHelloEventMessage({
subThreadId: newSubThreadId,
message: {
type: 'chat',
message_type: 'pushNotification',
sender_id: 'bot',
is_auto_response: true,
content: {
text: content,
attachment: []
},
from_name: '',
id: generateNewId(),
}
}));
}
};

if (isHelloUser) {
window.addEventListener('message', handleNotificationMessage);
return () => {
window.removeEventListener('message', handleNotificationMessage);
};
}
}, [isHelloUser]);


const initializeHelloServices = async (widgetToken: string = '') => {
// Prevent duplicate initialization
Expand Down Expand Up @@ -313,9 +355,7 @@ export const useHelloEffects = ({ chatSessionId, messageRef, tabSessionId }: Use
}
}

if (true) {
emitEventToParent("ENABLE_DOMAIN_TRACKING")
}
emitEventToParent("ENABLE_DOMAIN_TRACKING")

} catch (error) {
console.error("Error initializing Hello services:", error);
Expand Down
Loading