diff --git "a/C:\\chatknot\\app/(dashboard)/chat/page.js" "b/C:\\chatknot\\old backup\\app/(dashboard)/chat/page.js" index 920a683..62a866b 100644 --- "a/C:\\chatknot\\app/(dashboard)/chat/page.js" +++ "b/C:\\chatknot\\old backup\\app/(dashboard)/chat/page.js" @@ -14,10 +14,9 @@ import firefox from "@/public/assets/images/firefox-icon.png"; import edge from "@/public/assets/images/edge.png"; import safari from "@/public/assets/images/safari-icon.png"; -import { FaMobileAlt, FaDesktop, FaTabletAlt } from "react-icons/fa"; import ubunto from "@/public/assets/images/ubunto.png"; import android from "@/public/assets/images/android.png"; -const notificationSound = "/sounds/chatalert.mp3"; +import notificationSound from "@/public/sounds/chatalert.mp3"; import { addTab, minimize } from "../../lib/features/chat/chatSlice"; import FilterChats from "./FilterChats"; import axios from "axios"; @@ -32,15 +31,13 @@ const Chat = () => { const [visitors, setVisitors] = useState([]); const [hideColumns, setHideColumns] = useState(false); const [blinkingVisitor, setBlinkingVisitor] = useState([]); - const { activeTab } = useSelector((state) => state.chat); + const { activeTab } = useSelector((state) => state.chat); const [IsShowPK, setIsShowPK] = useState(false); const [ShowAlert, setShowAlert] = useState(false); const [showFilter, setShowFilter] = useState(false); - const selectedBrands = useSelector( - (state) => state.selectedBrands.selectedBrands, - ); + const selectedBrands = useSelector((state) => state.selectedBrands.selectedBrands); const [filteredVisitors, setFilteredVisitors] = useState([]); - + const [brands, setBrands] = useState([]); const [filteredBrand, setFilteredBrand] = useState([]); const toggleFilterChats = () => { @@ -92,7 +89,7 @@ const Chat = () => { second: "2-digit", hour12: true, // Change to false for 24-hour format if desired }).format(serverUtcTime); - + return userLocalTime; } @@ -118,51 +115,54 @@ const Chat = () => { // } // ); // setBrands(response.data); - // + // // setFilteredBrand(response.data); - + // } catch (error) { // console.error("Error fetching brands:", error); - + // } // }; const fetchBrands = async () => { try { - const forchat = { - forChat: true, - }; const response = await apiRequest( `/api/companies/${user.company_id}/brands`, - "GET", - forchat, + 'GET' ); - setBrands(response); - // + + setBrands(response); + // setFilteredBrand(response); + } catch (error) { console.error("Error fetching brands:", error.message); + + } }; - + if (user?.company_id) { fetchBrands(); } }, []); useEffect(() => { + + if (selectedBrands.length > 0) { // Filter visitors based on selected brands setFilteredVisitors((prevVisitors) => { // Only keep visitors whose public_key is in selectedBrands return visitors.filter((visitor) => - selectedBrands.includes(visitor.public_key), + selectedBrands.includes(visitor.public_key) ); }); } else { // If no brand is selected, reset the filtered visitors to show all visitors setFilteredVisitors(visitors); } - }, [selectedBrands, visitors]); // Re-run the effect when selectedBrands or visitors changes + }, [selectedBrands,visitors]); // Re-run the effect when selectedBrands or visitors changes + useEffect(() => { // Ensure socket instance is created once @@ -170,18 +170,18 @@ const Chat = () => { if (!socketinst) return; setSocket(socketinst); - + // Emit brand ID to the backend when the page loads socketinst.emit("page load", { brand_id: bid }); const handleActiveVisitors = async (data) => { const decryptedData = await decryptData(data); - + if (!decryptedData || typeof decryptedData !== "object") { console.error("Decryption failed or returned invalid data"); return; } - + let { client_id, public_key, @@ -198,16 +198,15 @@ const Chat = () => { browser, brand_name, totalMsgCount, - device_size, } = decryptedData; - - // Now this should work correctly - - // if (country === 'Pakistan' && !IsShowPK) { + + // Now this should work correctly + + // if (country === 'Pakistan' && !IsShowPK) { // return; // } - const j_time = emitTimeInUserTimezone(join_time); + const j_time = emitTimeInUserTimezone(join_time); // Save the original join_time with client_id setOriginalJoinTimes((prevTimes) => ({ ...prevTimes, @@ -221,6 +220,8 @@ const Chat = () => { hour12: true, }); + + const newVisitor = { name: client_name ? client_name : null, client_id: client_id, @@ -239,16 +240,18 @@ const Chat = () => { unseenMsg: unseenMsg, brand_name: brand_name, totalMessages: totalMsgCount, - device_size: device_size, }; - + setVisitors((prevVisitors) => { + // Check if the visitor with the same client_id already exists const existingVisitorIndex = prevVisitors.findIndex( - (v) => v.client_id === client_id, + (v) => v.client_id === client_id ); - + + if (existingVisitorIndex > -1) { + // Update existing visitor const updatedVisitors = [...prevVisitors]; updatedVisitors[existingVisitorIndex] = newVisitor; @@ -259,23 +262,26 @@ const Chat = () => { } }); if (selectedBrands.length === 0 || selectedBrands.includes(public_key)) { - setFilteredVisitors((prevVisitors) => { - // Check if the visitor with the same client_id already exists - const existingVisitorIndex = prevVisitors.findIndex( - (v) => v.client_id === client_id, - ); - - if (existingVisitorIndex > -1) { - // Update existing visitor - const updatedVisitors = [...prevVisitors]; - updatedVisitors[existingVisitorIndex] = newVisitor; - return updatedVisitors; - } else { - // Add new visitor only if it doesn't already exist - return [...prevVisitors, newVisitor]; - } - }); - } + setFilteredVisitors((prevVisitors) => { + + // Check if the visitor with the same client_id already exists + const existingVisitorIndex = prevVisitors.findIndex( + (v) => v.client_id === client_id + ); + + + if (existingVisitorIndex > -1) { + + // Update existing visitor + const updatedVisitors = [...prevVisitors]; + updatedVisitors[existingVisitorIndex] = newVisitor; + return updatedVisitors; + } else { + // Add new visitor only if it doesn't already exist + return [...prevVisitors, newVisitor]; + } + }); + } }; const handleNewClient = (data) => { @@ -293,7 +299,6 @@ const Chat = () => { country, status, browser, - device_size, } = decryptedData; // if (country === 'Pakistan' && !IsShowPK) { @@ -316,7 +321,7 @@ const Chat = () => { }); const newVisitor = { - name: client_name ? client_name : null, + name: client_name ? client_name : null, client_id: client_id, online: joinDate, servedBy: "", @@ -332,65 +337,73 @@ const Chat = () => { browser: browser, brand_name: brand_name, totalMessages: 0, - device_size: device_size, }; // Update the state with the new visitor setVisitors((prevVisitors) => { + const updatedVisitors = [newVisitor, ...prevVisitors]; // Log inside setState to ensure proper order return updatedVisitors; }); + + + + +// Determine whether to update filtered visitors +if (selectedBrands.length === 0 || selectedBrands.includes(public_key)) { + setFilteredVisitors((prevVisitors) => { + // Only add newVisitor if the public_key is in selectedBrands or selectedBrands is empty + return [newVisitor, ...prevVisitors]; + }); +} - // Determine whether to update filtered visitors - if (selectedBrands.length === 0 || selectedBrands.includes(public_key)) { - setFilteredVisitors((prevVisitors) => { - // Only add newVisitor if the public_key is in selectedBrands or selectedBrands is empty - return [newVisitor, ...prevVisitors]; - }); - } }; const handleVisitorServedByUpdate = (data) => { - const decryptedData = decryptData(data); + const decryptedData = decryptData(data) const { client_id, served_by } = decryptedData; setVisitors((prevVisitors) => { + return prevVisitors.map((visitor) => visitor.client_id === client_id ? { ...visitor, servedBy: served_by } - : visitor, - ); - }); - - setFilteredVisitors((prevVisitors) => { - return prevVisitors.map((visitor) => - visitor.client_id === client_id - ? { ...visitor, servedBy: served_by } - : visitor, + : visitor ); }); + + setFilteredVisitors((prevVisitors) => { + return prevVisitors.map((visitor) => + visitor.client_id === client_id + ? { ...visitor, servedBy: served_by } + : visitor + ); + }); + }; const handleVisitorStatusChange = (data) => { - const decryptedData = decryptData(data); - - const { client_id, served_by, status, visitor_id } = decryptedData; - setVisitors((prevVisitors) => { + const decryptedData = decryptData(data) + + const { client_id, served_by ,status,visitor_id} = decryptedData; + setVisitors((prevVisitors) => { + if (status === 4) { if (currentChat?.client_id == client_id) { setHideColumns(false); setCurrentChat(null); } return prevVisitors.filter( - (visitor) => visitor.client_id !== client_id, + (visitor) => visitor.client_id !== client_id ); } else { // Update visitor's status in the list - + + const updatedVisitors = prevVisitors.map((visitor) => visitor.client_id === client_id ? { ...visitor, visitorStatus: status } - : visitor, + : visitor ); // If the current chat's visitor's status is updated, also update the currentChat state @@ -404,36 +417,39 @@ const Chat = () => { return updatedVisitors; } }); + + setFilteredVisitors((prevVisitors) => { + + if (status === 4) { + if (currentChat?.client_id == client_id) { + setHideColumns(false); + setCurrentChat(null); + } + return prevVisitors.filter( + (visitor) => visitor.client_id !== client_id + ); + } else { + // Update visitor's status in the list + + + const updatedVisitors = prevVisitors.map((visitor) => + visitor.client_id === client_id + ? { ...visitor, visitorStatus: status } + : visitor + ); - setFilteredVisitors((prevVisitors) => { - if (status === 4) { - if (currentChat?.client_id == client_id) { - setHideColumns(false); - setCurrentChat(null); - } - return prevVisitors.filter( - (visitor) => visitor.client_id !== client_id, - ); - } else { - // Update visitor's status in the list - - const updatedVisitors = prevVisitors.map((visitor) => - visitor.client_id === client_id - ? { ...visitor, visitorStatus: status } - : visitor, - ); - - // If the current chat's visitor's status is updated, also update the currentChat state - if (currentChat?.client_id === client_id) { - setCurrentChat((prevChat) => ({ - ...prevChat, - visitorStatus: status, - })); - } + // If the current chat's visitor's status is updated, also update the currentChat state + if (currentChat?.client_id === client_id) { + setCurrentChat((prevChat) => ({ + ...prevChat, + visitorStatus: status, + })); + } - return updatedVisitors; - } - }); + return updatedVisitors; + } + }); + }; const playNotificationSound = () => { const audio = new Audio(notificationSound); @@ -441,52 +457,56 @@ const Chat = () => { }; const handleNewMessageBlink = (data) => { - const decryptedData = decryptData(data); - const message = decryptedData; - - setVisitors((prevVisitors) => { + + const decryptedData = decryptData(data) + const message = decryptedData + + + + setVisitors((prevVisitors) => { + return prevVisitors.map((visitor) => visitor.client_id === message.client_id ? { ...visitor, totalMessages: message.totalMessages } - : visitor, + : visitor ); - }); - setFilteredVisitors((prevVisitors) => { + }); setFilteredVisitors((prevVisitors) => { + return prevVisitors.map((visitor) => visitor.client_id === message.client_id ? { ...visitor, totalMessages: message.totalMessages } - : visitor, + : visitor ); }); - + // if(message.public_key != brand_pk){ // return null; // } if (message.isParticipant) { // playNotificationSound(); } - // If notifyAllAdmins is false, check if userId exists in unseenCounts - if ( - !message.notifyAllAdmins && - !message.unseenCounts.hasOwnProperty(user.userId) - ) { - // - return; - } + // If notifyAllAdmins is false, check if userId exists in unseenCounts + if (!message.notifyAllAdmins && !message.unseenCounts.hasOwnProperty(user.userId)) { + // + return; +} // Only add to blinking state if the current chat is NOT the one receiving the message if (activeTab || activeTab !== message.client_id) { + + setVisitors((prevVisitors) => { + return prevVisitors.map((visitor) => visitor.client_id === message.client_id ? { ...visitor, unseenMsg: message.unseenCount } - : visitor, + : visitor ); - }); - setFilteredVisitors((prevVisitors) => { + }); setFilteredVisitors((prevVisitors) => { + return prevVisitors.map((visitor) => visitor.client_id === message.client_id ? { ...visitor, unseenMsg: message.unseenCount } - : visitor, + : visitor ); }); setBlinkingVisitor((prevBlinkingVisitors) => { @@ -496,63 +516,70 @@ const Chat = () => { return prevBlinkingVisitors; }); } else { + // If current chat is the same as the message client, we can remove blinking removeBlinkingVisitor(message.client_id); } }; const handleClientDataUpdate = (data) => { - const decryptedData = decryptData(data); + const decryptedData = decryptData(data) const updatedData = decryptedData; - + const { client_id, name, email, phone, notes, tags } = updatedData; setVisitors((prevVisitors) => { - // Update visitor's status in the list - const updatedVisitors = prevVisitors.map((visitor) => - visitor.client_id === client_id - ? { ...visitor, name: name } - : visitor, - ); + + // Update visitor's status in the list + const updatedVisitors = prevVisitors.map((visitor) => + visitor.client_id === client_id + ? { ...visitor, name: name } + : visitor + ); - return updatedVisitors; + return updatedVisitors; }); setFilteredVisitors((prevVisitors) => { - // Update visitor's status in the list - const updatedVisitors = prevVisitors.map((visitor) => - visitor.client_id === client_id - ? { ...visitor, name: name } - : visitor, - ); + + // Update visitor's status in the list + const updatedVisitors = prevVisitors.map((visitor) => + visitor.client_id === client_id + ? { ...visitor, name: name } + : visitor + ); - return updatedVisitors; + return updatedVisitors; }); + + + }; const handleMessageSeen = (data) => { - const decryptedData = decryptData(data); - if (decryptedData.user_id != user.userId) { + const decryptedData = decryptData(data) + if(decryptedData.user_id != user.userId){ return null; } - const message = decryptedData; - setVisitors((prevVisitors) => + const message = decryptedData + setVisitors((prevVisitors) => prevVisitors.map((visitor) => visitor.client_id === message.client_id ? { ...visitor, unseenMsg: 0 } - : visitor, - ), - ); - setFilteredVisitors((prevVisitors) => + : visitor + ) + ); setFilteredVisitors((prevVisitors) => prevVisitors.map((visitor) => visitor.client_id === message.client_id ? { ...visitor, unseenMsg: 0 } - : visitor, - ), + : visitor + ) ); }; const handleChatMessage = (message) => { // const decryptedData = decryptData(data) // const message = decryptedData - - if (activeTab || activeTab !== message.client_id) { + + + + if (activeTab || activeTab !== message.client_id) { // Play sound // const audio = new Audio(notificationSound); // Adjust the path if necessary // audio.play().catch(err => { @@ -571,10 +598,10 @@ const Chat = () => { socketinst.on("visitor status change", handleVisitorStatusChange); socketinst.on("chat message", handleChatMessage); socketinst.on("New message blink", handleNewMessageBlink); - socketinst.on("client data updated", handleClientDataUpdate); + socketinst.on('client data updated', handleClientDataUpdate); socketinst.on("message_seen", handleMessageSeen); socketinst.on("visitor_already_left", (data) => { - const decryptedData = decryptData(data); + const decryptedData = decryptData(data) customOnClick(); }); @@ -587,7 +614,7 @@ const Chat = () => { socketinst.off("visitor status change", handleVisitorStatusChange); socketinst.off("New message blink", handleNewMessageBlink); socketinst.off("chat message", handleChatMessage); - socketinst.off("client data updated", handleClientDataUpdate); + socketinst.off('client data updated', handleClientDataUpdate); socketinst.off("message_seen", handleMessageSeen); // socketinst.off('chat message', handleChatMessage); }; @@ -599,9 +626,12 @@ const Chat = () => { }, 3000); }; const handleVisitorClick = (visitor) => { - if (user.is_private == 1 && visitor.servedBy == "") { - return; - } + + + + if(user.is_private == 1 && visitor.servedBy == ""){ + return + } if (activeTab && activeTab === visitor.client_id) { setHideColumns(false); dispatch(minimize({ client_id: activeTab })); @@ -609,7 +639,7 @@ const Chat = () => { chatKey: `${visitor.public_key}_${visitor.client_id}`, from: user?.pseudonym, }); - + socket.emit("admin_closed_chat", { client_id: visitor.client_id, public_key: visitor.public_key, @@ -622,7 +652,7 @@ const Chat = () => { setHideColumns(false); dispatch(minimize({ client_id: activeTab })); } - + // Create a new copy of the visitor object const updatedVisitor = { ...visitor, @@ -633,13 +663,15 @@ const Chat = () => { const visitorCopy = { ...updatedVisitor }; delete visitorCopy.online; delete visitorCopy.join_time; - + setCurrentChat(updatedVisitor); - + + socket.emit("join chat", updatedVisitor); - + let updatedVi = { ...visitorCopy }; // Clone the visitorCopy object - + + if (visitor.servedBy) { updatedVi = { ...updatedVi, // Keep existing visitor data @@ -651,13 +683,14 @@ const Chat = () => { servedBy: false, // Add/Update servedBy flag }; } - + // Dispatch action to add the updated tab in the Redux store dispatch(addTab(updatedVi)); - + setHideColumns(true); } }; + const handleVisitorNameClick = () => { setHideColumns(!hideColumns); @@ -681,20 +714,20 @@ const Chat = () => { }; const handleShowPkChange = (e) => { - setIsShowPK(e.target.checked); + setIsShowPK(e.target.checked); }; // Categorize visitors, adding "Not Served" category const categorizedVisitors = { active: filteredVisitors.filter( - (v) => (v.visitorStatus === 1 || v.visitorStatus === 5) && v.servedBy, + (v) => (v.visitorStatus === 1 || v.visitorStatus === 5) && v.servedBy ), // Exclude not served notServed: filteredVisitors.filter((v) => !v.servedBy), // New category for visitors not served idle: filteredVisitors.filter((v) => v.visitorStatus === 2 && v.servedBy), // Exclude not served from idle closed: filteredVisitors.filter((v) => v.visitorStatus === 3 && v.servedBy), // Exclude not served from closed }; const noVisitorsFound = Object.values(categorizedVisitors).every( - (category) => category.length === 0, + (category) => category.length === 0 ); const [collapsedSections, setCollapsedSections] = useState({ active: false, @@ -705,16 +738,16 @@ const Chat = () => { const countPakistaniVisitors = () => { const counts = { active: categorizedVisitors.active.filter( - (visitor) => visitor.country === "Pakistan", + (visitor) => visitor.country === "Pakistan" ).length, notServed: categorizedVisitors.notServed.filter( - (visitor) => visitor.country === "Pakistan", + (visitor) => visitor.country === "Pakistan" ).length, idle: categorizedVisitors.idle.filter( - (visitor) => visitor.country === "Pakistan", + (visitor) => visitor.country === "Pakistan" ).length, closed: categorizedVisitors.closed.filter( - (visitor) => visitor.country === "Pakistan", + (visitor) => visitor.country === "Pakistan" ).length, }; return counts; @@ -779,166 +812,171 @@ const Chat = () => {
-
- - {selectedBrandNames.length > 0 && ( -
- {selectedBrandNames.map((name, index) => ( - - {name} - - ))} -
- )} -
+
+ + {selectedBrandNames.length > 0 && ( +
+ {selectedBrandNames.map((name, index) => ( + + {name} + + ))} +
+ )} +
-
- -
+
+
+
- {noVisitorsFound ? ( -
-

No visitor found.

-
- ) : ( -
- {categorizedVisitors.active.length > 0 && ( - <> -

toggleSection("active")} - className="collapsible-header" - > - Active Visitors ( - {IsShowPK - ? categorizedVisitors.active.length - : categorizedVisitors.active.length - - categorizedVisitors.active.filter( - (visitor) => visitor.country === "Pakistan", - ).length} - ) {collapsedSections.active ? "+" : "-"} -

- - {!collapsedSections.active && ( - - )} - - )} - - {categorizedVisitors.notServed.length > 0 && ( - <> -

toggleSection("notServed")} - className="collapsible-header mt-3" - > - Not Served Visitors ( - {IsShowPK - ? categorizedVisitors.notServed.length - : categorizedVisitors.notServed.length - - categorizedVisitors.notServed.filter( - (visitor) => visitor.country === "Pakistan", - ).length} - ) {collapsedSections.notServed ? "+" : "-"} -

- {!collapsedSections.notServed && ( - - )} - - )} - - {categorizedVisitors.closed.length > 0 && ( - <> -

toggleSection("closed")} - className="collapsible-header mt-3" - > - Closed Chats ( - {IsShowPK - ? categorizedVisitors.closed.length - : categorizedVisitors.closed.length - - categorizedVisitors.closed.filter( - (visitor) => visitor.country === "Pakistan", - ).length} - ) {collapsedSections.closed ? "+" : "-"} -

- {!collapsedSections.closed && ( - - )} - - )} - - {categorizedVisitors.idle.length > 0 && ( - <> -

toggleSection("idle")} - className="collapsible-header mt-3" - > - Idle Visitors ( - {IsShowPK - ? categorizedVisitors.idle.length - : categorizedVisitors.idle.length - - categorizedVisitors.idle.filter( - (visitor) => visitor.country === "Pakistan", - ).length} - ) {collapsedSections.idle ? "+" : "-"} -

- {!collapsedSections.idle && ( - - )} - - )} -
- )} + {noVisitorsFound ? ( +
+

No visitor found.

+
+ ) :( +
+ {categorizedVisitors.active.length > 0 && ( + <> +

toggleSection("active")} className="collapsible-header"> + Active Visitors{" "} + ( + {IsShowPK + ? categorizedVisitors.active.length + : categorizedVisitors.active.length - + categorizedVisitors.active.filter( + (visitor) => visitor.country === "Pakistan" + ).length} + ) + {" "}{collapsedSections.active ? "+" : "-"} +

+ + {!collapsedSections.active && ( + + )} + + )} + + {categorizedVisitors.notServed.length > 0 && ( + <> +

toggleSection("notServed")} + className="collapsible-header mt-3" + > + Not Served Visitors{" "} + ( + {IsShowPK + ? categorizedVisitors.notServed.length + : categorizedVisitors.notServed.length - + categorizedVisitors.notServed.filter( + (visitor) => visitor.country === "Pakistan" + ).length} + ) + {" "}{collapsedSections.notServed ? "+" : "-"} +

+ {!collapsedSections.notServed && ( + + )} + + )} + + {categorizedVisitors.closed.length > 0 && ( + <> +

toggleSection("closed")} + className="collapsible-header mt-3" + > + Closed Chats{" "} + ( + {IsShowPK + ? categorizedVisitors.closed.length + : categorizedVisitors.closed.length - + categorizedVisitors.closed.filter( + (visitor) => visitor.country === "Pakistan" + ).length} + ) + {" "}{collapsedSections.closed ? "+" : "-"} +

+ {!collapsedSections.closed && ( + + )} + + )} + + {categorizedVisitors.idle.length > 0 && ( + <> +

toggleSection("idle")} + className="collapsible-header mt-3" + > + Idle Visitors{" "} + ( + {IsShowPK + ? categorizedVisitors.idle.length + : categorizedVisitors.idle.length - + categorizedVisitors.idle.filter( + (visitor) => visitor.country === "Pakistan" + ).length} + ) + {" "}{collapsedSections.idle ? "+" : "-"} +

+ {!collapsedSections.idle && ( + + )} + + )} +
+ ) + + } {/* {hideColumns && } */}
@@ -956,8 +994,8 @@ const VisitorTable = ({ type, IsShowPK, }) => { - const { activeTab } = useSelector((state) => state.chat); - + const { activeTab } = useSelector((state) => state.chat); + return ( @@ -980,6 +1018,7 @@ const VisitorTable = ({ + {visitors.map((visitor, index) => ( { const [onlineTime, setOnlineTime] = useState(""); - + // Calculate the online time based on the joinTime const calculateOnlineTime = useCallback(() => { const now = new Date(); - + + const onlineDate = online && Number(online) > 0 ? new Date(online) : now; const diffMs = now - new Date(onlineDate); const diffMins = Math.floor(diffMs / (1000 * 60)); const diffHrs = Math.floor(diffMins / 60); const remainingMins = diffMins % 60; - + return `${diffHrs > 0 ? diffHrs + "h " : ""}${remainingMins}m`; }, [online]); // Use `useMemo` to calculate the initial `onlineTime` and prevent unnecessary re-renders const initialOnlineTime = useMemo( () => calculateOnlineTime(), - [calculateOnlineTime], + [calculateOnlineTime] ); useEffect(() => { @@ -1061,6 +1101,8 @@ const VisitorRow = ({ return () => clearInterval(interval); }, [calculateOnlineTime, initialOnlineTime]); + + // Helper to get browser name const getBrowserName = (browser) => { if (browser?.includes("Chrome")) { @@ -1131,50 +1173,10 @@ const VisitorRow = ({ } }; - const getDeviceType = (deviceSizeStr) => { - try { - if (!deviceSizeStr) return "unknown"; - let sizeObj = - typeof deviceSizeStr === "string" - ? JSON.parse(deviceSizeStr) - : deviceSizeStr; - return sizeObj?.type || "unknown"; - } catch (e) { - return "unknown"; - } - }; - - const getDeviceIcon = (deviceSizeStr) => { - const type = getDeviceType(deviceSizeStr).toLowerCase(); - if (type === "mobile") { - return ( - - ); - } else if (type === "tablet") { - return ( - - ); - } else if (type === "desktop") { - return ( - - ); - } - return null; - }; - // Helper to get country flag as an image const currentVisitorData = blinkingVisitor.find( - (v) => v.client_id === visitor.client_id, + (v) => v.client_id === visitor.client_id ); const unseenCount = currentVisitorData ? currentVisitorData.unseenCount : 0; @@ -1191,17 +1193,18 @@ const VisitorRow = ({ ) : null; }; - const { activeTab } = useSelector((state) => state.chat); + const { activeTab } = useSelector((state) => state.chat); return ( 0 ? "new-message-blink-row" : ""} visitor-row-new ${ + className={`${unseenMsg > 0 ? "new-message-blink-row":""} visitor-row-new ${ visitor?.country === "Pakistan" && !IsShowPK ? "hide-pakistan-visitors" : "" } ${activeTab === chatId ? "active-history-row" : ""} `} - onClick={() => onVisitorNameClick(visitor)} + onClick={() => onVisitorNameClick(visitor)} > + {visitor?.country === "Pakistan" && !IsShowPK} @@ -1273,16 +1267,17 @@ const VisitorRow = ({ {visitorStatus == 1 || 5 ? onlineTime : visitorStatus == 2 - ? "idle" - : visitorStatus == 3 - ? "close chat" - : ""} + ? "idle" + : visitorStatus == 3 + ? "close chat" + : ""} + {brand_name} + + {/* */} @@ -1298,5 +1293,6 @@ const VisitorRow = ({ ); }; - + export default Chat; + \ No newline at end of file diff --git "a/C:\\chatknot\\app/(dashboard)/history/page.js" "b/C:\\chatknot\\old backup\\app/(dashboard)/history/page.js" index a20e626..3c668a0 100644 --- "a/C:\\chatknot\\app/(dashboard)/history/page.js" +++ "b/C:\\chatknot\\old backup\\app/(dashboard)/history/page.js" @@ -1,5 +1,5 @@ "use client"; -import { useState, useEffect, useCallback, useRef, useMemo } from "react"; +import { useState, useEffect, useCallback, useRef } from "react"; import { useSelector } from "react-redux"; import { countryNameToCode } from "@/app/countries"; import { getSocket } from "@/app/lib/socketManager"; @@ -32,10 +32,10 @@ const History = () => { const [error, setError] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [totalPages, setTotalPages] = useState(1); - const user = useSelector((state) => state.user.userInfo); - const limit = user?.userId === 111 ? 25 : 50; + const limit = 50; const [socket, setSocket] = useState(null); const [hideColumns, setHideColumns] = useState(false); + const user = useSelector((state) => state.user.userInfo); const [searchTerm, setSearchTerm] = useState(""); // New search term state const [chatSessionId, SetChatSessionId] = useState(); const [NewHistoryRecieved, setNewHistoryRecieved] = useState([]); @@ -53,7 +53,7 @@ const History = () => { const [filterCurrentPage, setFilterCurrentPage] = useState(1); const [filterTotalPages, setFilterTotalPages] = useState(1); const [servedStatus, setservedStatus] = useState("all"); - const [connectedStatus, setconnectedStatus] = useState("all"); +const [connectedStatus, setconnectedStatus] = useState("all"); const token = getCookie("token"); // const [selectedBrands, setSelectedBrands] = useState([]); const [filteredTotalRecords, setfilteredTotalRecords] = useState(0); @@ -68,10 +68,9 @@ const History = () => { const [showSettings, setShowSettings] = useState(false); const [selectedBrands, setSelectedBrands] = useState([]); const [brands, setBrands] = useState([]); - const [filteredBrands, setFilteredBrand] = useState([]); + const [filteredBrands, setFilteredBrand] = useState(); const [dateRange, setDateRange] = useState(null); - const [activePreset, setActivePreset] = useState(null); // const filteredBrands = allBrands.filter((brand) => // brand.toLowerCase().includes(brandSearch.toLowerCase()) @@ -86,8 +85,8 @@ const History = () => { prevVisitors.map((visitor) => visitor.visitor_session_id === visitorSessionId ? { ...visitor, IP_Health: newIpHealth } - : visitor, - ), + : visitor + ) ); }; @@ -120,6 +119,7 @@ const History = () => { }; }, [showSettings]); + const applyDateRange = async () => { setLoading(true); setisFiltering(true); @@ -133,16 +133,12 @@ const History = () => { setShowDatePicker(false); // Close date picker after applying the date range try { - const response = await apiRequest( - "/api/client/visitor-history-filterbydate", - "POST", - { - user_id: user.userId, // Pass user ID from state or context - start_date: formattedStartDate, // Start date of the range - end_date: formattedEndDate, // End date of the range - }, - ); - + const response = await apiRequest('/api/client/visitor-history-filterbydate','POST',{ + user_id: user.userId, // Pass user ID from state or context + start_date: formattedStartDate, // Start date of the range + end_date: formattedEndDate, // End date of the range + }) + // const data = await response.json(); if (response) { @@ -168,7 +164,7 @@ const History = () => { // } // ); // setBrands(response.data); - // + // // setFilteredBrand(response.data); // // Map over fetched brands to extract their IDs and add them to selectedBrands // setSelectedBrands((prev) => [ @@ -182,16 +178,9 @@ const History = () => { const fetchBrands = async () => { try { - const forchat = { - forChat: true, - }; - const response = await apiRequest( - `api/companies/${user.company_id}/brands`, - "GET", - forchat, - ); + const response = await apiRequest(`api/companies/${user.company_id}/brands`,"GET"); setBrands(response); - + setFilteredBrand(response); setSelectedBrands((prev) => [ ...prev, @@ -208,29 +197,18 @@ const History = () => { const handleSearchBrandChange = (e) => { setBrandSearch(e.target.value); const filtered = brands.filter((brand) => - brand.name.toLowerCase().includes(e.target.value.toLowerCase()), + brand.name.toLowerCase().includes(e.target.value.toLowerCase()) ); setFilteredBrand(filtered); }; const selectAllBrands = () => { const allBrandIds = filteredBrands.map((brand) => brand.id); - const areAllSelected = allBrandIds.every((id) => - selectedBrands.includes(id), - ); - + const areAllSelected = allBrandIds.every((id) => selectedBrands.includes(id)); + if (!areAllSelected) { setSelectedBrands(allBrandIds); - - searchVisitors( - searchTerm, - servedStatus, - connectedStatus, - includeClientId, - includeEmail, - includeMsg, - includeName, - selectedBrands, - ); + + searchVisitors(searchTerm, servedStatus, connectedStatus,includeClientId,includeEmail,includeMsg,includeName,selectedBrands); setFilterCurrentPage(1); setIsBrandChange((prev) => { // Ensure all brand IDs are toggled in the `isBrandChange` array @@ -254,6 +232,7 @@ const History = () => { }); } }; + const unselectAllBrands = () => { setSelectedBrands([]); @@ -273,7 +252,7 @@ const History = () => { const socketinst = getSocket(); if (!socketinst) return; const handleUpdateHistory = (data) => { - const decryptedData = decryptData(data); + const decryptedData = decryptData(data) // Assuming data contains the fields you specified const { @@ -347,7 +326,7 @@ const History = () => { year: "numeric", }; const datePart = new Intl.DateTimeFormat("en-US", dateOptions).format( - serverUtcTime, + serverUtcTime ); // Format the time part @@ -359,7 +338,7 @@ const History = () => { hour12: true, // 12-hour format }; const timePart = new Intl.DateTimeFormat("en-US", timeOptions).format( - serverUtcTime, + serverUtcTime ); // Combine the date and time parts @@ -393,9 +372,11 @@ const History = () => { const updatedBrands = selectedBrands.includes(brand.id) ? selectedBrands.filter((id) => id !== brand.id) : [...selectedBrands, brand.id]; - + setSelectedBrands(updatedBrands); // Update the state with the new list - + + + // Pass the updated list to the search function searchVisitors( searchTerm, @@ -408,6 +389,7 @@ const History = () => { updatedBrands, // Pass the updated brands list here ); }; + //opening side tab const openSideTab = (chatSession) => { @@ -424,8 +406,8 @@ const History = () => { setNewHistoryRecieved((prevState) => prevState.filter( (history) => - history.visitor_session_id !== chatSession.visitor_session_id, - ), + history.visitor_session_id !== chatSession.visitor_session_id + ) ); setHideColumns(true); } @@ -456,7 +438,8 @@ const History = () => { // Handle sorting columns // Debounced search function with pagination - + + const searchVisitors = useCallback( debounce( async ( @@ -468,13 +451,16 @@ const History = () => { includeMsg = true, includeName = true, selectedBrands = filteredBrands.map((brand) => brand.id), - page = 1, - ) => { + page = 1 + ) => { setisFiltering(true); setLoading(true); setError(null); - + try { + + + // Build the payload dynamically const payload = { user_id: user.userId, @@ -487,7 +473,7 @@ const History = () => { currentPage: page, itemsPerPage: 10, }; - + // Use passed arguments if available; otherwise, fallback to state if (statusServed) { payload.servedStatus = statusServed; @@ -495,11 +481,7 @@ const History = () => { if (statusConnected) { payload.connectedStatus = statusConnected; } - const response = await apiRequest( - "/api/client/visitor-history-search", - "POST", - payload, - ); + const response =await apiRequest('/api/client/visitor-history-search','POST',(payload)) // const response = await fetch( // `${process.env.NEXT_PUBLIC_API_URL}/api/client/visitor-history-search`, // { @@ -510,159 +492,103 @@ const History = () => { // body: JSON.stringify(payload), // } // ); - + // const data = await response.json(); - + + if (response) { + setVisitors(response.SearchData.sessionRows); setfilteredTotalRecords(response.SearchData.totalRecords); - setFilterTotalPages( - Math.ceil(response.SearchData.totalRecords / 50), - ); + setFilterTotalPages(Math.ceil(response.SearchData.totalRecords / 50)); } else { setError("Failed to fetch search results"); } } catch (err) { setError("An error occurred while searching"); } - + setLoading(false); }, - 500, + 500 ), - [ - selectedBrands, - includeName, - includeEmail, - includeClientId, - includeMsg, - servedStatus, - connectedStatus, - ], + [selectedBrands, includeName, includeEmail, includeClientId, includeMsg, servedStatus, connectedStatus] ); + + const handleFilterChange = (filterType, value) => { switch (filterType) { case "includeName": - setIncludeName(!includeName); - if (searchTerm.length > 0) - searchVisitors( - searchTerm, - servedStatus, - connectedStatus, - includeClientId, - includeEmail, - includeMsg, - !includeName, - selectedBrands, - ); + setIncludeName(!includeName ); + if(searchTerm.length>0) + searchVisitors(searchTerm, servedStatus, connectedStatus,includeClientId,includeEmail,includeMsg,!includeName,selectedBrands); break; case "includeEmail": setIncludeEmail(!includeEmail); - if (searchTerm.length > 0) - searchVisitors( - searchTerm, - servedStatus, - connectedStatus, - includeClientId, - !includeEmail, - includeMsg, - includeName, - selectedBrands, - ); + if(searchTerm.length>0) + searchVisitors(searchTerm, servedStatus, connectedStatus,includeClientId,!includeEmail,includeMsg,includeName,selectedBrands); break; case "includeClientId": setIncludeClientId(!includeClientId); // searchVisitors(!includeClientId) - if (searchTerm.length > 0) - searchVisitors( - searchTerm, - servedStatus, - connectedStatus, - !includeClientId, - includeEmail, - includeMsg, - includeName, - selectedBrands, - ); + if(searchTerm.length>0) + searchVisitors(searchTerm, servedStatus, connectedStatus,!includeClientId,includeEmail,includeMsg,includeName,selectedBrands); break; case "includeMsg": setincludeMsg(!includeMsg); - if (searchTerm.length > 0) - searchVisitors( - searchTerm, - servedStatus, - connectedStatus, - includeClientId, - includeEmail, - !includeMsg, - includeName, - selectedBrands, - ); + if(searchTerm.length>0) + searchVisitors(searchTerm, servedStatus, connectedStatus,includeClientId,includeEmail,!includeMsg,includeName,selectedBrands); break; default: break; } + // searchVisitors(searchTerm); }; - const handleStatusChange = (statusType, value) => { - if (statusType === "servedStatus") { - setservedStatus(value); - - searchVisitors( - searchTerm, - value, - connectedStatus, - includeClientId, - includeEmail, - includeMsg, - includeName, - selectedBrands, - ); - } else if (statusType === "connectedStatus") { - setconnectedStatus(value); - - searchVisitors( - searchTerm, - servedStatus, - value, - includeClientId, - includeEmail, - includeMsg, - includeName, - selectedBrands, - ); // Pass the current `servedStatus` and the updated `connectedStatus` - } - }; +const handleStatusChange = (statusType, value) => { + if (statusType === "servedStatus") { + setservedStatus(value); + + searchVisitors(searchTerm, value, connectedStatus,includeClientId,includeEmail,includeMsg,includeName,selectedBrands); + } else if (statusType === "connectedStatus") { + setconnectedStatus(value); + + searchVisitors(searchTerm, servedStatus, value,includeClientId,includeEmail,includeMsg,includeName,selectedBrands); // Pass the current `servedStatus` and the updated `connectedStatus` + } +}; + // useEffect(() => { // setFilterCurrentPage(1); // searchVisitors(searchTerm); // }, [servedStatus,connectedStatus]) - + // useEffect(() => { - // + // // if(IsBrandChange.length >0){ // setFilterCurrentPage(1); // // searchVisitors(searchTerm); - + + // searchVisitors(searchTerm, servedStatus, connectedStatus,includeClientId,includeEmail,includeMsg,includeName,selectedBrands); - // + // // } - + // }, [ // searchTerm, - + // IsBrandChange, - + // ]); // useEffect(() => { // if (isFiltering) { - // - // - + // + // + + // searchVisitors(searchTerm, servedStatus, connectedStatus,!includeClientId,includeEmail,includeMsg,includeName,filterCurrentPage); // } // }, [filterCurrentPage]); @@ -683,34 +609,21 @@ const History = () => { setFilterTotalPages(1); setSearchTerm(term); - - searchVisitors( - term, - servedStatus, - connectedStatus, - includeClientId, - includeEmail, - includeMsg, - includeName, - selectedBrands, - ); + + + searchVisitors(term, servedStatus, connectedStatus,includeClientId,includeEmail,includeMsg,includeName,selectedBrands); }; // Fetch data from the API const fetchVisitors = async (page) => { setLoading(true); setError(null); - console.log("fetchVisitors", page); - console.log("fetchVisitors", user.userId); - // Removed hardcoded block for user 111 to allow data loading try { - const response = await apiRequest( - `/api/client/visitor-history?page=${page}&limit=${limit}`, - "POST", - { user_id: user.userId }, - ); + + + const response =await apiRequest(`/api/client/visitor-history?page=${page}&limit=${limit}`,'POST',{user_id:user.userId}) // const response = await fetch( - + // `${process.env.NEXT_PUBLIC_API_URL}/api/client/visitor-history?page=${page}&limit=${limit}`, // { // method: "POST", // Using POST instead of GET @@ -724,6 +637,7 @@ const History = () => { // ); // const data = await response.json(); + if (response) { setVisitors(response.data); // assuming the API returns an array of results @@ -734,7 +648,7 @@ const History = () => { setError("Failed to fetch data"); } } catch (err) { - setError("Please try search using filters"); + setError("An error occurred while fetching data"); } setLoading(false); }; @@ -747,165 +661,35 @@ const History = () => { // const eventSource = new EventSource( // `${process.env.NEXT_PUBLIC_API_URL}/api/client/visitor-history-stream?user_id=${user.userId}&page=${page}&limit=${limit}` // ); - + + // setVisitors([]); // reset // setLoading(true); - + // eventSource.onmessage = (e) => { // const visitor = JSON.parse(e.data); // console.log(visitor); // setLoading(false) // setVisitors(prev => [...prev, visitor]); // }; - + // eventSource.addEventListener("done", () => { // setLoading(false); // eventSource.close(); // }); - + // eventSource.addEventListener("error", (e) => { // console.error("SSE error", e); // setError("Stream failed"); // setLoading(false); // eventSource.close(); // }); - + // return () => { // eventSource.close(); // }; // }; - - // Calculate analytics statistics for user 111 - const analyticsStats = useMemo(() => { - if (user?.userId !== 111 || visitors.length === 0) return null; - - const totalSessions = visitors.length; - const servedSessions = visitors.filter( - (v) => v.served_by && v.served_by !== "N/A", - ).length; - const notServedSessions = totalSessions - servedSessions; - const servedPercentage = - totalSessions > 0 - ? ((servedSessions / totalSessions) * 100).toFixed(1) - : 0; - - // Calculate top 3 brands - const brandCounts = {}; - visitors.forEach((v) => { - if (v.brand_name && v.brand_name !== "N/A") { - brandCounts[v.brand_name] = (brandCounts[v.brand_name] || 0) + 1; - } - }); - const topBrands = Object.entries(brandCounts) - .sort((a, b) => b[1] - a[1]) - .slice(0, 3) - .map(([name, count]) => ({ name, count })); - - // Calculate average session duration - let totalDuration = 0; - let validDurations = 0; - visitors.forEach((v) => { - if (v.join_time && v.left_time) { - const duration = new Date(v.left_time) - new Date(v.join_time); - if (duration > 0) { - totalDuration += duration; - validDurations++; - } - } - }); - const avgDuration = validDurations > 0 ? totalDuration / validDurations : 0; - const avgDurationFormatted = formatDuration(avgDuration); - - return { - totalSessions, - servedSessions, - notServedSessions, - servedPercentage, - topBrands, - avgDuration: avgDurationFormatted, - }; - }, [visitors, user?.userId]); - - // Helper function to format duration - const formatDuration = (ms) => { - const seconds = Math.floor(ms / 1000); - const minutes = Math.floor(seconds / 60); - const hours = Math.floor(minutes / 60); - - if (hours > 0) { - return `${hours}h ${minutes % 60}m`; - } else if (minutes > 0) { - return `${minutes}m ${seconds % 60}s`; - } else { - return `${seconds}s`; - } - }; - - // Quick filter preset handlers for user 111 - const handleQuickPreset = (preset) => { - const today = new Date(); - let startDate, endDate; - - switch (preset) { - case "today": - startDate = new Date(today.setHours(0, 0, 0, 0)); - endDate = new Date(today.setHours(23, 59, 59, 999)); - break; - case "last7days": - endDate = new Date(today.setHours(23, 59, 59, 999)); - startDate = new Date(today.setDate(today.getDate() - 7)); - startDate.setHours(0, 0, 0, 0); - break; - case "last30days": - endDate = new Date(today.setHours(23, 59, 59, 999)); - startDate = new Date(today.setDate(today.getDate() - 30)); - startDate.setHours(0, 0, 0, 0); - break; - default: - return; - } - - setActivePreset(preset); - setTempDateRange([{ startDate, endDate, key: "selection" }]); - setDateRange([{ startDate, endDate, key: "selection" }]); - - // Apply the filter - const formattedStartDate = formatDateToMySQL(startDate); - const formattedEndDate = formatDateToMySQL(endDate); - - setLoading(true); - setisFiltering(true); - - apiRequest("/api/client/visitor-history-filterbydate", "POST", { - user_id: user.userId, - start_date: formattedStartDate, - end_date: formattedEndDate, - }) - .then((response) => { - if (response) { - setLoading(false); - setVisitors(response.SearchData.sessionRows); - setfilteredTotalRecords(response.SearchData.totalRecords); - } - }) - .catch((err) => { - setError("An error occurred while applying date filter"); - setLoading(false); - }); - }; - - // Auto-expand filter panel for user 111 on mount - useEffect(() => { - if (user?.userId === 111) { - // Only open on initial mount, don't close if user manually closes it - const timer = setTimeout(() => { - setShowSettings(true); - }, 100); - return () => clearTimeout(timer); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [user?.userId]); - + // Fetch visitors on component mount and when page changes useEffect(() => { fetchVisitors(currentPage); @@ -916,6 +700,7 @@ const History = () => { if (currentPage < totalPages) { setCurrentPage((prev) => prev + 1); } + }; const handlePreviousPage = () => { @@ -924,30 +709,30 @@ const History = () => { } }; const handleResetFilter = () => { + setSearchTerm(""); const allBrandIds = filteredBrands.map((brand) => brand.id); - const areAllSelected = allBrandIds.every((id) => - selectedBrands.includes(id), - ); - + const areAllSelected = allBrandIds.every((id) => selectedBrands.includes(id)); + if (!areAllSelected) { setSelectedBrands(allBrandIds); - + // searchVisitors(searchTerm, servedStatus, connectedStatus,includeClientId,includeEmail,includeMsg,includeName,selectedBrands); setFilterCurrentPage(1); + } - + setfilteredTotalRecords(0); setIncludeName(true); setIncludeEmail(true); setIncludeClientId(true); setincludeMsg(true); - setservedStatus("all"); - setconnectedStatus("all"); + setservedStatus('all'); + setconnectedStatus('all'); setisFiltering(false); setVisitors(allVisitors); }; - + const getBrowserName = (browser) => { if (browser?.includes("Chrome")) { return "chrome"; @@ -1035,180 +820,172 @@ const History = () => {
- {showSettings &&
} + {showSettings && + +
+ }
-
-
- - - - +
+
+ + + + + toggleSettings(!showSettings)} + + title="filter" + > + + + {isFiltering && ( toggleSettings(!showSettings)} - title="filter" + onClick={handleResetFilter} + title="reset" > - + - {isFiltering && ( - - - - )} -
+ )} +
- {showSettings && ( -
- {/* Background Layer */} -
toggleSettings(false)} - >
- - {/* Filter Bar */} -
-
-
Filter Options
-
-
- - handleFilterChange("includeName", e.target.checked) - } - /> - -
-
- - handleFilterChange("includeEmail", e.target.checked) - } - /> - -
-
- - handleFilterChange( - "includeClientId", - e.target.checked, - ) - } - /> - -
-
- - handleFilterChange("includeMsg", e.target.checked) - } - /> - -
+ {showSettings && ( +
+ {/* Background Layer */} +
toggleSettings(false)}>
+ + {/* Filter Bar */} +
+
+
Filter Options
+
+
+ + handleFilterChange("includeName", e.target.checked) + } + /> +
+
+ + handleFilterChange("includeEmail", e.target.checked) + } + /> + +
+
+ + handleFilterChange("includeClientId", e.target.checked) + } + /> + +
+
+ + handleFilterChange("includeMsg", e.target.checked) + } + /> + +
+
- {/* Select Filters */} -
-
- - -
- -
- - -
+ {/* Select Filters */} +
+
+ +
-
- -
+ + - {filteredBrands.map((brand) => ( - - ))} + + + + +
+
+ +
+ +
+
+ +
+ + {filteredBrands.map((brand) => ( + + ))}
- )} +
+ )}
@@ -1251,30 +1028,6 @@ const History = () => { )}
- {/* Quick Filter Presets for User 111 */} - {user?.userId === 111 && ( -
- - - -
- )} - - - {/* Power User Styles */} -
- - {/* Power User Banner for User 111 */} - {user?.userId === 111 && ( -
-
- ⚡ Power User Mode -

- Due to your large dataset, please use the search and filter - options to view your history. Use the quick presets above for - faster access to recent data. -

-
-
- )} - - {/* Analytics Dashboard for User 111 */} - {user?.userId === 111 && analyticsStats && ( -
-
Session Statistics
-
-
-
{analyticsStats.totalSessions}
-
Total Sessions
-
-
-
{analyticsStats.servedSessions}
-
Served
-
-
-
- {analyticsStats.notServedSessions} -
-
Not Served
-
-
-
- {analyticsStats.servedPercentage}% -
-
Served Rate
-
-
-
{analyticsStats.avgDuration}
-
Avg Duration
-
-
-
Top Brands
-
- {analyticsStats.topBrands.map((brand, idx) => ( -
- {brand.name} - {brand.count} -
- ))} - {analyticsStats.topBrands.length === 0 && ( - No brand data - )} -
-
-
-
- )}

