@kite-copilot/chat-panel 0.2.38 → 0.2.40

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.
@@ -882,10 +882,62 @@ function DataRenderer({ type, data }) {
882
882
  }
883
883
 
884
884
  // src/ChatPanel.tsx
885
- import * as React4 from "react";
885
+ import * as React5 from "react";
886
886
  import { createClient } from "@supabase/supabase-js";
887
887
  import { ArrowLeft, ArrowUp, Command, CornerDownLeft, CheckCircle2 as CheckCircle23, SquarePen, Paperclip, X, FileSpreadsheet, Loader2 as Loader22, ChevronLeft, ChevronRight, Sparkles, Minus } from "lucide-react";
888
888
 
889
+ // src/hooks/useUserAuth.ts
890
+ import * as React4 from "react";
891
+ function useUserAuth({
892
+ productBackendUrl,
893
+ sessionId,
894
+ enabled = true
895
+ }) {
896
+ const [authState, setAuthState] = React4.useState({ status: "idle" });
897
+ const lastSessionIdRef = React4.useRef(null);
898
+ const fetchUser = React4.useCallback(async () => {
899
+ if (!productBackendUrl || !enabled) {
900
+ setAuthState({ status: "idle" });
901
+ return;
902
+ }
903
+ setAuthState({ status: "loading" });
904
+ try {
905
+ const response = await fetch(`${productBackendUrl}/users/me`, {
906
+ method: "GET",
907
+ credentials: "include",
908
+ // Include cookies for authentication
909
+ headers: {
910
+ "Accept": "application/json"
911
+ }
912
+ });
913
+ if (!response.ok) {
914
+ if (response.status === 401) {
915
+ throw new Error("Please log in to use the chat assistant.");
916
+ }
917
+ if (response.status === 403) {
918
+ throw new Error("You do not have permission to access this feature.");
919
+ }
920
+ throw new Error(`Authentication failed (${response.status})`);
921
+ }
922
+ const user = await response.json();
923
+ setAuthState({ status: "authenticated", user });
924
+ } catch (error) {
925
+ const message = error instanceof Error ? error.message : "Unable to verify your identity. Please try again.";
926
+ setAuthState({ status: "error", error: message });
927
+ }
928
+ }, [productBackendUrl, enabled]);
929
+ React4.useEffect(() => {
930
+ if (sessionId !== lastSessionIdRef.current) {
931
+ lastSessionIdRef.current = sessionId;
932
+ fetchUser();
933
+ }
934
+ }, [sessionId, fetchUser]);
935
+ const retry = React4.useCallback(() => {
936
+ fetchUser();
937
+ }, [fetchUser]);
938
+ return { authState, retry };
939
+ }
940
+
889
941
  // src/components/TypingIndicator.tsx
890
942
  import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
