ajaxter-chat 2.0.1 → 3.0.1

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.
Files changed (94) hide show
  1. package/README.md +119 -128
  2. package/dist/components/BlockList/index.d.ts +10 -0
  3. package/dist/components/BlockList/index.js +33 -0
  4. package/dist/components/CallScreen/index.d.ts +13 -0
  5. package/dist/components/CallScreen/index.js +48 -0
  6. package/dist/components/ChatScreen/index.d.ts +10 -3
  7. package/dist/components/ChatScreen/index.js +142 -57
  8. package/dist/components/ChatWidget.js +192 -98
  9. package/dist/components/EmojiPicker/index.d.ts +8 -0
  10. package/dist/components/EmojiPicker/index.js +18 -0
  11. package/dist/components/HomeScreen/index.d.ts +2 -3
  12. package/dist/components/HomeScreen/index.js +25 -41
  13. package/dist/components/MaintenanceView/index.d.ts +0 -1
  14. package/dist/components/MaintenanceView/index.js +4 -6
  15. package/dist/components/RecentChatsScreen/index.d.ts +4 -3
  16. package/dist/components/RecentChatsScreen/index.js +7 -37
  17. package/dist/components/Tabs/BottomTabs.d.ts +1 -1
  18. package/dist/components/Tabs/BottomTabs.js +25 -20
  19. package/dist/components/TicketScreen/index.d.ts +3 -3
  20. package/dist/components/TicketScreen/index.js +39 -56
  21. package/dist/components/UserListScreen/index.d.ts +2 -4
  22. package/dist/components/UserListScreen/index.js +33 -62
  23. package/dist/config/index.d.ts +3 -3
  24. package/dist/config/index.js +18 -26
  25. package/dist/hooks/useChat.d.ts +8 -3
  26. package/dist/hooks/useChat.js +22 -18
  27. package/dist/hooks/useRemoteConfig.d.ts +6 -0
  28. package/dist/hooks/useRemoteConfig.js +22 -0
  29. package/dist/hooks/useWebRTC.d.ts +11 -0
  30. package/dist/hooks/useWebRTC.js +112 -0
  31. package/dist/index.d.ts +9 -5
  32. package/dist/index.js +8 -4
  33. package/dist/types/index.d.ts +62 -21
  34. package/dist/utils/chat.d.ts +13 -0
  35. package/dist/utils/chat.js +62 -0
  36. package/dist/utils/theme.d.ts +3 -1
  37. package/dist/utils/theme.js +14 -7
  38. package/package.json +4 -4
  39. package/public/chatData.json +162 -0
  40. package/src/components/BlockList/index.tsx +94 -0
  41. package/src/components/CallScreen/index.tsx +144 -0
  42. package/src/components/ChatScreen/index.tsx +403 -139
  43. package/src/components/ChatWidget.tsx +394 -250
  44. package/src/components/EmojiPicker/index.tsx +48 -0
  45. package/src/components/HomeScreen/index.tsx +58 -82
  46. package/src/components/MaintenanceView/index.tsx +6 -9
  47. package/src/components/RecentChatsScreen/index.tsx +51 -96
  48. package/src/components/Tabs/BottomTabs.tsx +45 -37
  49. package/src/components/TicketScreen/index.tsx +87 -133
  50. package/src/components/UserListScreen/index.tsx +75 -153
  51. package/src/config/index.ts +22 -28
  52. package/src/hooks/useChat.ts +31 -14
  53. package/src/hooks/useRemoteConfig.ts +20 -0
  54. package/src/hooks/useWebRTC.ts +130 -0
  55. package/src/index.ts +26 -15
  56. package/src/types/index.ts +85 -40
  57. package/src/utils/chat.ts +70 -0
  58. package/src/utils/theme.ts +18 -7
  59. package/dist/hooks/useUsers.d.ts +0 -7
  60. package/dist/hooks/useUsers.js +0 -26
  61. package/dist/services/userService.d.ts +0 -2
  62. package/dist/services/userService.js +0 -9
  63. package/dist/src/components/ChatScreen/index.d.ts +0 -12
  64. package/dist/src/components/ChatScreen/index.js +0 -83
  65. package/dist/src/components/ChatWidget.d.ts +0 -4
  66. package/dist/src/components/ChatWidget.js +0 -141
  67. package/dist/src/components/HomeScreen/index.d.ts +0 -9
  68. package/dist/src/components/HomeScreen/index.js +0 -71
  69. package/dist/src/components/MaintenanceView/index.d.ts +0 -7
  70. package/dist/src/components/MaintenanceView/index.js +0 -16
  71. package/dist/src/components/RecentChatsScreen/index.d.ts +0 -16
  72. package/dist/src/components/RecentChatsScreen/index.js +0 -38
  73. package/dist/src/components/Tabs/BottomTabs.d.ts +0 -10
  74. package/dist/src/components/Tabs/BottomTabs.js +0 -29
  75. package/dist/src/components/TicketScreen/index.d.ts +0 -9
  76. package/dist/src/components/TicketScreen/index.js +0 -71
  77. package/dist/src/components/UserListScreen/index.d.ts +0 -13
  78. package/dist/src/components/UserListScreen/index.js +0 -64
  79. package/dist/src/config/index.d.ts +0 -3
  80. package/dist/src/config/index.js +0 -38
  81. package/dist/src/hooks/useChat.d.ts +0 -8
  82. package/dist/src/hooks/useChat.js +0 -26
  83. package/dist/src/hooks/useUsers.d.ts +0 -7
  84. package/dist/src/hooks/useUsers.js +0 -26
  85. package/dist/src/index.d.ts +0 -14
  86. package/dist/src/index.js +0 -13
  87. package/dist/src/services/userService.d.ts +0 -2
  88. package/dist/src/services/userService.js +0 -9
  89. package/dist/src/types/index.d.ts +0 -59
  90. package/dist/src/types/index.js +0 -1
  91. package/dist/src/utils/theme.d.ts +0 -3
  92. package/dist/src/utils/theme.js +0 -13
  93. package/src/hooks/useUsers.ts +0 -27
  94. package/src/services/userService.ts +0 -9
