@kite-copilot/chat-panel 0.2.49 → 0.2.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/auto.cjs +118 -158
- package/dist/auto.d.cts +1 -1
- package/dist/auto.d.ts +1 -1
- package/dist/auto.js +1 -1
- package/dist/{chunk-YZXB3LLU.js → chunk-VBCGW333.js} +118 -158
- package/dist/{createKiteChat-e6BnJS6T.d.cts → createKiteChat-DeQKgFyx.d.cts} +8 -2
- package/dist/{createKiteChat-e6BnJS6T.d.ts → createKiteChat-DeQKgFyx.d.ts} +8 -2
- package/dist/embed.global.js +24 -59
- package/dist/index.cjs +118 -158
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -896,28 +896,22 @@ function useUserAuth({
|
|
|
896
896
|
}) {
|
|
897
897
|
const [authState, setAuthState] = React4.useState({ status: "idle" });
|
|
898
898
|
const lastSessionIdRef = React4.useRef(null);
|
|
899
|
+
const lastEnabledRef = React4.useRef(enabled);
|
|
899
900
|
const fetchUser = React4.useCallback(async () => {
|
|
900
901
|
if (!productBackendUrl || !enabled) {
|
|
901
|
-
console.log("[useUserAuth] Skipping auth - productBackendUrl:", productBackendUrl, "enabled:", enabled);
|
|
902
902
|
setAuthState({ status: "idle" });
|
|
903
903
|
return;
|
|
904
904
|
}
|
|
905
|
-
console.log("[useUserAuth] Starting auth request to product backend...");
|
|
906
|
-
console.log("[useUserAuth] Product backend URL:", productBackendUrl);
|
|
907
|
-
console.log("[useUserAuth] Full request URL:", `${productBackendUrl}/users/me`);
|
|
908
905
|
setAuthState({ status: "loading" });
|
|
909
906
|
try {
|
|
910
907
|
const response = await fetch(`${productBackendUrl}/users/me`, {
|
|
911
908
|
method: "GET",
|
|
912
909
|
credentials: "include",
|
|
913
|
-
// Include cookies for authentication
|
|
914
910
|
headers: {
|
|
915
911
|
"Accept": "application/json"
|
|
916
912
|
}
|
|
917
913
|
});
|
|
918
|
-
console.log("[useUserAuth] Response received - status:", response.status, "ok:", response.ok);
|
|
919
914
|
if (!response.ok) {
|
|
920
|
-
console.log("[useUserAuth] Auth request failed with status:", response.status);
|
|
921
915
|
if (response.status === 401) {
|
|
922
916
|
throw new Error("Please log in to use the chat assistant.");
|
|
923
917
|
}
|
|
@@ -927,27 +921,36 @@ function useUserAuth({
|
|
|
927
921
|
throw new Error(`Authentication failed (${response.status})`);
|
|
928
922
|
}
|
|
929
923
|
const user = await response.json();
|
|
930
|
-
console.log("[useUserAuth] Auth SUCCESS - parsed user data:");
|
|
931
|
-
console.log("[useUserAuth] id:", user.id);
|
|
932
|
-
console.log("[useUserAuth] email:", user.email);
|
|
933
|
-
console.log("[useUserAuth] name:", user.name);
|
|
934
|
-
console.log("[useUserAuth] role:", user.role);
|
|
935
|
-
console.log("[useUserAuth] isInternal:", user.isInternal);
|
|
936
|
-
console.log("[useUserAuth] agreementsSigned:", user.agreementsSigned);
|
|
937
|
-
console.log("[useUserAuth] lastLoginTime:", user.lastLoginTime);
|
|
938
924
|
setAuthState({ status: "authenticated", user });
|
|
939
925
|
} catch (error) {
|
|
940
|
-
|
|
926
|
+
if (error instanceof Error) {
|
|
927
|
+
const errorMessage = error.message.toLowerCase();
|
|
928
|
+
const isNetworkError = error instanceof TypeError || errorMessage.includes("failed to fetch") || errorMessage.includes("network");
|
|
929
|
+
const is404Error = errorMessage.includes("404");
|
|
930
|
+
if (isNetworkError || is404Error) {
|
|
931
|
+
console.warn("[useUserAuth] Auth endpoint unavailable, falling back to unauthenticated mode:", error.message);
|
|
932
|
+
setAuthState({ status: "idle" });
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
941
936
|
const message = error instanceof Error ? error.message : "Unable to verify your identity. Please try again.";
|
|
942
937
|
setAuthState({ status: "error", error: message });
|
|
943
938
|
}
|
|
944
939
|
}, [productBackendUrl, enabled]);
|
|
945
940
|
React4.useEffect(() => {
|
|
946
|
-
|
|
941
|
+
const sessionChanged = sessionId !== lastSessionIdRef.current;
|
|
942
|
+
const enabledChanged = enabled !== lastEnabledRef.current;
|
|
943
|
+
const becameEnabled = enabled && !lastEnabledRef.current;
|
|
944
|
+
if (sessionChanged) {
|
|
947
945
|
lastSessionIdRef.current = sessionId;
|
|
946
|
+
}
|
|
947
|
+
if (enabledChanged) {
|
|
948
|
+
lastEnabledRef.current = enabled;
|
|
949
|
+
}
|
|
950
|
+
if (sessionChanged || becameEnabled) {
|
|
948
951
|
fetchUser();
|
|
949
952
|
}
|
|
950
|
-
}, [sessionId, fetchUser]);
|
|
953
|
+
}, [sessionId, enabled, fetchUser]);
|
|
951
954
|
const retry = React4.useCallback(() => {
|
|
952
955
|
fetchUser();
|
|
953
956
|
}, [fetchUser]);
|
|
@@ -964,13 +967,11 @@ function useOrgConfig({ agentUrl, orgId }) {
|
|
|
964
967
|
});
|
|
965
968
|
React5.useEffect(() => {
|
|
966
969
|
if (!agentUrl || !orgId) {
|
|
967
|
-
console.log("[useOrgConfig] Skipping - missing agentUrl or orgId", { agentUrl, orgId });
|
|
968
970
|
return;
|
|
969
971
|
}
|
|
970
972
|
const fetchConfig = async () => {
|
|
971
973
|
setState({ status: "loading", config: null, error: null });
|
|
972
974
|
const url = `${agentUrl}/org/${orgId}/config`;
|
|
973
|
-
console.log("[useOrgConfig] Fetching org config from:", url);
|
|
974
975
|
try {
|
|
975
976
|
const response = await fetch(url, {
|
|
976
977
|
method: "GET",
|
|
@@ -982,7 +983,6 @@ function useOrgConfig({ agentUrl, orgId }) {
|
|
|
982
983
|
throw new Error(`Failed to fetch org config (${response.status})`);
|
|
983
984
|
}
|
|
984
985
|
const config = await response.json();
|
|
985
|
-
console.log("[useOrgConfig] Received config:", config);
|
|
986
986
|
setState({ status: "success", config, error: null });
|
|
987
987
|
} catch (error) {
|
|
988
988
|
const message = error instanceof Error ? error.message : "Failed to fetch org config";
|
|
@@ -1016,8 +1016,7 @@ function useFrontendToolExecutor({
|
|
|
1016
1016
|
}
|
|
1017
1017
|
}, [agentUrl]);
|
|
1018
1018
|
const executeToolRequest = useCallback3(async (toolRequest) => {
|
|
1019
|
-
const { call_id,
|
|
1020
|
-
console.log("[FrontendToolExecutor] Executing tool:", tool_name, "with args:", args);
|
|
1019
|
+
const { call_id, arguments: args, endpoint, method, path_params } = toolRequest;
|
|
1021
1020
|
try {
|
|
1022
1021
|
let url = endpoint;
|
|
1023
1022
|
for (const param of path_params) {
|
|
@@ -1033,7 +1032,6 @@ function useFrontendToolExecutor({
|
|
|
1033
1032
|
}
|
|
1034
1033
|
const queryString = queryParams.toString();
|
|
1035
1034
|
const fullUrl = `${productBackendUrl}${url}${queryString ? "?" + queryString : ""}`;
|
|
1036
|
-
console.log("[FrontendToolExecutor] Fetching:", fullUrl);
|
|
1037
1035
|
const response = await fetch(fullUrl, {
|
|
1038
1036
|
method,
|
|
1039
1037
|
credentials: "include",
|
|
@@ -1045,7 +1043,6 @@ function useFrontendToolExecutor({
|
|
|
1045
1043
|
let result;
|
|
1046
1044
|
if (response.ok) {
|
|
1047
1045
|
result = await response.json();
|
|
1048
|
-
console.log("[FrontendToolExecutor] Tool result:", result);
|
|
1049
1046
|
} else {
|
|
1050
1047
|
const errorText = await response.text();
|
|
1051
1048
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
@@ -1097,7 +1094,6 @@ function TypingIndicator({ className = "" }) {
|
|
|
1097
1094
|
|
|
1098
1095
|
// src/ChatPanel.tsx
|
|
1099
1096
|
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1100
|
-
var CHAT_PANEL_VERSION = true ? "0.2.49" : "dev";
|
|
1101
1097
|
var DEFAULT_AGENT_URL = "http://localhost:5002";
|
|
1102
1098
|
var PANEL_WIDTH = 400;
|
|
1103
1099
|
var PANEL_HEIGHT = 600;
|
|
@@ -1561,7 +1557,8 @@ function ChatPanel({
|
|
|
1561
1557
|
supabaseAnonKey,
|
|
1562
1558
|
initialCorner = "bottom-left",
|
|
1563
1559
|
onCornerChange,
|
|
1564
|
-
productBackendUrl
|
|
1560
|
+
productBackendUrl,
|
|
1561
|
+
getAuthHeaders
|
|
1565
1562
|
} = {}) {
|
|
1566
1563
|
const [messages, setMessages] = React6.useState(initialMessages);
|
|
1567
1564
|
const [input, setInput] = React6.useState("");
|
|
@@ -1583,6 +1580,8 @@ function ChatPanel({
|
|
|
1583
1580
|
const [sessionUser, setSessionUser] = React6.useState(null);
|
|
1584
1581
|
const orgConfigState = useOrgConfig({ agentUrl, orgId: orgId || "" });
|
|
1585
1582
|
const effectiveProductBackendUrl = orgConfigState.config?.productBackendUrl || productBackendUrl;
|
|
1583
|
+
const effectiveSupabaseUrl = orgConfigState.config?.supabaseUrl || supabaseUrl;
|
|
1584
|
+
const effectiveSupabaseAnonKey = orgConfigState.config?.supabaseAnonKey || supabaseAnonKey;
|
|
1586
1585
|
const { authState, retry: retryAuth } = useUserAuth({
|
|
1587
1586
|
productBackendUrl: effectiveProductBackendUrl,
|
|
1588
1587
|
sessionId,
|
|
@@ -1594,37 +1593,6 @@ function ChatPanel({
|
|
|
1594
1593
|
agentUrl,
|
|
1595
1594
|
sessionId
|
|
1596
1595
|
});
|
|
1597
|
-
React6.useEffect(() => {
|
|
1598
|
-
if (!effectiveProductBackendUrl || orgConfigState.status !== "success") {
|
|
1599
|
-
return;
|
|
1600
|
-
}
|
|
1601
|
-
const testProductBackendEndpoint = async () => {
|
|
1602
|
-
const url = `${effectiveProductBackendUrl}/getDocument/snowkite/categories/`;
|
|
1603
|
-
console.log("[KiteChat TEST] Testing product backend connectivity...");
|
|
1604
|
-
console.log("[KiteChat TEST] URL:", url);
|
|
1605
|
-
try {
|
|
1606
|
-
const response = await fetch(url, {
|
|
1607
|
-
method: "GET",
|
|
1608
|
-
// Note: not using credentials: 'include' to avoid CORS issues with wildcard
|
|
1609
|
-
headers: {
|
|
1610
|
-
"Accept": "application/json"
|
|
1611
|
-
}
|
|
1612
|
-
});
|
|
1613
|
-
console.log("[KiteChat TEST] Response status:", response.status);
|
|
1614
|
-
console.log("[KiteChat TEST] Response ok:", response.ok);
|
|
1615
|
-
if (response.ok) {
|
|
1616
|
-
const data = await response.json();
|
|
1617
|
-
console.log("[KiteChat TEST] SUCCESS - product backend reachable, data:", data);
|
|
1618
|
-
} else {
|
|
1619
|
-
const errorText = await response.text();
|
|
1620
|
-
console.log("[KiteChat TEST] FAILED - status:", response.status, "body:", errorText);
|
|
1621
|
-
}
|
|
1622
|
-
} catch (error) {
|
|
1623
|
-
console.error("[KiteChat TEST] ERROR:", error);
|
|
1624
|
-
}
|
|
1625
|
-
};
|
|
1626
|
-
testProductBackendEndpoint();
|
|
1627
|
-
}, [effectiveProductBackendUrl, orgConfigState.status]);
|
|
1628
1596
|
const effectiveUser = React6.useMemo(() => {
|
|
1629
1597
|
if (sessionUser) {
|
|
1630
1598
|
return sessionUser;
|
|
@@ -1655,7 +1623,6 @@ function ChatPanel({
|
|
|
1655
1623
|
userRole: authState.user.role,
|
|
1656
1624
|
isInternal: authState.user.isInternal
|
|
1657
1625
|
});
|
|
1658
|
-
console.log("[ChatPanel] Session user captured:", authState.user.id);
|
|
1659
1626
|
}
|
|
1660
1627
|
}, [authState, sessionUser]);
|
|
1661
1628
|
const isWaitingForAuth = React6.useMemo(() => {
|
|
@@ -1668,26 +1635,18 @@ function ChatPanel({
|
|
|
1668
1635
|
const supabaseRef = React6.useRef(null);
|
|
1669
1636
|
const typingChannelRef = React6.useRef(null);
|
|
1670
1637
|
const typingTimeoutRef = React6.useRef(null);
|
|
1671
|
-
React6.useEffect(() => {
|
|
1672
|
-
console.log(`[KiteChat] Chat Panel v${CHAT_PANEL_VERSION} loaded`);
|
|
1673
|
-
}, []);
|
|
1674
1638
|
const resetSession = React6.useCallback(() => {
|
|
1675
|
-
console.log("[KiteChat] resetSession called", { isEscalated, hasSupabase: !!supabaseRef.current, sessionId });
|
|
1676
1639
|
if (isEscalated && supabaseRef.current && sessionId) {
|
|
1677
|
-
console.log("[KiteChat] Updating customer_status to disconnected for session:", sessionId);
|
|
1678
1640
|
supabaseRef.current.from("escalations").update({
|
|
1679
1641
|
customer_status: "disconnected",
|
|
1680
1642
|
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1681
1643
|
}).eq("session_id", sessionId).then(
|
|
1682
|
-
(
|
|
1683
|
-
console.log("[KiteChat] Disconnect update result:", result);
|
|
1644
|
+
() => {
|
|
1684
1645
|
},
|
|
1685
1646
|
(err) => {
|
|
1686
1647
|
console.error("[KiteChat] Disconnect update failed:", err);
|
|
1687
1648
|
}
|
|
1688
1649
|
);
|
|
1689
|
-
} else {
|
|
1690
|
-
console.log("[KiteChat] Skipping disconnect update - conditions not met");
|
|
1691
1650
|
}
|
|
1692
1651
|
setSessionUser(null);
|
|
1693
1652
|
setSessionId(crypto.randomUUID());
|
|
@@ -1703,22 +1662,19 @@ function ChatPanel({
|
|
|
1703
1662
|
}
|
|
1704
1663
|
}, [isEscalated, sessionId]);
|
|
1705
1664
|
React6.useEffect(() => {
|
|
1706
|
-
if (
|
|
1707
|
-
supabaseRef.current = createClient(
|
|
1665
|
+
if (effectiveSupabaseUrl && effectiveSupabaseAnonKey && !supabaseRef.current) {
|
|
1666
|
+
supabaseRef.current = createClient(effectiveSupabaseUrl, effectiveSupabaseAnonKey);
|
|
1708
1667
|
}
|
|
1709
|
-
}, [
|
|
1668
|
+
}, [effectiveSupabaseUrl, effectiveSupabaseAnonKey]);
|
|
1710
1669
|
React6.useEffect(() => {
|
|
1711
1670
|
if (!isEscalated || !sessionId || !supabaseRef.current) {
|
|
1712
1671
|
return;
|
|
1713
1672
|
}
|
|
1714
1673
|
const channelName = `typing:${sessionId}`;
|
|
1715
1674
|
const channel = supabaseRef.current.channel(channelName);
|
|
1716
|
-
console.log(`[KiteChat] Subscribing to typing channel: ${channelName}`);
|
|
1717
1675
|
channel.on("broadcast", { event: "typing" }, (payload) => {
|
|
1718
|
-
console.log("[KiteChat] Received typing broadcast:", payload);
|
|
1719
1676
|
const { sender, isTyping } = payload.payload;
|
|
1720
1677
|
if (sender === "agent") {
|
|
1721
|
-
console.log(`[KiteChat] Agent typing: ${isTyping}`);
|
|
1722
1678
|
setAgentIsTyping(isTyping);
|
|
1723
1679
|
if (isTyping) {
|
|
1724
1680
|
if (typingTimeoutRef.current) {
|
|
@@ -1730,10 +1686,11 @@ function ChatPanel({
|
|
|
1730
1686
|
}
|
|
1731
1687
|
}
|
|
1732
1688
|
}).subscribe((status) => {
|
|
1733
|
-
console.log(`[KiteChat] Typing channel status: ${status}`);
|
|
1734
1689
|
if (status === "SUBSCRIBED") {
|
|
1735
1690
|
typingChannelRef.current = channel;
|
|
1736
|
-
console.log("[KiteChat] Typing channel
|
|
1691
|
+
console.log("[KiteChat] Typing channel subscribed successfully");
|
|
1692
|
+
} else if (status === "CHANNEL_ERROR") {
|
|
1693
|
+
console.error("[KiteChat] Typing channel subscription failed");
|
|
1737
1694
|
}
|
|
1738
1695
|
});
|
|
1739
1696
|
return () => {
|
|
@@ -1744,6 +1701,20 @@ function ChatPanel({
|
|
|
1744
1701
|
}
|
|
1745
1702
|
};
|
|
1746
1703
|
}, [isEscalated, sessionId]);
|
|
1704
|
+
React6.useEffect(() => {
|
|
1705
|
+
if (!isOpen && isEscalated && supabaseRef.current && sessionId) {
|
|
1706
|
+
console.log("[KiteChat] Panel closed during live chat, marking disconnected");
|
|
1707
|
+
supabaseRef.current.from("escalations").update({
|
|
1708
|
+
customer_status: "disconnected",
|
|
1709
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1710
|
+
}).eq("session_id", sessionId).then(
|
|
1711
|
+
() => console.log("[KiteChat] Successfully marked disconnected on panel close"),
|
|
1712
|
+
(err) => {
|
|
1713
|
+
console.error("[KiteChat] Failed to mark disconnected on panel close:", err);
|
|
1714
|
+
}
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
}, [isOpen, isEscalated, sessionId]);
|
|
1747
1718
|
const heartbeatIntervalRef = React6.useRef(null);
|
|
1748
1719
|
const updateCustomerStatus = React6.useCallback(async (status) => {
|
|
1749
1720
|
if (!supabaseRef.current || !sessionId) return;
|
|
@@ -1762,24 +1733,50 @@ function ChatPanel({
|
|
|
1762
1733
|
}
|
|
1763
1734
|
const currentSessionId = sessionId;
|
|
1764
1735
|
const supabase = supabaseRef.current;
|
|
1765
|
-
|
|
1736
|
+
const sbUrl = effectiveSupabaseUrl;
|
|
1737
|
+
const sbKey = effectiveSupabaseAnonKey;
|
|
1738
|
+
const markActive = () => {
|
|
1739
|
+
supabase.from("escalations").update({
|
|
1740
|
+
customer_status: "active",
|
|
1741
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1742
|
+
}).eq("session_id", currentSessionId).then(
|
|
1743
|
+
() => {
|
|
1744
|
+
},
|
|
1745
|
+
(err) => console.error("[KiteChat] Failed to update customer status:", err)
|
|
1746
|
+
);
|
|
1747
|
+
};
|
|
1748
|
+
const markDisconnectedWithKeepalive = () => {
|
|
1749
|
+
if (!sbUrl || !sbKey) return;
|
|
1750
|
+
const url = `${sbUrl}/rest/v1/escalations?session_id=eq.${currentSessionId}`;
|
|
1751
|
+
fetch(url, {
|
|
1752
|
+
method: "PATCH",
|
|
1753
|
+
headers: {
|
|
1754
|
+
"Content-Type": "application/json",
|
|
1755
|
+
"apikey": sbKey,
|
|
1756
|
+
"Authorization": `Bearer ${sbKey}`,
|
|
1757
|
+
"Prefer": "return=minimal"
|
|
1758
|
+
},
|
|
1759
|
+
body: JSON.stringify({
|
|
1760
|
+
customer_status: "disconnected",
|
|
1761
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1762
|
+
}),
|
|
1763
|
+
keepalive: true
|
|
1764
|
+
}).catch(() => {
|
|
1765
|
+
});
|
|
1766
|
+
};
|
|
1767
|
+
console.log("[KiteChat] Starting presence heartbeat for live chat");
|
|
1768
|
+
markActive();
|
|
1766
1769
|
heartbeatIntervalRef.current = window.setInterval(() => {
|
|
1767
|
-
|
|
1770
|
+
markActive();
|
|
1768
1771
|
}, 6e4);
|
|
1769
1772
|
const handleBeforeUnload = () => {
|
|
1770
|
-
|
|
1771
|
-
customer_status: "disconnected",
|
|
1772
|
-
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1773
|
-
}).eq("session_id", currentSessionId);
|
|
1773
|
+
markDisconnectedWithKeepalive();
|
|
1774
1774
|
};
|
|
1775
1775
|
const handleVisibilityChange = () => {
|
|
1776
1776
|
if (document.visibilityState === "hidden") {
|
|
1777
|
-
|
|
1778
|
-
customer_status: "disconnected",
|
|
1779
|
-
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1780
|
-
}).eq("session_id", currentSessionId);
|
|
1777
|
+
markDisconnectedWithKeepalive();
|
|
1781
1778
|
} else if (document.visibilityState === "visible") {
|
|
1782
|
-
|
|
1779
|
+
markActive();
|
|
1783
1780
|
}
|
|
1784
1781
|
};
|
|
1785
1782
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
@@ -1787,13 +1784,12 @@ function ChatPanel({
|
|
|
1787
1784
|
return () => {
|
|
1788
1785
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
1789
1786
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1787
|
+
console.log("[KiteChat] Escalation ended, marking disconnected");
|
|
1790
1788
|
supabase.from("escalations").update({
|
|
1791
1789
|
customer_status: "disconnected",
|
|
1792
1790
|
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1793
1791
|
}).eq("session_id", currentSessionId).then(
|
|
1794
|
-
() =>
|
|
1795
|
-
console.log("[KiteChat] Marked customer as disconnected");
|
|
1796
|
-
},
|
|
1792
|
+
() => console.log("[KiteChat] Successfully marked disconnected on escalation end"),
|
|
1797
1793
|
(err) => {
|
|
1798
1794
|
console.error("[KiteChat] Failed to mark disconnected:", err);
|
|
1799
1795
|
}
|
|
@@ -1803,17 +1799,14 @@ function ChatPanel({
|
|
|
1803
1799
|
heartbeatIntervalRef.current = null;
|
|
1804
1800
|
}
|
|
1805
1801
|
};
|
|
1806
|
-
}, [isEscalated, sessionId,
|
|
1802
|
+
}, [isEscalated, sessionId, effectiveSupabaseUrl, effectiveSupabaseAnonKey]);
|
|
1807
1803
|
const sendTypingIndicator = React6.useCallback((isTyping) => {
|
|
1808
|
-
if (!typingChannelRef.current) {
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
if (!isEscalated) {
|
|
1813
|
-
console.log("[KiteChat] Cannot send typing - not escalated");
|
|
1804
|
+
if (!typingChannelRef.current || !isEscalated) {
|
|
1805
|
+
if (isTyping) {
|
|
1806
|
+
console.warn("[KiteChat] Typing channel not ready, cannot send typing indicator");
|
|
1807
|
+
}
|
|
1814
1808
|
return;
|
|
1815
1809
|
}
|
|
1816
|
-
console.log(`[KiteChat] Sending typing indicator: ${isTyping}`);
|
|
1817
1810
|
typingChannelRef.current.send({
|
|
1818
1811
|
type: "broadcast",
|
|
1819
1812
|
event: "typing",
|
|
@@ -1822,16 +1815,23 @@ function ChatPanel({
|
|
|
1822
1815
|
}, [isEscalated]);
|
|
1823
1816
|
const userTypingTimeoutRef = React6.useRef(null);
|
|
1824
1817
|
const handleTypingStart = React6.useCallback(() => {
|
|
1825
|
-
if (!isEscalated || !supabaseRef.current) return;
|
|
1818
|
+
if (!isEscalated || !supabaseRef.current || !sessionId) return;
|
|
1826
1819
|
sendTypingIndicator(true);
|
|
1827
|
-
|
|
1820
|
+
supabaseRef.current.from("escalations").update({
|
|
1821
|
+
customer_status: "active",
|
|
1822
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1823
|
+
}).eq("session_id", sessionId).then(
|
|
1824
|
+
() => {
|
|
1825
|
+
},
|
|
1826
|
+
(err) => console.error("[KiteChat] Failed to update presence:", err)
|
|
1827
|
+
);
|
|
1828
1828
|
if (userTypingTimeoutRef.current) {
|
|
1829
1829
|
window.clearTimeout(userTypingTimeoutRef.current);
|
|
1830
1830
|
}
|
|
1831
1831
|
userTypingTimeoutRef.current = window.setTimeout(() => {
|
|
1832
1832
|
sendTypingIndicator(false);
|
|
1833
1833
|
}, 1500);
|
|
1834
|
-
}, [isEscalated, sendTypingIndicator,
|
|
1834
|
+
}, [isEscalated, sendTypingIndicator, sessionId]);
|
|
1835
1835
|
const streamIntervals = React6.useRef({});
|
|
1836
1836
|
const isEmpty = messages.length === 0;
|
|
1837
1837
|
const [phase, setPhase] = React6.useState("idle");
|
|
@@ -1866,12 +1866,6 @@ function ChatPanel({
|
|
|
1866
1866
|
const latestBulkSummaryNavigationRef = React6.useRef(null);
|
|
1867
1867
|
const [guideComplete, setGuideComplete] = React6.useState(false);
|
|
1868
1868
|
React6.useEffect(() => {
|
|
1869
|
-
window.resetIntegrationNotification = () => {
|
|
1870
|
-
localStorage.removeItem("gmailNotificationSeen");
|
|
1871
|
-
console.log(
|
|
1872
|
-
"Integration notification reset! Click the Integrations tab to see it again."
|
|
1873
|
-
);
|
|
1874
|
-
};
|
|
1875
1869
|
const handleIntegrationTabClick = () => {
|
|
1876
1870
|
const hasSeenNotification = localStorage.getItem("gmailNotificationSeen");
|
|
1877
1871
|
if (!hasSeenNotification) {
|
|
@@ -2013,17 +2007,7 @@ function ChatPanel({
|
|
|
2013
2007
|
return;
|
|
2014
2008
|
}
|
|
2015
2009
|
const currentBulkNav = latestBulkSummaryNavigationRef.current;
|
|
2016
|
-
console.log(
|
|
2017
|
-
"[DEBUG] Keyboard handler - latestBulkSummaryNavigation:",
|
|
2018
|
-
currentBulkNav,
|
|
2019
|
-
"onNavigate:",
|
|
2020
|
-
!!onNavigate
|
|
2021
|
-
);
|
|
2022
2010
|
if (currentBulkNav && onNavigate) {
|
|
2023
|
-
console.log(
|
|
2024
|
-
"[DEBUG] Navigating via keyboard to:",
|
|
2025
|
-
currentBulkNav.page
|
|
2026
|
-
);
|
|
2027
2011
|
e.preventDefault();
|
|
2028
2012
|
e.stopPropagation();
|
|
2029
2013
|
onNavigate(currentBulkNav.page, currentBulkNav.subtab);
|
|
@@ -2069,7 +2053,6 @@ function ChatPanel({
|
|
|
2069
2053
|
const messageId = data.message_id;
|
|
2070
2054
|
const isDuplicate = messageId ? prev.some((m) => m.serverMessageId === messageId) : prev.slice(-5).some((m) => m.content === content);
|
|
2071
2055
|
if (isDuplicate) {
|
|
2072
|
-
console.debug("[KiteChat] Skipping duplicate agent message:", messageId || content.slice(0, 30));
|
|
2073
2056
|
return prev;
|
|
2074
2057
|
}
|
|
2075
2058
|
return [...prev, {
|
|
@@ -2092,7 +2075,6 @@ function ChatPanel({
|
|
|
2092
2075
|
console.error("[KiteChat] Escalation WebSocket error:", err);
|
|
2093
2076
|
};
|
|
2094
2077
|
ws.onclose = () => {
|
|
2095
|
-
console.log("[KiteChat] Escalation WebSocket closed");
|
|
2096
2078
|
};
|
|
2097
2079
|
escalationWsRef.current = ws;
|
|
2098
2080
|
}, [agentUrl]);
|
|
@@ -2106,13 +2088,22 @@ function ChatPanel({
|
|
|
2106
2088
|
type: "user_message",
|
|
2107
2089
|
content
|
|
2108
2090
|
}));
|
|
2109
|
-
|
|
2091
|
+
if (supabaseRef.current && sessionId) {
|
|
2092
|
+
supabaseRef.current.from("escalations").update({
|
|
2093
|
+
customer_status: "active",
|
|
2094
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
2095
|
+
}).eq("session_id", sessionId).then(
|
|
2096
|
+
() => {
|
|
2097
|
+
},
|
|
2098
|
+
(err) => console.error("[KiteChat] Failed to update presence:", err)
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2110
2101
|
return true;
|
|
2111
2102
|
} catch (err) {
|
|
2112
2103
|
console.error("[KiteChat] Failed to send escalated message:", err);
|
|
2113
2104
|
return false;
|
|
2114
2105
|
}
|
|
2115
|
-
}, [
|
|
2106
|
+
}, [sessionId]);
|
|
2116
2107
|
React6.useEffect(() => {
|
|
2117
2108
|
return () => {
|
|
2118
2109
|
if (escalationWsRef.current) {
|
|
@@ -2386,14 +2377,6 @@ function ChatPanel({
|
|
|
2386
2377
|
try {
|
|
2387
2378
|
const controller = new AbortController();
|
|
2388
2379
|
const timeoutId = setTimeout(() => controller.abort(), 6e4);
|
|
2389
|
-
console.log("[ChatPanel] Sending chat request to agent backend...");
|
|
2390
|
-
console.log("[ChatPanel] Agent URL:", agentUrl);
|
|
2391
|
-
console.log("[ChatPanel] User data being sent:");
|
|
2392
|
-
console.log("[ChatPanel] user_id:", effectiveUser.userId);
|
|
2393
|
-
console.log("[ChatPanel] user_name:", effectiveUser.userName);
|
|
2394
|
-
console.log("[ChatPanel] user_email:", effectiveUser.userEmail);
|
|
2395
|
-
console.log("[ChatPanel] org_id:", orgId);
|
|
2396
|
-
console.log("[ChatPanel] authState.status:", authState.status);
|
|
2397
2380
|
const response = await fetch(`${agentUrl}/chat/stream`, {
|
|
2398
2381
|
method: "POST",
|
|
2399
2382
|
headers: {
|
|
@@ -2610,7 +2593,6 @@ function ChatPanel({
|
|
|
2610
2593
|
setMessages((prev) => [...prev, escalationMessage]);
|
|
2611
2594
|
} else if (eventType === "tool_request") {
|
|
2612
2595
|
const toolRequest = data;
|
|
2613
|
-
console.log("[KiteChat] Received tool_request:", toolRequest);
|
|
2614
2596
|
executeToolRequest(toolRequest).catch((err) => {
|
|
2615
2597
|
console.error("[KiteChat] Tool execution failed:", err);
|
|
2616
2598
|
});
|
|
@@ -2928,11 +2910,6 @@ ${userText}`
|
|
|
2928
2910
|
}
|
|
2929
2911
|
});
|
|
2930
2912
|
} else if (eventType === "summary") {
|
|
2931
|
-
console.log("[DEBUG] Received summary event - data:", data);
|
|
2932
|
-
console.log(
|
|
2933
|
-
"[DEBUG] navigationPage from backend:",
|
|
2934
|
-
data.navigationPage
|
|
2935
|
-
);
|
|
2936
2913
|
setPhase("idle");
|
|
2937
2914
|
setProgressSteps([]);
|
|
2938
2915
|
setPendingBulkSession(null);
|
|
@@ -2952,7 +2929,6 @@ ${userText}`
|
|
|
2952
2929
|
navigationPage: data.navigationPage
|
|
2953
2930
|
}
|
|
2954
2931
|
};
|
|
2955
|
-
console.log("[DEBUG] Creating bulkSummary message:", newMsg);
|
|
2956
2932
|
return [...filtered, newMsg];
|
|
2957
2933
|
});
|
|
2958
2934
|
setTimeout(() => {
|
|
@@ -4523,28 +4499,11 @@ ${userText}`
|
|
|
4523
4499
|
onClick: (e) => {
|
|
4524
4500
|
e.preventDefault();
|
|
4525
4501
|
e.stopPropagation();
|
|
4526
|
-
console.log(
|
|
4527
|
-
"[DEBUG] Button clicked - navigationPage:",
|
|
4528
|
-
navigationPage,
|
|
4529
|
-
"onNavigate:",
|
|
4530
|
-
!!onNavigate
|
|
4531
|
-
);
|
|
4532
4502
|
if (onNavigate && navigationPage.page) {
|
|
4533
|
-
console.log(
|
|
4534
|
-
"[DEBUG] Calling onNavigate with page:",
|
|
4535
|
-
navigationPage.page
|
|
4536
|
-
);
|
|
4537
4503
|
onNavigate(
|
|
4538
4504
|
navigationPage.page,
|
|
4539
4505
|
navigationPage.subtab
|
|
4540
4506
|
);
|
|
4541
|
-
} else {
|
|
4542
|
-
console.log(
|
|
4543
|
-
"[DEBUG] Condition failed - onNavigate:",
|
|
4544
|
-
!!onNavigate,
|
|
4545
|
-
"navigationPage.page:",
|
|
4546
|
-
navigationPage.page
|
|
4547
|
-
);
|
|
4548
4507
|
}
|
|
4549
4508
|
},
|
|
4550
4509
|
className: "flex items-center gap-2 text-xs text-gray-500 hover:text-gray-700 transition-colors group cursor-pointer",
|
|
@@ -4824,7 +4783,8 @@ function ChatPanelWithToggle({
|
|
|
4824
4783
|
supabaseAnonKey,
|
|
4825
4784
|
initialCorner,
|
|
4826
4785
|
onCornerChange,
|
|
4827
|
-
productBackendUrl
|
|
4786
|
+
productBackendUrl,
|
|
4787
|
+
getAuthHeaders
|
|
4828
4788
|
}) {
|
|
4829
4789
|
const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
|
|
4830
4790
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
@@ -4854,7 +4814,8 @@ function ChatPanelWithToggle({
|
|
|
4854
4814
|
supabaseAnonKey,
|
|
4855
4815
|
initialCorner,
|
|
4856
4816
|
onCornerChange,
|
|
4857
|
-
productBackendUrl
|
|
4817
|
+
productBackendUrl,
|
|
4818
|
+
getAuthHeaders
|
|
4858
4819
|
}
|
|
4859
4820
|
);
|
|
4860
4821
|
}
|
|
@@ -4928,7 +4889,8 @@ function KiteChatWrapper({
|
|
|
4928
4889
|
userEmail: config.userEmail,
|
|
4929
4890
|
supabaseUrl: config.supabaseUrl,
|
|
4930
4891
|
supabaseAnonKey: config.supabaseAnonKey,
|
|
4931
|
-
productBackendUrl: config.productBackendUrl
|
|
4892
|
+
productBackendUrl: config.productBackendUrl,
|
|
4893
|
+
getAuthHeaders: config.getAuthHeaders
|
|
4932
4894
|
}
|
|
4933
4895
|
);
|
|
4934
4896
|
}
|
|
@@ -4971,7 +4933,6 @@ function createKiteChat(config) {
|
|
|
4971
4933
|
}
|
|
4972
4934
|
)
|
|
4973
4935
|
);
|
|
4974
|
-
console.log("[KiteChat] Mounted");
|
|
4975
4936
|
},
|
|
4976
4937
|
unmount() {
|
|
4977
4938
|
if (!root) {
|
|
@@ -4983,7 +4944,6 @@ function createKiteChat(config) {
|
|
|
4983
4944
|
containerElement = null;
|
|
4984
4945
|
configUpdater = null;
|
|
4985
4946
|
stateUpdaters = null;
|
|
4986
|
-
console.log("[KiteChat] Unmounted");
|
|
4987
4947
|
},
|
|
4988
4948
|
open() {
|
|
4989
4949
|
stateUpdaters?.setIsOpen(true);
|
|
@@ -118,8 +118,10 @@ interface ChatPanelProps {
|
|
|
118
118
|
onCornerChange?: (corner: PanelCorner) => void;
|
|
119
119
|
/** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
|
|
120
120
|
productBackendUrl?: string;
|
|
121
|
+
/** Optional async function to provide authentication headers for API requests */
|
|
122
|
+
getAuthHeaders?: () => Promise<Record<string, string>>;
|
|
121
123
|
}
|
|
122
|
-
declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
|
|
124
|
+
declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
|
|
123
125
|
/**
|
|
124
126
|
* PanelToggle - An arrow button on the right edge that toggles the side panel
|
|
125
127
|
* Shows left arrow when closed (click to open), right arrow when open (click to close)
|
|
@@ -182,8 +184,10 @@ interface ChatPanelWithToggleProps {
|
|
|
182
184
|
onCornerChange?: (corner: PanelCorner) => void;
|
|
183
185
|
/** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
|
|
184
186
|
productBackendUrl?: string;
|
|
187
|
+
/** Optional async function to provide authentication headers for API requests */
|
|
188
|
+
getAuthHeaders?: () => Promise<Record<string, string>>;
|
|
185
189
|
}
|
|
186
|
-
declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
|
|
190
|
+
declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
|
|
187
191
|
/**
|
|
188
192
|
* @deprecated Use ChatPanelWithToggle instead for the new side panel UX
|
|
189
193
|
*/
|
|
@@ -253,6 +257,8 @@ interface KiteChatConfig {
|
|
|
253
257
|
supabaseAnonKey?: string;
|
|
254
258
|
/** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
|
|
255
259
|
productBackendUrl?: string;
|
|
260
|
+
/** Optional async function to provide authentication headers for API requests */
|
|
261
|
+
getAuthHeaders?: () => Promise<Record<string, string>>;
|
|
256
262
|
}
|
|
257
263
|
/**
|
|
258
264
|
* Instance returned by createKiteChat with lifecycle control methods.
|
|
@@ -118,8 +118,10 @@ interface ChatPanelProps {
|
|
|
118
118
|
onCornerChange?: (corner: PanelCorner) => void;
|
|
119
119
|
/** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
|
|
120
120
|
productBackendUrl?: string;
|
|
121
|
+
/** Optional async function to provide authentication headers for API requests */
|
|
122
|
+
getAuthHeaders?: () => Promise<Record<string, string>>;
|
|
121
123
|
}
|
|
122
|
-
declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
|
|
124
|
+
declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
|
|
123
125
|
/**
|
|
124
126
|
* PanelToggle - An arrow button on the right edge that toggles the side panel
|
|
125
127
|
* Shows left arrow when closed (click to open), right arrow when open (click to close)
|
|
@@ -182,8 +184,10 @@ interface ChatPanelWithToggleProps {
|
|
|
182
184
|
onCornerChange?: (corner: PanelCorner) => void;
|
|
183
185
|
/** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
|
|
184
186
|
productBackendUrl?: string;
|
|
187
|
+
/** Optional async function to provide authentication headers for API requests */
|
|
188
|
+
getAuthHeaders?: () => Promise<Record<string, string>>;
|
|
185
189
|
}
|
|
186
|
-
declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
|
|
190
|
+
declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
|
|
187
191
|
/**
|
|
188
192
|
* @deprecated Use ChatPanelWithToggle instead for the new side panel UX
|
|
189
193
|
*/
|
|
@@ -253,6 +257,8 @@ interface KiteChatConfig {
|
|
|
253
257
|
supabaseAnonKey?: string;
|
|
254
258
|
/** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
|
|
255
259
|
productBackendUrl?: string;
|
|
260
|
+
/** Optional async function to provide authentication headers for API requests */
|
|
261
|
+
getAuthHeaders?: () => Promise<Record<string, string>>;
|
|
256
262
|
}
|
|
257
263
|
/**
|
|
258
264
|
* Instance returned by createKiteChat with lifecycle control methods.
|