891
943
  function TypingIndicator({ className = "" }) {
@@ -916,7 +968,7 @@ function TypingIndicator({ className = "" }) {
916
968
 
917
969
  // src/ChatPanel.tsx
918
970
  import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
919
- var CHAT_PANEL_VERSION = true ? "0.2.38" : "dev";
971
+ var CHAT_PANEL_VERSION = true ? "0.2.40" : "dev";
920
972
  var DEFAULT_AGENT_URL = "http://localhost:5002";
921
973
  var PANEL_WIDTH = 340;
922
974
  function unescapeJsonString(str) {
@@ -1334,6 +1386,32 @@ var guides = {
1334
1386
  }
1335
1387
  };
1336
1388
  var initialMessages = [];
1389
+ function AuthLoadingState() {
1390
+ return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center h-full p-6", children: [
1391
+ /* @__PURE__ */ jsx10(Loader22, { className: "h-8 w-8 animate-spin text-gray-400 mb-3" }),
1392
+ /* @__PURE__ */ jsx10("p", { className: "text-xs text-gray-500", children: "Verifying your identity..." })
1393
+ ] });
1394
+ }
1395
+ function AuthErrorState({
1396
+ error,
1397
+ onRetry
1398
+ }) {
1399
+ return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center h-full p-6 text-center", children: [
1400
+ /* @__PURE__ */ jsx10("div", { className: "w-12 h-12 rounded-full bg-red-100 flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx10(X, { className: "h-6 w-6 text-red-600" }) }),
1401
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-900 mb-2", children: "Unable to Start Chat" }),
1402
+ /* @__PURE__ */ jsx10("p", { className: "text-xs text-gray-500 mb-4 max-w-[240px]", children: error }),
1403
+ /* @__PURE__ */ jsx10(
1404
+ Button,
1405
+ {
1406
+ variant: "secondary",
1407
+ size: "sm",
1408
+ onClick: onRetry,
1409
+ className: "h-8 px-4 text-xs",
1410
+ children: "Try Again"
1411
+ }
1412
+ )
1413
+ ] });
1414
+ }
1337
1415
  function ChatPanel({
1338
1416
  isOpen = true,
1339
1417
  onClose,
@@ -1351,26 +1429,62 @@ function ChatPanel({
1351
1429
  userEmail,
1352
1430
  userOrganization,
1353
1431
  supabaseUrl,
1354
- supabaseAnonKey
1432
+ supabaseAnonKey,
1433
+ productBackendUrl
1355
1434
  } = {}) {
1356
- const [messages, setMessages] = React4.useState(initialMessages);
1357
- const [input, setInput] = React4.useState("");
1358
- const [sessionId, setSessionId] = React4.useState(() => crypto.randomUUID());
1359
- const [isEscalated, setIsEscalated] = React4.useState(false);
1360
- const escalationWsRef = React4.useRef(null);
1361
- const [agentIsTyping, setAgentIsTyping] = React4.useState(false);
1362
- const supabaseRef = React4.useRef(null);
1363
- const typingChannelRef = React4.useRef(null);
1364
- const typingTimeoutRef = React4.useRef(null);
1365
- React4.useEffect(() => {
1435
+ const [messages, setMessages] = React5.useState(initialMessages);
1436
+ const [input, setInput] = React5.useState("");
1437
+ const [sessionId, setSessionId] = React5.useState(() => crypto.randomUUID());
1438
+ const { authState, retry: retryAuth } = useUserAuth({
1439
+ productBackendUrl,
1440
+ sessionId,
1441
+ enabled: !!productBackendUrl
1442
+ // Only enable if URL is provided
1443
+ });
1444
+ const effectiveUser = React5.useMemo(() => {
1445
+ if (authState.status === "authenticated") {
1446
+ return {
1447
+ userId: authState.user.id,
1448
+ userName: authState.user.name,
1449
+ userEmail: authState.user.email,
1450
+ userRole: authState.user.role,
1451
+ isInternal: authState.user.isInternal
1452
+ };
1453
+ }
1454
+ return {
1455
+ userId: userId || "anonymous",
1456
+ userName: userName || "Anonymous User",
1457
+ userEmail: userEmail || "Not provided",
1458
+ userRole: void 0,
1459
+ isInternal: false
1460
+ };
1461
+ }, [authState, userId, userName, userEmail]);
1462
+ const [isEscalated, setIsEscalated] = React5.useState(false);
1463
+ const escalationWsRef = React5.useRef(null);
1464
+ const [agentIsTyping, setAgentIsTyping] = React5.useState(false);
1465
+ const supabaseRef = React5.useRef(null);
1466
+ const typingChannelRef = React5.useRef(null);
1467
+ const typingTimeoutRef = React5.useRef(null);
1468
+ React5.useEffect(() => {
1366
1469
  console.log(`[KiteChat] Chat Panel v${CHAT_PANEL_VERSION} loaded`);
1367
1470
  }, []);
1368
- const resetSession = React4.useCallback(() => {
1471
+ const resetSession = React5.useCallback(() => {
1472
+ console.log("[KiteChat] resetSession called", { isEscalated, hasSupabase: !!supabaseRef.current, sessionId });
1369
1473
  if (isEscalated && supabaseRef.current && sessionId) {
1474
+ console.log("[KiteChat] Updating customer_status to disconnected for session:", sessionId);
1370
1475
  supabaseRef.current.from("escalations").update({
1371
1476
  customer_status: "disconnected",
1372
1477
  customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1373
- }).eq("session_id", sessionId);
1478
+ }).eq("session_id", sessionId).then(
1479
+ (result) => {
1480
+ console.log("[KiteChat] Disconnect update result:", result);
1481
+ },
1482
+ (err) => {
1483
+ console.error("[KiteChat] Disconnect update failed:", err);
1484
+ }
1485
+ );
1486
+ } else {
1487
+ console.log("[KiteChat] Skipping disconnect update - conditions not met");
1374
1488
  }
1375
1489
  setSessionId(crypto.randomUUID());
1376
1490
  setIsEscalated(false);
@@ -1384,12 +1498,12 @@ function ChatPanel({
1384
1498
  typingChannelRef.current = null;
1385
1499
  }
1386
1500
  }, [isEscalated, sessionId]);
1387
- React4.useEffect(() => {
1501
+ React5.useEffect(() => {
1388
1502
  if (supabaseUrl && supabaseAnonKey && !supabaseRef.current) {
1389
1503
  supabaseRef.current = createClient(supabaseUrl, supabaseAnonKey);
1390
1504
  }
1391
1505
  }, [supabaseUrl, supabaseAnonKey]);
1392
- React4.useEffect(() => {
1506
+ React5.useEffect(() => {
1393
1507
  if (!isEscalated || !sessionId || !supabaseRef.current) {
1394
1508
  return;
1395
1509
  }
@@ -1426,8 +1540,8 @@ function ChatPanel({
1426
1540
  }
1427
1541
  };
1428
1542
  }, [isEscalated, sessionId]);
1429
- const heartbeatIntervalRef = React4.useRef(null);
1430
- const updateCustomerStatus = React4.useCallback(async (status) => {
1543
+ const heartbeatIntervalRef = React5.useRef(null);
1544
+ const updateCustomerStatus = React5.useCallback(async (status) => {
1431
1545
  if (!supabaseRef.current || !sessionId) return;
1432
1546
  try {
1433
1547
  await supabaseRef.current.from("escalations").update({
@@ -1438,7 +1552,7 @@ function ChatPanel({
1438
1552
  console.error("[KiteChat] Failed to update customer status:", err);
1439
1553
  }
1440
1554
  }, [sessionId]);
1441
- React4.useEffect(() => {
1555
+ React5.useEffect(() => {
1442
1556
  if (!isEscalated || !sessionId || !supabaseRef.current) {
1443
1557
  return;
1444
1558
  }
@@ -1486,7 +1600,7 @@ function ChatPanel({
1486
1600
  }
1487
1601
  };
1488
1602
  }, [isEscalated, sessionId, updateCustomerStatus]);
1489
- const sendTypingIndicator = React4.useCallback((isTyping) => {
1603
+ const sendTypingIndicator = React5.useCallback((isTyping) => {
1490
1604
  if (!typingChannelRef.current) {
1491
1605
  console.log("[KiteChat] Cannot send typing - channel not ready");
1492
1606
  return;
@@ -1502,8 +1616,8 @@ function ChatPanel({
1502
1616
  payload: { sender: "user", isTyping }
1503
1617
  });
1504
1618
  }, [isEscalated]);
1505
- const userTypingTimeoutRef = React4.useRef(null);
1506
- const handleTypingStart = React4.useCallback(() => {
1619
+ const userTypingTimeoutRef = React5.useRef(null);
1620
+ const handleTypingStart = React5.useCallback(() => {
1507
1621
  if (!isEscalated || !supabaseRef.current) return;
1508
1622
  sendTypingIndicator(true);
1509
1623
  updateCustomerStatus("active");
@@ -1514,19 +1628,19 @@ function ChatPanel({
1514
1628
  sendTypingIndicator(false);
1515
1629
  }, 1500);
1516
1630
  }, [isEscalated, sendTypingIndicator, updateCustomerStatus]);
1517
- const streamIntervals = React4.useRef({});
1631
+ const streamIntervals = React5.useRef({});
1518
1632
  const isEmpty = messages.length === 0;
1519
- const [phase, setPhase] = React4.useState("idle");
1520
- const [progressSteps, setProgressSteps] = React4.useState([]);
1521
- const phaseTimers = React4.useRef([]);
1633
+ const [phase, setPhase] = React5.useState("idle");
1634
+ const [progressSteps, setProgressSteps] = React5.useState([]);
1635
+ const phaseTimers = React5.useRef([]);
1522
1636
  const lastRole = messages.length ? messages[messages.length - 1].role : void 0;
1523
- const [panelView, setPanelView] = React4.useState(
1637
+ const [panelView, setPanelView] = React5.useState(
1524
1638
  "landing"
1525
1639
  );
1526
- const [currentFolderId, setCurrentFolderId] = React4.useState(void 0);
1527
- const [startingQuestions, setStartingQuestions] = React4.useState(startingQuestionsProp || defaultStartingQuestions);
1528
- const [loadingQuestions, setLoadingQuestions] = React4.useState(false);
1529
- React4.useEffect(() => {
1640
+ const [currentFolderId, setCurrentFolderId] = React5.useState(void 0);
1641
+ const [startingQuestions, setStartingQuestions] = React5.useState(startingQuestionsProp || defaultStartingQuestions);
1642
+ const [loadingQuestions, setLoadingQuestions] = React5.useState(false);
1643
+ React5.useEffect(() => {
1530
1644
  if (startingQuestionsEndpoint && !startingQuestionsProp) {
1531
1645
  setLoadingQuestions(true);
1532
1646
  fetch(startingQuestionsEndpoint).then((res) => res.json()).then((data) => {
@@ -1538,16 +1652,16 @@ function ChatPanel({
1538
1652
  }).finally(() => setLoadingQuestions(false));
1539
1653
  }
1540
1654
  }, [startingQuestionsEndpoint, startingQuestionsProp]);
1541
- React4.useEffect(() => {
1655
+ React5.useEffect(() => {
1542
1656
  if (startingQuestionsProp) {
1543
1657
  setStartingQuestions(startingQuestionsProp);
1544
1658
  }
1545
1659
  }, [startingQuestionsProp]);
1546
- const [activeGuide, setActiveGuide] = React4.useState(void 0);
1547
- const activeGuideRef = React4.useRef(void 0);
1548
- const latestBulkSummaryNavigationRef = React4.useRef(null);
1549
- const [guideComplete, setGuideComplete] = React4.useState(false);
1550
- React4.useEffect(() => {
1660
+ const [activeGuide, setActiveGuide] = React5.useState(void 0);
1661
+ const activeGuideRef = React5.useRef(void 0);
1662
+ const latestBulkSummaryNavigationRef = React5.useRef(null);
1663
+ const [guideComplete, setGuideComplete] = React5.useState(false);
1664
+ React5.useEffect(() => {
1551
1665
  window.resetIntegrationNotification = () => {
1552
1666
  localStorage.removeItem("gmailNotificationSeen");
1553
1667
  console.log(
@@ -1581,7 +1695,7 @@ function ChatPanel({
1581
1695
  );
1582
1696
  };
1583
1697
  }, []);
1584
- React4.useEffect(() => {
1698
+ React5.useEffect(() => {
1585
1699
  if (activeGuide) {
1586
1700
  if (!activeGuideRef.current || activeGuideRef.current.id !== activeGuide.id || activeGuideRef.current.stepIndex !== activeGuide.stepIndex) {
1587
1701
  activeGuideRef.current = activeGuide;
@@ -1590,21 +1704,21 @@ function ChatPanel({
1590
1704
  activeGuideRef.current = void 0;
1591
1705
  }
1592
1706
  }, [activeGuide]);
1593
- const [pendingNavigation, setPendingNavigation] = React4.useState(null);
1594
- const [pendingAction, setPendingAction] = React4.useState(null);
1595
- const [actionFormData, setActionFormData] = React4.useState({});
1596
- const messagesEndRef = React4.useRef(null);
1597
- const messagesContainerRef = React4.useRef(null);
1598
- const currentStepRef = React4.useRef(null);
1707
+ const [pendingNavigation, setPendingNavigation] = React5.useState(null);
1708
+ const [pendingAction, setPendingAction] = React5.useState(null);
1709
+ const [actionFormData, setActionFormData] = React5.useState({});
1710
+ const messagesEndRef = React5.useRef(null);
1711
+ const messagesContainerRef = React5.useRef(null);
1712
+ const currentStepRef = React5.useRef(null);
1599
1713
  const { cursorState, moveTo, hide } = useGuideCursor();
1600
- const [pendingFile, setPendingFile] = React4.useState(null);
1601
- const [pendingBulkSession, setPendingBulkSession] = React4.useState(null);
1602
- const pendingBulkSessionRef = React4.useRef(null);
1603
- const fileInputRef = React4.useRef(null);
1604
- const [searchExpanded, setSearchExpanded] = React4.useState(false);
1605
- const [searchInput, setSearchInput] = React4.useState("");
1606
- const searchInputRef = React4.useRef(null);
1607
- React4.useEffect(() => {
1714
+ const [pendingFile, setPendingFile] = React5.useState(null);
1715
+ const [pendingBulkSession, setPendingBulkSession] = React5.useState(null);
1716
+ const pendingBulkSessionRef = React5.useRef(null);
1717
+ const fileInputRef = React5.useRef(null);
1718
+ const [searchExpanded, setSearchExpanded] = React5.useState(false);
1719
+ const [searchInput, setSearchInput] = React5.useState("");
1720
+ const searchInputRef = React5.useRef(null);
1721
+ React5.useEffect(() => {
1608
1722
  if (!activeGuide || activeGuide.id !== "add-api-key" || activeGuide.stepIndex !== 2) {
1609
1723
  return;
1610
1724
  }
@@ -1630,7 +1744,7 @@ function ChatPanel({
1630
1744
  const interval = setInterval(checkForDialogOpen, 300);
1631
1745
  return () => clearInterval(interval);
1632
1746
  }, [activeGuide, hide]);
1633
- React4.useEffect(() => {
1747
+ React5.useEffect(() => {
1634
1748
  return () => {
1635
1749
  Object.values(streamIntervals.current).forEach(
1636
1750
  (id) => window.clearInterval(id)
@@ -1640,7 +1754,7 @@ function ChatPanel({
1640
1754
  phaseTimers.current = [];
1641
1755
  };
1642
1756
  }, []);
1643
- React4.useEffect(() => {
1757
+ React5.useEffect(() => {
1644
1758
  if (activeGuide && messages.length > 0) {
1645
1759
  const lastMessage = messages[messages.length - 1];
1646
1760
  if (lastMessage.kind === "guideStep" || lastMessage.kind === "guideComplete") {
@@ -1657,7 +1771,7 @@ function ChatPanel({
1657
1771
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1658
1772
  }
1659
1773
  }, [messages, phase, activeGuide]);
1660
- const latestBulkSummaryNavigation = React4.useMemo(() => {
1774
+ const latestBulkSummaryNavigation = React5.useMemo(() => {
1661
1775
  for (let i = messages.length - 1; i >= 0; i--) {
1662
1776
  const msg = messages[i];
1663
1777
  if (msg.kind === "bulkSummary" && msg.bulkSummary?.navigationPage && msg.bulkSummary.successes > 0) {
@@ -1666,13 +1780,13 @@ function ChatPanel({
1666
1780
  }
1667
1781
  return null;
1668
1782
  }, [messages]);
1669
- React4.useEffect(() => {
1783
+ React5.useEffect(() => {
1670
1784
  latestBulkSummaryNavigationRef.current = latestBulkSummaryNavigation;
1671
1785
  }, [latestBulkSummaryNavigation]);
1672
- React4.useEffect(() => {
1786
+ React5.useEffect(() => {
1673
1787
  pendingBulkSessionRef.current = pendingBulkSession;
1674
1788
  }, [pendingBulkSession]);
1675
- React4.useEffect(() => {
1789
+ React5.useEffect(() => {
1676
1790
  const handleKeyDown = (e) => {
1677
1791
  if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
1678
1792
  const currentBulkSession = pendingBulkSessionRef.current;
@@ -1735,7 +1849,7 @@ function ChatPanel({
1735
1849
  guideComplete,
1736
1850
  onNavigate
1737
1851
  ]);
1738
- const connectToEscalationWs = React4.useCallback((currentSessionId) => {
1852
+ const connectToEscalationWs = React5.useCallback((currentSessionId) => {
1739
1853
  if (!agentUrl) return;
1740
1854
  if (escalationWsRef.current) {
1741
1855
  escalationWsRef.current.close();
@@ -1778,7 +1892,7 @@ function ChatPanel({
1778
1892
  };
1779
1893
  escalationWsRef.current = ws;
1780
1894
  }, [agentUrl]);
1781
- const sendEscalatedMessage = React4.useCallback(async (content) => {
1895
+ const sendEscalatedMessage = React5.useCallback(async (content) => {
1782
1896
  if (!escalationWsRef.current || escalationWsRef.current.readyState !== WebSocket.OPEN) {
1783
1897
  console.error("[KiteChat] Escalation WebSocket not connected");
1784
1898
  return false;
@@ -1795,14 +1909,14 @@ function ChatPanel({
1795
1909
  return false;
1796
1910
  }
1797
1911
  }, [updateCustomerStatus]);
1798
- React4.useEffect(() => {
1912
+ React5.useEffect(() => {
1799
1913
  return () => {
1800
1914
  if (escalationWsRef.current) {
1801
1915
  escalationWsRef.current.close();
1802
1916
  }
1803
1917
  };
1804
1918
  }, []);
1805
- React4.useEffect(() => {
1919
+ React5.useEffect(() => {
1806
1920
  if (isEscalated && sessionId) {
1807
1921
  connectToEscalationWs(sessionId);
1808
1922
  }
@@ -2077,9 +2191,9 @@ function ChatPanel({
2077
2191
  session_id: sessionId,
2078
2192
  message: userText,
2079
2193
  current_page: currentPage || "dashboard",
2080
- user_id: userId,
2081
- user_name: userName,
2082
- user_email: userEmail,
2194
+ user_id: effectiveUser.userId,
2195
+ user_name: effectiveUser.userName,
2196
+ user_email: effectiveUser.userEmail,
2083
2197
  user_organization: userOrganization,
2084
2198
  org_id: orgId
2085
2199
  }),
@@ -3022,6 +3136,64 @@ ${userText}`
3022
3136
  ] })
3023
3137
  ] }) }) });
3024
3138
  }
3139
+ if (productBackendUrl) {
3140
+ if (authState.status === "loading") {
3141
+ return /* @__PURE__ */ jsxs6(
3142
+ "section",
3143
+ {
3144
+ className: `fixed top-0 right-0 z-40 flex flex-col bg-white border-l border-gray-200 h-full overflow-hidden transition-transform duration-300 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
3145
+ style: { width: `${PANEL_WIDTH}px` },
3146
+ children: [
3147
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white shrink-0", children: [
3148
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2.5", children: [
3149
+ /* @__PURE__ */ jsx10(Sparkles, { className: "h-3.5 w-3.5 text-black", fill: "currentColor" }),
3150
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-800", children: "Copilot" })
3151
+ ] }),
3152
+ /* @__PURE__ */ jsx10(
3153
+ Button,
3154
+ {
3155
+ variant: "ghost",
3156
+ size: "sm",
3157
+ className: "h-7 w-7 p-0 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full",
3158
+ onClick: () => onClose?.(),
3159
+ children: /* @__PURE__ */ jsx10(Minus, { className: "h-3.5 w-3.5" })
3160
+ }
3161
+ )
3162
+ ] }),
3163
+ /* @__PURE__ */ jsx10(AuthLoadingState, {})
3164
+ ]
3165
+ }
3166
+ );
3167
+ }
3168
+ if (authState.status === "error") {
3169
+ return /* @__PURE__ */ jsxs6(
3170
+ "section",
3171
+ {
3172
+ className: `fixed top-0 right-0 z-40 flex flex-col bg-white border-l border-gray-200 h-full overflow-hidden transition-transform duration-300 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
3173
+ style: { width: `${PANEL_WIDTH}px` },
3174
+ children: [
3175
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white shrink-0", children: [
3176
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2.5", children: [
3177
+ /* @__PURE__ */ jsx10(Sparkles, { className: "h-3.5 w-3.5 text-black", fill: "currentColor" }),
3178
+ /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-800", children: "Copilot" })
3179
+ ] }),
3180
+ /* @__PURE__ */ jsx10(
3181
+ Button,
3182
+ {
3183
+ variant: "ghost",
3184
+ size: "sm",
3185
+ className: "h-7 w-7 p-0 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full",
3186
+ onClick: () => onClose?.(),
3187
+ children: /* @__PURE__ */ jsx10(Minus, { className: "h-3.5 w-3.5" })
3188
+ }
3189
+ )
3190
+ ] }),
3191
+ /* @__PURE__ */ jsx10(AuthErrorState, { error: authState.error, onRetry: retryAuth })
3192
+ ]
3193
+ }
3194
+ );
3195
+ }
3196
+ }
3025
3197
  return /* @__PURE__ */ jsxs6(
3026
3198
  "section",
3027
3199
  {
@@ -4139,7 +4311,7 @@ ${userText}`
4139
4311
  message.id
4140
4312
  );
4141
4313
  }
4142
- return /* @__PURE__ */ jsx10(React4.Fragment, { children: /* @__PURE__ */ jsxs6(
4314
+ return /* @__PURE__ */ jsx10(React5.Fragment, { children: /* @__PURE__ */ jsxs6(
4143
4315
  "div",
4144
4316
  {
4145
4317
  ref: isCurrentGuideStep ? currentStepRef : null,
@@ -4393,9 +4565,10 @@ function ChatPanelWithToggle({
4393
4565
  userEmail,
4394
4566
  userOrganization,
4395
4567
  supabaseUrl,
4396
- supabaseAnonKey
4568
+ supabaseAnonKey,
4569
+ productBackendUrl
4397
4570
  }) {
4398
- const [internalIsOpen, setInternalIsOpen] = React4.useState(defaultOpen);
4571
+ const [internalIsOpen, setInternalIsOpen] = React5.useState(defaultOpen);
4399
4572
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
4400
4573
  const setIsOpen = (open) => {
4401
4574
  if (controlledIsOpen === void 0) {
@@ -4403,7 +4576,7 @@ function ChatPanelWithToggle({
4403
4576
  }
4404
4577
  onOpenChange?.(open);
4405
4578
  };
4406
- React4.useEffect(() => {
4579
+ React5.useEffect(() => {
4407
4580
  const originalPadding = document.body.style.paddingRight;
4408
4581
  const originalTransition = document.body.style.transition;
4409
4582
  document.body.style.transition = "padding-right 0.3s ease";
@@ -4431,7 +4604,8 @@ function ChatPanelWithToggle({
4431
4604
  userEmail,
4432
4605
  userOrganization,
4433
4606
  supabaseUrl,
4434
- supabaseAnonKey
4607
+ supabaseAnonKey,
4608
+ productBackendUrl
4435
4609
  }
4436
4610
  );
4437
4611
  }
@@ -4449,7 +4623,7 @@ function HelpButton({ onClick, className = "" }) {
4449
4623
  }
4450
4624
 
4451
4625
  // src/createKiteChat.tsx
4452
- import React5 from "react";
4626
+ import React6 from "react";
4453
4627
  import { createRoot } from "react-dom/client";
4454
4628
  import { jsx as jsx11 } from "react/jsx-runtime";
4455
4629
  function KiteChatWrapper({
@@ -4457,14 +4631,14 @@ function KiteChatWrapper({
4457
4631
  onConfigUpdate,
4458
4632
  onStateUpdate
4459
4633
  }) {
4460
- const [config, setConfig] = React5.useState(initialConfig);
4461
- const [currentPage, setCurrentPage] = React5.useState(initialConfig.currentPage || "dashboard");
4462
- const [isOpen, setIsOpen] = React5.useState(false);
4463
- const isOpenRef = React5.useRef(false);
4464
- React5.useEffect(() => {
4634
+ const [config, setConfig] = React6.useState(initialConfig);
4635
+ const [currentPage, setCurrentPage] = React6.useState(initialConfig.currentPage || "dashboard");
4636
+ const [isOpen, setIsOpen] = React6.useState(false);
4637
+ const isOpenRef = React6.useRef(false);
4638
+ React6.useEffect(() => {
4465
4639
  isOpenRef.current = isOpen;
4466
4640
  }, [isOpen]);
4467
- React5.useEffect(() => {
4641
+ React6.useEffect(() => {
4468
4642
  onConfigUpdate((newConfig) => {
4469
4643
  if (newConfig.currentPage !== void 0) {
4470
4644
  setCurrentPage(newConfig.currentPage);
@@ -4476,7 +4650,7 @@ function KiteChatWrapper({
4476
4650
  getIsOpen: () => isOpenRef.current
4477
4651
  });
4478
4652
  }, [onConfigUpdate, onStateUpdate]);
4479
- React5.useEffect(() => {
4653
+ React6.useEffect(() => {
4480
4654
  const container = document.getElementById("kite-chat-root");
4481
4655
  if (!container) return;
4482
4656
  if (config.theme === "dark") {
@@ -4505,7 +4679,8 @@ function KiteChatWrapper({
4505
4679
  userEmail: config.userEmail,
4506
4680
  userOrganization: config.userOrganization,
4507
4681
  supabaseUrl: config.supabaseUrl,
4508
- supabaseAnonKey: config.supabaseAnonKey
4682
+ supabaseAnonKey: config.supabaseAnonKey,
4683
+ productBackendUrl: config.productBackendUrl
4509
4684
  }
4510
4685
  );
4511
4686
  }
@@ -112,8 +112,10 @@ interface ChatPanelProps {
112
112
  supabaseUrl?: string;
113
113
  /** Supabase anonymous key for realtime features */
114
114
  supabaseAnonKey?: string;
115
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
116
+ productBackendUrl?: string;
115
117
  }
116
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
118
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
117
119
  /**
118
120
  * PanelToggle - An arrow button on the right edge that toggles the side panel
119
121
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -172,8 +174,10 @@ interface ChatPanelWithToggleProps {
172
174
  supabaseUrl?: string;
173
175
  /** Supabase anonymous key for realtime features */
174
176
  supabaseAnonKey?: string;
177
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
178
+ productBackendUrl?: string;
175
179
  }
176
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
180
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
177
181
  /**
178
182
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
179
183
  */
@@ -244,6 +248,8 @@ interface KiteChatConfig {
244
248
  supabaseUrl?: string;
245
249
  /** Supabase anonymous key for realtime features */
246
250
  supabaseAnonKey?: string;
251
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
252
+ productBackendUrl?: string;
247
253
  }
248
254
  /**
249
255
  * Instance returned by createKiteChat with lifecycle control methods.
@@ -112,8 +112,10 @@ interface ChatPanelProps {
112
112
  supabaseUrl?: string;
113
113
  /** Supabase anonymous key for realtime features */
114
114
  supabaseAnonKey?: string;
115
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
116
+ productBackendUrl?: string;
115
117
  }
116
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
118
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
117
119
  /**
118
120
  * PanelToggle - An arrow button on the right edge that toggles the side panel
119
121
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -172,8 +174,10 @@ interface ChatPanelWithToggleProps {
172
174
  supabaseUrl?: string;
173
175
  /** Supabase anonymous key for realtime features */
174
176
  supabaseAnonKey?: string;
177
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
178
+ productBackendUrl?: string;
175
179
  }
176
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
180
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, userOrganization, supabaseUrl, supabaseAnonKey, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
177
181
  /**
178
182
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
179
183
  */
@@ -244,6 +248,8 @@ interface KiteChatConfig {
244
248
  supabaseUrl?: string;
245
249
  /** Supabase anonymous key for realtime features */
246
250
  supabaseAnonKey?: string;
251
+ /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
252
+ productBackendUrl?: string;
247
253
  }
248
254
  /**
249
255
  * Instance returned by createKiteChat with lifecycle control methods.