@@ -1,141 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState, useEffect, useCallback } from 'react';
4
- import { loadChatConfig, buildUserListUrl } from '../config';
5
- import { mergeTheme } from '../utils/theme';
6
- import { useUsers } from '../hooks/useUsers';
7
- import { useChat } from '../hooks/useChat';
8
- // Screens
9
- import { HomeScreen } from './HomeScreen';
10
- import { UserListScreen } from './UserListScreen';
11
- import { ChatScreen } from './ChatScreen';
12
- import { RecentChatsScreen } from './RecentChatsScreen';
13
- import { TicketScreen } from './TicketScreen';
14
- import { MaintenanceView } from './MaintenanceView';
15
- import { BottomTabs } from './Tabs/BottomTabs';
16
- export const ChatWidget = ({ theme }) => {
17
- const [isMounted, setIsMounted] = useState(false);
18
- const [isOpen, setIsOpen] = useState(false);
19
- const [isMaximized, setIsMaximized] = useState(false);
20
- const [activeTab, setActiveTab] = useState('home');
21
- const [screen, setScreen] = useState('home');
22
- const [userListCtx, setUserListCtx] = useState('support');
23
- const [tickets, setTickets] = useState([]);
24
- // SSR guard
25
- useEffect(() => { setIsMounted(true); }, []);
26
- const config = loadChatConfig();
27
- const t = mergeTheme(theme);
28
- const apiUrl = buildUserListUrl(config);
29
- // Determine filter based on context
30
- const filterType = userListCtx === 'support' ? 'developer' : 'user';
31
- const { users, loading, error } = useUsers(apiUrl, filterType, config.status === 'ACTIVE' && screen === 'user-list');
32
- const { messages, activeUser, selectUser, sendMessage, clearChat } = useChat();
33
- // ── Navigation helpers ─────────────────────────────────────────────────────
34
- const goHome = useCallback(() => { setScreen('home'); setActiveTab('home'); }, []);
35
- const handleTabChange = useCallback((tab) => {
36
- setActiveTab(tab);
37
- if (tab === 'home') {
38
- setScreen('home');
39
- }
40
- if (tab === 'chats') {
41
- setScreen('recent-chats');
42
- }
43
- if (tab === 'tickets') {
44
- setScreen('tickets');
45
- }
46
- }, []);
47
- const handleCardClick = useCallback((ctx) => {
48
- if (ctx === 'ticket') {
49
- setActiveTab('tickets');
50
- setScreen('tickets');
51
- }
52
- else {
53
- setUserListCtx(ctx);
54
- setScreen('user-list');
55
- }
56
- }, []);
57
- const handleSelectUser = useCallback((user) => {
58
- selectUser(user);
59
- setScreen('chat');
60
- }, [selectUser]);
61
- const handleBackFromUserList = useCallback(() => {
62
- setScreen('home');
63
- }, []);
64
- const handleBackFromChat = useCallback(() => {
65
- clearChat();
66
- setScreen('user-list');
67
- }, [clearChat]);
68
- const handleRaiseTicket = useCallback((title, description) => {
69
- const t = {
70
- id: `ticket_${Date.now()}`,
71
- title,
72
- description,
73
- status: 'open',
74
- priority: 'medium',
75
- createdAt: new Date(),
76
- updatedAt: new Date(),
77
- };
78
- setTickets(prev => [t, ...prev]);
79
- }, []);
80
- // ── Sizing ─────────────────────────────────────────────────────────────────
81
- const normalW = 380;
82
- const normalH = 560;
83
- const maxW = 480;
84
- const maxH = 720;
85
- const width = isMaximized ? maxW : normalW;
86
- const height = isMaximized ? maxH : normalH;
87
- const posStyle = t.buttonPosition === 'bottom-left'
88
- ? { left: 24, right: 'auto' }
89
- : { right: 24, left: 'auto' };
90
- if (!isMounted)
91
- return null;
92
- if (config.status === 'DISABLE')
93
- return null;
94
- return (_jsxs(_Fragment, { children: [_jsx("style", { children: `
95
- @import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&display=swap');
96
- @keyframes cw-fadeUp {
97
- from { opacity:0; transform:translateY(10px); }
98
- to { opacity:1; transform:translateY(0); }
99
- }
100
- @keyframes cw-slideInRight {
101
- from { opacity:0; transform:translateX(18px); }
102
- to { opacity:1; transform:translateX(0); }
103
- }
104
- @keyframes cw-popIn {
105
- from { opacity:0; transform:scale(0.88) translateY(16px); }
106
- to { opacity:1; transform:scale(1) translateY(0); }
107
- }
108
- .cw-scrollbar::-webkit-scrollbar { width:4px; }
109
- .cw-scrollbar::-webkit-scrollbar-track { background:transparent; }
110
- .cw-scrollbar::-webkit-scrollbar-thumb { background:#e0e0e0; border-radius:4px; }
111
- ` }), _jsx("button", { onClick: () => setIsOpen(o => !o), "aria-label": isOpen ? 'Close chat' : t.buttonLabel, style: Object.assign(Object.assign({ position: 'fixed', bottom: 24 }, posStyle), { zIndex: 9999, display: 'flex', alignItems: 'center', gap: 10, padding: isOpen ? '14px' : '13px 22px', backgroundColor: t.buttonColor, color: t.buttonTextColor, border: 'none', borderRadius: 50, cursor: 'pointer', fontFamily: t.fontFamily, fontSize: '15px', fontWeight: 700, boxShadow: `0 8px 28px ${t.buttonColor}55`, transition: 'all 0.3s cubic-bezier(0.34,1.56,0.64,1)', transform: isOpen ? 'scale(0.94)' : 'scale(1)', minWidth: isOpen ? 50 : 'auto', justifyContent: 'center' }), onMouseEnter: e => {
112
- if (!isOpen) {
113
- e.currentTarget.style.transform = 'scale(1.06) translateY(-2px)';
114
- e.currentTarget.style.boxShadow = `0 12px 36px ${t.buttonColor}77`;
115
- }
116
- }, onMouseLeave: e => {
117
- e.currentTarget.style.transform = isOpen ? 'scale(0.94)' : 'scale(1)';
118
- e.currentTarget.style.boxShadow = `0 8px 28px ${t.buttonColor}55`;
119
- }, children: isOpen
120
- ? _jsx(CloseIcon, { color: t.buttonTextColor })
121
- : _jsxs(_Fragment, { children: [_jsx(ChatBubbleIcon, { color: t.buttonTextColor }), _jsx("span", { children: t.buttonLabel })] }) }), isOpen && (_jsxs("div", { style: Object.assign(Object.assign({ position: 'fixed', bottom: 86 }, posStyle), { zIndex: 9998, width,
122
- height, maxWidth: 'calc(100vw - 32px)', maxHeight: 'calc(100vh - 110px)', backgroundColor: '#fff', borderRadius: t.borderRadius, boxShadow: '0 20px 70px rgba(0,0,0,0.2), 0 6px 20px rgba(0,0,0,0.08)', display: 'flex', flexDirection: 'column', overflow: 'hidden', fontFamily: t.fontFamily, animation: 'cw-popIn 0.3s cubic-bezier(0.34,1.56,0.64,1)', transition: 'width 0.3s ease, height 0.3s ease' }), children: [screen !== 'chat' && (_jsx("button", { onClick: () => setIsMaximized(m => !m), title: isMaximized ? 'Minimize' : 'Maximize', style: {
123
- position: 'absolute', top: 12, right: 48, zIndex: 10,
124
- background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
125
- width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center',
126
- cursor: 'pointer', transition: 'background 0.15s',
127
- }, onMouseEnter: e => e.currentTarget.style.background = 'rgba(255,255,255,0.38)', onMouseLeave: e => e.currentTarget.style.background = 'rgba(255,255,255,0.22)', children: isMaximized
128
- ? _jsx(MinimizeIcon, {})
129
- : _jsx(MaximizeIcon, {}) })), screen !== 'chat' && (_jsx("button", { onClick: () => setIsOpen(false), title: "Close", style: {
130
- position: 'absolute', top: 12, right: 12, zIndex: 10,
131
- background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
132
- width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center',
133
- cursor: 'pointer',
134
- }, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round" }) }) })), _jsxs("div", { className: "cw-scrollbar", style: { flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }, children: [config.status === 'MAINTENANCE' && (_jsx(MaintenanceView, { primaryColor: t.primaryColor, fontFamily: t.fontFamily })), config.status === 'ACTIVE' && (_jsxs(_Fragment, { children: [screen === 'home' && (_jsx(HomeScreen, { config: config, theme: theme, onNavigate: handleCardClick })), screen === 'user-list' && (_jsx(UserListScreen, { context: userListCtx, users: users, loading: loading, error: error, theme: theme, onBack: handleBackFromUserList, onSelectUser: handleSelectUser })), screen === 'chat' && activeUser && (_jsx(ChatScreen, { activeUser: activeUser, messages: messages, onSend: sendMessage, onBack: handleBackFromChat, onClose: () => setIsOpen(false), theme: theme })), screen === 'recent-chats' && (_jsx(RecentChatsScreen, { chats: [], theme: theme, onSelectChat: handleSelectUser })), screen === 'tickets' && (_jsx(TicketScreen, { tickets: tickets, theme: theme, onRaiseTicket: handleRaiseTicket }))] }))] }), screen !== 'chat' && screen !== 'user-list' && config.status !== 'MAINTENANCE' && (_jsx(BottomTabs, { active: activeTab, onChange: handleTabChange, primaryColor: t.primaryColor, fontFamily: t.fontFamily }))] }))] }));
135
- };
136
- export default ChatWidget;
137
- // ── Tiny SVG icons ─────────────────────────────────────────────────────────────
138
- const ChatBubbleIcon = ({ color }) => (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
139
- const CloseIcon = ({ color }) => (_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: color, strokeWidth: "2.5", strokeLinecap: "round" }) }));
140
- const MaximizeIcon = () => (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M8 3H5a2 2 0 00-2 2v3M21 8V5a2 2 0 00-2-2h-3M3 16v3a2 2 0 002 2h3M16 21h3a2 2 0 002-2v-3", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" }) }));
141
- const MinimizeIcon = () => (_jsx("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M8 3v5H3M21 8h-5V3M3 16h5v5M16 21v-5h5", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" }) }));
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { ChatConfig, ChatWidgetTheme, UserListContext } from '../../types';
3
- interface HomeScreenProps {
4
- config: ChatConfig;
5
- theme?: ChatWidgetTheme;
6
- onNavigate: (ctx: UserListContext | 'ticket') => void;
7
- }
8
- export declare const HomeScreen: React.FC<HomeScreenProps>;
9
- export {};
@@ -1,71 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { mergeTheme } from '../../utils/theme';
3
- export const HomeScreen = ({ config, theme, onNavigate }) => {
4
- const t = mergeTheme(theme);
5
- const showSupport = config.chatType === 'SUPPORT' || config.chatType === 'BOTH';
6
- const showConversation = config.chatType === 'CHAT' || config.chatType === 'BOTH';
7
- const cards = [
8
- showSupport && {
9
- key: 'support',
10
- title: 'Need Support',
11
- subtitle: 'We typically reply in a few minutes',
12
- onClick: () => onNavigate('support'),
13
- },
14
- showConversation && {
15
- key: 'conversation',
16
- title: 'New Conversation',
17
- subtitle: 'With your colleague',
18
- onClick: () => onNavigate('conversation'),
19
- },
20
- // Raise Ticket is always shown
21
- {
22
- key: 'ticket',
23
- title: 'Raise Ticket',
24
- subtitle: 'For major changes',
25
- onClick: () => onNavigate('ticket'),
26
- },
27
- ].filter(Boolean);
28
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: {
29
- backgroundColor: t.primaryColor,
30
- padding: '32px 24px 40px',
31
- flexShrink: 0,
32
- }, children: [_jsx("h1", { style: {
33
- margin: '0 0 8px',
34
- fontSize: '28px',
35
- fontWeight: 800,
36
- color: '#fff',
37
- letterSpacing: '-0.03em',
38
- fontFamily: t.fontFamily,
39
- }, children: "Hi there \uD83D\uDC4B" }), _jsx("p", { style: { margin: 0, fontSize: '15px', color: 'rgba(255,255,255,0.85)', fontFamily: t.fontFamily }, children: "Need help? start a conversation:" })] }), _jsx("div", { style: {
40
- flex: 1,
41
- overflowY: 'auto',
42
- padding: '0 16px 16px',
43
- marginTop: '-24px',
44
- display: 'flex',
45
- flexDirection: 'column',
46
- gap: '10px',
47
- }, children: cards.map((card, i) => (_jsxs("button", { onClick: card.onClick, style: {
48
- width: '100%',
49
- background: '#fff',
50
- border: 'none',
51
- borderRadius: '14px',
52
- padding: '18px 20px',
53
- display: 'flex',
54
- alignItems: 'center',
55
- justifyContent: 'space-between',
56
- cursor: 'pointer',
57
- textAlign: 'left',
58
- boxShadow: '0 2px 12px rgba(0,0,0,0.09)',
59
- transition: 'transform 0.15s ease, box-shadow 0.15s ease',
60
- animation: `cw-fadeUp 0.35s ease both`,
61
- animationDelay: `${i * 0.08}s`,
62
- fontFamily: t.fontFamily,
63
- }, onMouseEnter: e => {
64
- e.currentTarget.style.transform = 'translateY(-2px)';
65
- e.currentTarget.style.boxShadow = '0 6px 20px rgba(0,0,0,0.13)';
66
- }, onMouseLeave: e => {
67
- e.currentTarget.style.transform = 'translateY(0)';
68
- e.currentTarget.style.boxShadow = '0 2px 12px rgba(0,0,0,0.09)';
69
- }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontWeight: 700, fontSize: '15px', color: '#1a2332', marginBottom: '3px' }, children: card.title }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: card.subtitle })] }), _jsx(SendArrow, { color: t.primaryColor })] }, card.key))) })] }));
70
- };
71
- const SendArrow = ({ color }) => (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: _jsx("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- interface MaintenanceViewProps {
3
- primaryColor: string;
4
- fontFamily: string;
5
- }
6
- export declare const MaintenanceView: React.FC<MaintenanceViewProps>;
7
- export {};
@@ -1,16 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export const MaintenanceView = ({ primaryColor, fontFamily }) => (_jsxs("div", { style: {
3
- display: 'flex', flexDirection: 'column', alignItems: 'center',
4
- justifyContent: 'center', height: '100%', padding: '32px',
5
- fontFamily, textAlign: 'center', gap: 16,
6
- }, children: [_jsx("div", { style: {
7
- width: 72, height: 72, borderRadius: '50%',
8
- backgroundColor: `${primaryColor}15`,
9
- display: 'flex', alignItems: 'center', justifyContent: 'center',
10
- }, children: _jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M12 9v4M12 17h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z", stroke: primaryColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("h3", { style: { margin: 0, fontSize: '17px', fontWeight: 800, color: '#1a2332', letterSpacing: '-0.02em' }, children: "Under Maintenance" }), _jsx("p", { style: { margin: 0, fontSize: '14px', color: '#7b8fa1', lineHeight: 1.6, maxWidth: 220 }, children: "Chat is under maintenance. We'll be back shortly!" }), _jsxs("span", { style: {
11
- display: 'inline-flex', alignItems: 'center', gap: 6,
12
- padding: '6px 14px', borderRadius: 20,
13
- backgroundColor: '#fff3cd', color: '#856404',
14
- fontSize: '12px', fontWeight: 700,
15
- border: '1px solid #ffc10730',
16
- }, children: [_jsx("span", { style: { width: 6, height: 6, borderRadius: '50%', backgroundColor: '#ffc107', display: 'inline-block' } }), "Temporarily Unavailable"] })] }));
@@ -1,16 +0,0 @@
1
- import React from 'react';
2
- import { ChatUser, ChatWidgetTheme } from '../../types';
3
- interface RecentChat {
4
- id: string;
5
- user: ChatUser;
6
- lastMessage: string;
7
- lastTime: Date;
8
- unread: number;
9
- }
10
- interface RecentChatsScreenProps {
11
- chats: RecentChat[];
12
- theme?: ChatWidgetTheme;
13
- onSelectChat: (user: ChatUser) => void;
14
- }
15
- export declare const RecentChatsScreen: React.FC<RecentChatsScreenProps>;
16
- export {};
@@ -1,38 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { mergeTheme } from '../../utils/theme';
3
- export const RecentChatsScreen = ({ chats, theme, onSelectChat }) => {
4
- const t = mergeTheme(theme);
5
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: {
6
- backgroundColor: t.primaryColor,
7
- padding: '20px 20px 24px',
8
- flexShrink: 0,
9
- }, children: [_jsx("h2", { style: { margin: 0, fontSize: '20px', fontWeight: 800, color: '#fff', fontFamily: t.fontFamily, letterSpacing: '-0.02em' }, children: "Recent Chats" }), _jsx("p", { style: { margin: '4px 0 0', fontSize: '13px', color: 'rgba(255,255,255,0.8)', fontFamily: t.fontFamily }, children: "Your conversation history" })] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: chats.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center', fontFamily: t.fontFamily }, children: [_jsx("div", { style: { fontSize: '36px', marginBottom: 12 }, children: "\uD83D\uDCAC" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No chats yet" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: "Start a conversation from the home tab" })] })) : (chats.map((chat, i) => {
10
- const initials = chat.user.name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
11
- const avatarColors = ['#1aaa96', '#2563EB', '#7C3AED', '#D97706', '#DC2626'];
12
- const bg = avatarColors[chat.user.name.charCodeAt(0) % avatarColors.length];
13
- const timeStr = new Date(chat.lastTime).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
14
- return (_jsxs("button", { onClick: () => onSelectChat(chat.user), style: {
15
- width: '100%', padding: '14px 20px',
16
- display: 'flex', alignItems: 'center', gap: '14px',
17
- background: 'transparent', border: 'none',
18
- borderBottom: '1px solid #f3f4f6',
19
- cursor: 'pointer', textAlign: 'left',
20
- fontFamily: t.fontFamily,
21
- animation: `cw-fadeUp 0.3s ease both`,
22
- animationDelay: `${i * 0.05}s`,
23
- transition: 'background 0.15s',
24
- }, onMouseEnter: e => e.currentTarget.style.background = '#f8fdfc', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: {
25
- width: 46, height: 46, borderRadius: '50%', backgroundColor: bg,
26
- display: 'flex', alignItems: 'center', justifyContent: 'center',
27
- color: '#fff', fontWeight: 700, fontSize: '15px', flexShrink: 0,
28
- position: 'relative',
29
- }, children: [initials, chat.unread > 0 && (_jsx("span", { style: {
30
- position: 'absolute', top: -2, right: -2,
31
- width: 18, height: 18, borderRadius: '50%',
32
- backgroundColor: '#ff4757', color: '#fff',
33
- fontSize: '10px', fontWeight: 700,
34
- display: 'flex', alignItems: 'center', justifyContent: 'center',
35
- border: '2px solid #fff',
36
- }, children: chat.unread }))] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: 3 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: '14px', color: '#1a2332' }, children: chat.user.name }), _jsx("span", { style: { fontSize: '11px', color: '#b0bec5' }, children: timeStr })] }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: chat.lastMessage })] })] }, chat.id));
37
- })) })] }));
38
- };
@@ -1,10 +0,0 @@
1
- import React from 'react';
2
- import { BottomTab } from '../../types';
3
- interface BottomTabsProps {
4
- active: BottomTab;
5
- onChange: (tab: BottomTab) => void;
6
- primaryColor: string;
7
- fontFamily: string;
8
- }
9
- export declare const BottomTabs: React.FC<BottomTabsProps>;
10
- export {};
@@ -1,29 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export const BottomTabs = ({ active, onChange, primaryColor, fontFamily }) => {
3
- const tabs = [
4
- { key: 'home', label: 'Home', Icon: HomeIcon },
5
- { key: 'chats', label: 'Chats', Icon: ChatsIcon },
6
- { key: 'tickets', label: 'Tickets', Icon: TicketsIcon },
7
- ];
8
- return (_jsx("div", { style: {
9
- display: 'flex',
10
- borderTop: '1px solid #eef0f5',
11
- backgroundColor: '#fff',
12
- flexShrink: 0,
13
- }, children: tabs.map(tab => {
14
- const isActive = active === tab.key;
15
- return (_jsxs("button", { onClick: () => onChange(tab.key), style: {
16
- flex: 1, padding: '10px 0 8px',
17
- display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
18
- background: 'transparent', border: 'none', cursor: 'pointer',
19
- fontFamily, fontSize: '10px', fontWeight: isActive ? 700 : 500,
20
- color: isActive ? primaryColor : '#9aa3af',
21
- transition: 'color 0.15s',
22
- borderTop: isActive ? `2px solid ${primaryColor}` : '2px solid transparent',
23
- }, children: [_jsx(tab.Icon, { active: isActive, color: isActive ? primaryColor : '#b0bec5' }), tab.label] }, tab.key));
24
- }) }));
25
- };
26
- // ── Icons ─────────────────────────────────────────────────────────────────────
27
- const HomeIcon = ({ active, color }) => (_jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M3 9.5L12 3l9 6.5V20a1 1 0 01-1 1H4a1 1 0 01-1-1V9.5z", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round", fill: active ? `${color}20` : 'none' }), _jsx("path", { d: "M9 21V12h6v9", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round" })] }));
28
- const ChatsIcon = ({ active, color }) => (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round", fill: active ? `${color}20` : 'none' }) }));
29
- const TicketsIcon = ({ active, color }) => (_jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M15 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V9l-4-4z", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round", fill: active ? `${color}20` : 'none' }), _jsx("path", { d: "M15 5v4h4M9 13h6M9 17h4", stroke: color, strokeWidth: active ? 2.2 : 1.8, strokeLinecap: "round" })] }));
@@ -1,9 +0,0 @@
1
- import React from 'react';
2
- import { ChatWidgetTheme, Ticket } from '../../types';
3
- interface TicketScreenProps {
4
- tickets: Ticket[];
5
- theme?: ChatWidgetTheme;
6
- onRaiseTicket: (title: string, description: string) => void;
7
- }
8
- export declare const TicketScreen: React.FC<TicketScreenProps>;
9
- export {};
@@ -1,71 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
3
- import { mergeTheme } from '../../utils/theme';
4
- export const TicketScreen = ({ tickets, theme, onRaiseTicket }) => {
5
- const t = mergeTheme(theme);
6
- const [showForm, setShowForm] = useState(false);
7
- const [title, setTitle] = useState('');
8
- const [desc, setDesc] = useState('');
9
- const handleSubmit = () => {
10
- if (!title.trim())
11
- return;
12
- onRaiseTicket(title.trim(), desc.trim());
13
- setTitle('');
14
- setDesc('');
15
- setShowForm(false);
16
- };
17
- const statusMeta = {
18
- 'open': { label: 'Open', bg: '#e6faf8', color: t.primaryColor },
19
- 'in-progress': { label: 'In Progress', bg: '#fffbeb', color: '#d97706' },
20
- 'resolved': { label: 'Resolved', bg: '#f0fdf4', color: '#16a34a' },
21
- 'closed': { label: 'Closed', bg: '#f3f4f6', color: '#6b7280' },
22
- };
23
- const priorityMeta = {
24
- low: { label: '↓ Low', color: '#6b7280' },
25
- medium: { label: '→ Medium', color: '#d97706' },
26
- high: { label: '↑ High', color: '#dc2626' },
27
- };
28
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsx("div", { style: { backgroundColor: t.primaryColor, padding: '20px 20px 24px', flexShrink: 0 }, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: '20px', fontWeight: 800, color: '#fff', fontFamily: t.fontFamily, letterSpacing: '-0.02em' }, children: "Tickets" }), _jsxs("p", { style: { margin: '4px 0 0', fontSize: '13px', color: 'rgba(255,255,255,0.8)', fontFamily: t.fontFamily }, children: [tickets.length, " ticket", tickets.length !== 1 ? 's' : '', " raised"] })] }), _jsx("button", { onClick: () => setShowForm(v => !v), style: {
29
- background: 'rgba(255,255,255,0.25)', border: 'none', borderRadius: '20px',
30
- padding: '8px 16px', color: '#fff', fontWeight: 700, fontSize: '13px',
31
- cursor: 'pointer', fontFamily: t.fontFamily, display: 'flex', alignItems: 'center', gap: 5,
32
- }, children: showForm ? '✕ Cancel' : '+ New Ticket' })] }) }), showForm && (_jsxs("div", { style: {
33
- padding: '16px 20px',
34
- borderBottom: '1px solid #eef0f5',
35
- backgroundColor: '#fafcff',
36
- animation: 'cw-fadeUp 0.2s ease',
37
- flexShrink: 0,
38
- }, children: [_jsx("input", { placeholder: "Ticket title *", value: title, onChange: e => setTitle(e.target.value), style: {
39
- width: '100%', padding: '10px 14px', borderRadius: 10,
40
- border: '1.5px solid #e2e8f0', outline: 'none',
41
- fontFamily: t.fontFamily, fontSize: '14px', color: '#1a2332',
42
- marginBottom: 10, boxSizing: 'border-box',
43
- }, onFocus: e => (e.target.style.borderColor = t.primaryColor), onBlur: e => (e.target.style.borderColor = '#e2e8f0') }), _jsx("textarea", { placeholder: "Describe the issue (optional)", value: desc, onChange: e => setDesc(e.target.value), rows: 3, style: {
44
- width: '100%', padding: '10px 14px', borderRadius: 10,
45
- border: '1.5px solid #e2e8f0', outline: 'none', resize: 'none',
46
- fontFamily: t.fontFamily, fontSize: '14px', color: '#1a2332',
47
- marginBottom: 10, boxSizing: 'border-box',
48
- }, onFocus: e => (e.target.style.borderColor = t.primaryColor), onBlur: e => (e.target.style.borderColor = '#e2e8f0') }), _jsx("button", { onClick: handleSubmit, disabled: !title.trim(), style: {
49
- width: '100%', padding: '11px', borderRadius: 10,
50
- backgroundColor: title.trim() ? t.primaryColor : '#e2e8f0',
51
- color: title.trim() ? '#fff' : '#9aa3af',
52
- border: 'none', cursor: title.trim() ? 'pointer' : 'not-allowed',
53
- fontWeight: 700, fontSize: '14px', fontFamily: t.fontFamily,
54
- transition: 'background 0.2s',
55
- }, children: "Submit Ticket" })] })), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: tickets.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center', fontFamily: t.fontFamily }, children: [_jsx("div", { style: { fontSize: '36px', marginBottom: 12 }, children: "\uD83C\uDFAB" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No tickets yet" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: "Raise a ticket for major issues or changes" })] })) : (tickets.map((ticket, i) => {
56
- const sm = statusMeta[ticket.status];
57
- const pm = priorityMeta[ticket.priority];
58
- const date = new Date(ticket.createdAt).toLocaleDateString([], { month: 'short', day: 'numeric' });
59
- return (_jsxs("div", { style: {
60
- padding: '14px 20px',
61
- borderBottom: '1px solid #f3f4f6',
62
- fontFamily: t.fontFamily,
63
- animation: `cw-fadeUp 0.3s ease both`,
64
- animationDelay: `${i * 0.05}s`,
65
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 6 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: '14px', color: '#1a2332', flex: 1, paddingRight: 12 }, children: ticket.title }), _jsx("span", { style: {
66
- fontSize: '10px', fontWeight: 700, padding: '3px 9px', borderRadius: 20,
67
- backgroundColor: sm.bg, color: sm.color, whiteSpace: 'nowrap',
68
- textTransform: 'uppercase', letterSpacing: '0.04em',
69
- }, children: sm.label })] }), ticket.description && (_jsx("div", { style: { fontSize: '13px', color: '#7b8fa1', marginBottom: 8, lineHeight: 1.5 }, children: ticket.description })), _jsxs("div", { style: { display: 'flex', gap: 12, fontSize: '11px', color: '#b0bec5' }, children: [_jsx("span", { style: { color: pm.color, fontWeight: 600 }, children: pm.label }), _jsxs("span", { children: ["#", ticket.id.slice(-6).toUpperCase()] }), _jsx("span", { children: date })] })] }, ticket.id));
70
- })) })] }));
71
- };
@@ -1,13 +0,0 @@
1
- import React from 'react';
2
- import { ChatUser, ChatWidgetTheme, UserListContext } from '../../types';
3
- interface UserListScreenProps {
4
- context: UserListContext;
5
- users: ChatUser[];
6
- loading: boolean;
7
- error: string | null;
8
- theme?: ChatWidgetTheme;
9
- onBack: () => void;
10
- onSelectUser: (user: ChatUser) => void;
11
- }
12
- export declare const UserListScreen: React.FC<UserListScreenProps>;
13
- export {};
@@ -1,64 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { mergeTheme } from '../../utils/theme';
3
- export const UserListScreen = ({ context, users, loading, error, theme, onBack, onSelectUser, }) => {
4
- const t = mergeTheme(theme);
5
- const title = context === 'support' ? 'Need Support' : 'New Conversation';
6
- const subtitle = context === 'support'
7
- ? 'Choose a support agent'
8
- : 'Choose a colleague to chat with';
9
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideInRight 0.25s ease' }, children: [_jsxs("div", { style: {
10
- backgroundColor: t.primaryColor,
11
- padding: '16px 20px',
12
- display: 'flex',
13
- alignItems: 'center',
14
- gap: '12px',
15
- flexShrink: 0,
16
- }, children: [_jsx("button", { onClick: onBack, style: {
17
- background: 'rgba(255,255,255,0.2)',
18
- border: 'none',
19
- borderRadius: '50%',
20
- width: '34px',
21
- height: '34px',
22
- display: 'flex',
23
- alignItems: 'center',
24
- justifyContent: 'center',
25
- cursor: 'pointer',
26
- flexShrink: 0,
27
- }, children: _jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsxs("div", { children: [_jsx("div", { style: { fontWeight: 700, fontSize: '16px', color: '#fff', fontFamily: t.fontFamily }, children: title }), _jsx("div", { style: { fontSize: '12px', color: 'rgba(255,255,255,0.8)', fontFamily: t.fontFamily }, children: subtitle })] })] }), _jsxs("div", { style: { flex: 1, overflowY: 'auto', padding: '8px 0' }, children: [loading && _jsx(UserListSkeleton, {}), error && _jsx(ErrorState, { message: error, color: t.primaryColor, font: t.fontFamily }), !loading && !error && users.length === 0 && (_jsx(EmptyState, { color: t.primaryColor, font: t.fontFamily })), !loading && !error && users.map((user, i) => (_jsx(UserRow, { user: user, index: i, primaryColor: t.primaryColor, fontFamily: t.fontFamily, onClick: () => onSelectUser(user) }, user.uid)))] })] }));
28
- };
29
- // ── Sub-components ─────────────────────────────────────────────────────────────
30
- const UserRow = ({ user, index, primaryColor, fontFamily, onClick }) => {
31
- const initials = user.name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
32
- const avatarColors = ['#1aaa96', '#2563EB', '#7C3AED', '#D97706', '#DC2626', '#059669'];
33
- const bg = avatarColors[user.name.charCodeAt(0) % avatarColors.length];
34
- return (_jsxs("button", { onClick: onClick, style: {
35
- width: '100%',
36
- padding: '14px 20px',
37
- display: 'flex',
38
- alignItems: 'center',
39
- gap: '14px',
40
- background: 'transparent',
41
- border: 'none',
42
- borderBottom: '1px solid #f3f4f6',
43
- cursor: 'pointer',
44
- textAlign: 'left',
45
- fontFamily,
46
- animation: 'cw-fadeUp 0.3s ease both',
47
- animationDelay: `${index * 0.05}s`,
48
- transition: 'background 0.15s',
49
- }, onMouseEnter: e => e.currentTarget.style.background = '#f8fdfc', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsx("div", { style: {
50
- width: '46px', height: '46px', borderRadius: '50%',
51
- backgroundColor: bg, flexShrink: 0,
52
- display: 'flex', alignItems: 'center', justifyContent: 'center',
53
- color: '#fff', fontWeight: 700, fontSize: '15px',
54
- }, children: initials }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: '14px', color: '#1a2332', marginBottom: '2px' }, children: user.name }), _jsx("div", { style: { fontSize: '12px', color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: user.project || user.email })] }), _jsx("span", { style: {
55
- fontSize: '10px', fontWeight: 700, padding: '3px 9px',
56
- borderRadius: '20px', textTransform: 'uppercase', letterSpacing: '0.05em',
57
- backgroundColor: user.type === 'developer' ? '#e6faf8' : '#eff6ff',
58
- color: user.type === 'developer' ? primaryColor : '#2563EB',
59
- border: `1px solid ${user.type === 'developer' ? primaryColor + '30' : '#2563eb30'}`,
60
- }, children: user.type === 'developer' ? 'Dev' : 'User' })] }));
61
- };
62
- const UserListSkeleton = () => (_jsx(_Fragment, { children: [1, 2, 3, 4].map(i => (_jsxs("div", { style: { padding: '14px 20px', display: 'flex', gap: '14px', alignItems: 'center' }, children: [_jsx("div", { style: { width: 46, height: 46, borderRadius: '50%', background: '#f0f0f0', flexShrink: 0 } }), _jsxs("div", { style: { flex: 1 }, children: [_jsx("div", { style: { height: 13, width: '55%', background: '#f0f0f0', borderRadius: 6, marginBottom: 7 } }), _jsx("div", { style: { height: 11, width: '38%', background: '#f0f0f0', borderRadius: 6 } })] })] }, i))) }));
63
- const ErrorState = ({ message, color, font }) => (_jsxs("div", { style: { padding: '40px 24px', textAlign: 'center', fontFamily: font }, children: [_jsx("div", { style: { fontSize: '32px', marginBottom: '10px' }, children: "\u26A0\uFE0F" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: '6px' }, children: "Could not load users" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: message })] }));
64
- const EmptyState = ({ color, font }) => (_jsxs("div", { style: { padding: '40px 24px', textAlign: 'center', fontFamily: font }, children: [_jsx("div", { style: { fontSize: '32px', marginBottom: '10px' }, children: "\uD83D\uDC65" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: '6px' }, children: "No users available" }), _jsx("div", { style: { fontSize: '13px', color: '#7b8fa1' }, children: "Check back later" })] }));
@@ -1,3 +0,0 @@
1
- import { ChatConfig } from '../types';
2
- export declare function loadChatConfig(): ChatConfig;
3
- export declare function buildUserListUrl(config: ChatConfig): string;
@@ -1,38 +0,0 @@
1
- function getEnv(key) {
2
- var _a, _b, _c;
3
- if (typeof process !== 'undefined' && process.env) {
4
- return ((_c = (_b = (_a = process.env[`NEXT_PUBLIC_${key}`]) !== null && _a !== void 0 ? _a : process.env[`REACT_APP_${key}`]) !== null && _b !== void 0 ? _b : process.env[key]) !== null && _c !== void 0 ? _c : undefined);
5
- }
6
- return undefined;
7
- }
8
- function validateStatus(v) {
9
- if (v === 'ACTIVE' || v === 'DISABLE' || v === 'MAINTENANCE')
10
- return v;
11
- console.warn(`[ChatWidget] Invalid CHAT_STATUS "${v}". Defaulting to DISABLE.`);
12
- return 'DISABLE';
13
- }
14
- function validateChatType(v) {
15
- if (v === 'SUPPORT' || v === 'CHAT' || v === 'BOTH')
16
- return v;
17
- console.warn(`[ChatWidget] Invalid CHAT_TYPE "${v}". Defaulting to SUPPORT.`);
18
- return 'SUPPORT';
19
- }
20
- export function loadChatConfig() {
21
- var _a, _b;
22
- const portStr = getEnv('CHAT_HOST_PORT');
23
- const hostPort = portStr ? parseInt(portStr, 10) : null;
24
- return {
25
- hostUrl: (_a = getEnv('CHAT_HOST_URL')) !== null && _a !== void 0 ? _a : 'http://localhost',
26
- hostPort,
27
- userListEndpoint: (_b = getEnv('CHAT_USER_LIST')) !== null && _b !== void 0 ? _b : 'api/users',
28
- status: validateStatus(getEnv('CHAT_STATUS')),
29
- chatType: validateChatType(getEnv('CHAT_TYPE')),
30
- };
31
- }
32
- export function buildUserListUrl(config) {
33
- const base = config.hostUrl.replace(/\/$/, '');
34
- const endpoint = config.userListEndpoint.replace(/^\//, '');
35
- // Port is optional
36
- const portPart = config.hostPort ? `:${config.hostPort}` : '';
37
- return `${base}${portPart}/${endpoint}`;
38
- }
@@ -1,8 +0,0 @@
1
- import { ChatMessage, ChatUser } from '../types';
2
- export declare function useChat(): {
3
- messages: ChatMessage[];
4
- activeUser: ChatUser | null;
5
- selectUser: (user: ChatUser) => void;
6
- sendMessage: (text: string) => void;
7
- clearChat: () => void;
8
- };
@@ -1,26 +0,0 @@
1
- import { useState, useCallback } from 'react';
2
- export function useChat() {
3
- const [messages, setMessages] = useState([]);
4
- const [activeUser, setActiveUser] = useState(null);
5
- const selectUser = useCallback((user) => {
6
- setActiveUser(user);
7
- setMessages([]);
8
- // TODO: socket.emit('join', user.uid); socket.on('message', handler)
9
- }, []);
10
- const sendMessage = useCallback((text) => {
11
- if (!activeUser || !text.trim())
12
- return;
13
- const msg = {
14
- id: `msg_${Date.now()}`,
15
- senderId: 'me',
16
- receiverId: activeUser.uid,
17
- text: text.trim(),
18
- timestamp: new Date(),
19
- status: 'sent',
20
- };
21
- setMessages(prev => [...prev, msg]);
22
- // TODO: socket.emit('message', msg)
23
- }, [activeUser]);
24
- const clearChat = useCallback(() => { setMessages([]); setActiveUser(null); }, []);
25
- return { messages, activeUser, selectUser, sendMessage, clearChat };
26
- }
@@ -1,7 +0,0 @@
1
- import { ChatUser, UserType } from '../types';
2
- export declare function useUsers(url: string, filterType?: UserType, enabled?: boolean): {
3
- users: ChatUser[];
4
- loading: boolean;
5
- error: string | null;
6
- refetch: () => Promise<void>;
7
- };