Total Records:{" "} @@ -1529,9 +1058,7 @@ const History = () => { {loading ? ( ) : error ? ( -

- {error} -

+

{error}

) : ( <>
@@ -1256,15 +1259,6 @@ const VisitorRow = ({
- - {/* Device Icon with Tooltip */} -
- {getDeviceIcon(visitor?.device_size)} - - Device: {getDeviceType(visitor?.device_size)} -
-
-
{totalMessages} {servedBy} - {brand_name} - {servedBy} {brand_name}
{ - + @@ -1573,26 +1098,20 @@ const History = () => { NewHistoryRecieved.some( (history) => history.visitor_session_id === - visitor.visitor_session_id, + visitor.visitor_session_id ) ? "new-history-row" : "" }`} > {/* */} - - + + - + + - - + - - - - - ))} @@ -1697,20 +1192,11 @@ const History = () => { {isFiltering && (
Messages Platform Brand - Landing Page - Landing Page IP Join At Duration{visitor.visitor_session_id || 'N/A'} - {visitor.client_id || "N/A"} - - {visitor.client_name || "N/A"} - {visitor.client_id || "N/A"}{visitor.client_name || "N/A"} {visitor.served_by || "N/A"} - - {visitor.message_count} - {visitor.message_count } {/* Browser Icon with Tooltip */}
@@ -1621,53 +1140,29 @@ const History = () => {
- {visitor.brand_name || "N/A"} - + {visitor.brand_name || "N/A"} {visitor.landing_url || "N/A"} + + {visitor.ip || "N/A"} + {emitTimeInUserTimezone(visitor.join_time) || "N/A"} + {calculateSessionTime( visitor.join_time, - visitor.left_time, + visitor.left_time ) || "N/A"} + {visitor.IP_Health === 1 ? "Good" : visitor.IP_Health === 0 - ? "Bad" - : "N/A"} + ? "Bad" + : "N/A"}