ajaxter-chat 2.0.1 → 3.0.3
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 +119 -128
- package/dist/components/BlockList/index.d.ts +10 -0
- package/dist/components/BlockList/index.js +33 -0
- package/dist/components/CallScreen/index.d.ts +13 -0
- package/dist/components/CallScreen/index.js +48 -0
- package/dist/components/ChatScreen/index.d.ts +10 -3
- package/dist/components/ChatScreen/index.js +142 -57
- package/dist/components/ChatWidget.js +192 -98
- package/dist/components/EmojiPicker/index.d.ts +8 -0
- package/dist/components/EmojiPicker/index.js +18 -0
- package/dist/components/HomeScreen/index.d.ts +2 -3
- package/dist/components/HomeScreen/index.js +25 -41
- package/dist/components/MaintenanceView/index.d.ts +0 -1
- package/dist/components/MaintenanceView/index.js +4 -6
- package/dist/components/RecentChatsScreen/index.d.ts +4 -3
- package/dist/components/RecentChatsScreen/index.js +7 -37
- package/dist/components/Tabs/BottomTabs.d.ts +1 -1
- package/dist/components/Tabs/BottomTabs.js +25 -20
- package/dist/components/TicketScreen/index.d.ts +3 -3
- package/dist/components/TicketScreen/index.js +39 -56
- package/dist/components/UserListScreen/index.d.ts +2 -4
- package/dist/components/UserListScreen/index.js +33 -62
- package/dist/config/index.d.ts +7 -3
- package/dist/config/index.js +28 -25
- package/dist/hooks/useChat.d.ts +8 -3
- package/dist/hooks/useChat.js +22 -18
- package/dist/hooks/useRemoteConfig.d.ts +6 -0
- package/dist/hooks/useRemoteConfig.js +26 -0
- package/dist/hooks/useWebRTC.d.ts +11 -0
- package/dist/hooks/useWebRTC.js +112 -0
- package/dist/index.d.ts +9 -5
- package/dist/index.js +8 -4
- package/dist/types/index.d.ts +62 -21
- package/dist/utils/chat.d.ts +13 -0
- package/dist/utils/chat.js +62 -0
- package/dist/utils/theme.d.ts +3 -1
- package/dist/utils/theme.js +14 -7
- package/package.json +4 -4
- package/public/chatData.json +162 -0
- package/src/components/BlockList/index.tsx +94 -0
- package/src/components/CallScreen/index.tsx +144 -0
- package/src/components/ChatScreen/index.tsx +403 -139
- package/src/components/ChatWidget.tsx +394 -250
- package/src/components/EmojiPicker/index.tsx +48 -0
- package/src/components/HomeScreen/index.tsx +58 -82
- package/src/components/MaintenanceView/index.tsx +6 -9
- package/src/components/RecentChatsScreen/index.tsx +51 -96
- package/src/components/Tabs/BottomTabs.tsx +45 -37
- package/src/components/TicketScreen/index.tsx +87 -133
- package/src/components/UserListScreen/index.tsx +75 -153
- package/src/config/index.ts +32 -26
- package/src/hooks/useChat.ts +31 -14
- package/src/hooks/useRemoteConfig.ts +26 -0
- package/src/hooks/useWebRTC.ts +130 -0
- package/src/index.ts +26 -15
- package/src/types/index.ts +85 -40
- package/src/utils/chat.ts +70 -0
- package/src/utils/theme.ts +18 -7
- package/dist/hooks/useUsers.d.ts +0 -7
- package/dist/hooks/useUsers.js +0 -26
- package/dist/services/userService.d.ts +0 -2
- package/dist/services/userService.js +0 -9
- package/dist/src/components/ChatScreen/index.d.ts +0 -12
- package/dist/src/components/ChatScreen/index.js +0 -83
- package/dist/src/components/ChatWidget.d.ts +0 -4
- package/dist/src/components/ChatWidget.js +0 -141
- package/dist/src/components/HomeScreen/index.d.ts +0 -9
- package/dist/src/components/HomeScreen/index.js +0 -71
- package/dist/src/components/MaintenanceView/index.d.ts +0 -7
- package/dist/src/components/MaintenanceView/index.js +0 -16
- package/dist/src/components/RecentChatsScreen/index.d.ts +0 -16
- package/dist/src/components/RecentChatsScreen/index.js +0 -38
- package/dist/src/components/Tabs/BottomTabs.d.ts +0 -10
- package/dist/src/components/Tabs/BottomTabs.js +0 -29
- package/dist/src/components/TicketScreen/index.d.ts +0 -9
- package/dist/src/components/TicketScreen/index.js +0 -71
- package/dist/src/components/UserListScreen/index.d.ts +0 -13
- package/dist/src/components/UserListScreen/index.js +0 -64
- package/dist/src/config/index.d.ts +0 -3
- package/dist/src/config/index.js +0 -38
- package/dist/src/hooks/useChat.d.ts +0 -8
- package/dist/src/hooks/useChat.js +0 -26
- package/dist/src/hooks/useUsers.d.ts +0 -7
- package/dist/src/hooks/useUsers.js +0 -26
- package/dist/src/index.d.ts +0 -14
- package/dist/src/index.js +0 -13
- package/dist/src/services/userService.d.ts +0 -2
- package/dist/src/services/userService.js +0 -9
- package/dist/src/types/index.d.ts +0 -59
- package/dist/src/types/index.js +0 -1
- package/dist/src/utils/theme.d.ts +0 -3
- package/dist/src/utils/theme.js +0 -13
- package/src/hooks/useUsers.ts +0 -27
- package/src/services/userService.ts +0 -9
|
@@ -1,38 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
export const RecentChatsScreen = ({ chats,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
};
|
|
2
|
+
import { avatarColor, initials, formatTime } from '../../utils/chat';
|
|
3
|
+
export const RecentChatsScreen = ({ chats, config, onSelectChat }) => (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: { background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`, padding: '18px 18px 22px', flexShrink: 0 }, children: [_jsx("h2", { style: { margin: 0, fontSize: 20, fontWeight: 800, color: '#fff', letterSpacing: '-0.02em' }, children: "Recent Chats" }), _jsx("p", { style: { margin: '3px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: "Your conversation history" })] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: chats.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\uD83D\uDCAC" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No chats yet" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Start a conversation from home" })] })) : chats.map((chat, i) => (_jsxs("button", { onClick: () => onSelectChat(chat.user), style: {
|
|
4
|
+
width: '100%', padding: '13px 16px', display: 'flex', alignItems: 'center', gap: 13,
|
|
5
|
+
background: 'transparent', border: 'none', borderBottom: '1px solid #f0f2f5',
|
|
6
|
+
cursor: 'pointer', textAlign: 'left', animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s`,
|
|
7
|
+
transition: 'background 0.14s',
|
|
8
|
+
}, onMouseEnter: e => e.currentTarget.style.background = '#f8faff', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: { position: 'relative', flexShrink: 0 }, children: [_jsx("div", { style: { width: 46, height: 46, borderRadius: '50%', backgroundColor: avatarColor(chat.user.name), display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontWeight: 700, fontSize: 15 }, children: initials(chat.user.name) }), chat.unread > 0 && (_jsx("span", { style: { position: 'absolute', top: -2, right: -2, width: 18, height: 18, borderRadius: '50%', background: '#ef4444', color: '#fff', fontSize: 10, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', border: '2px solid #fff' }, 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: 14, color: '#1a2332' }, children: chat.user.name }), _jsx("span", { style: { fontSize: 11, color: '#b0bec5' }, children: formatTime(chat.lastTime) })] }), _jsxs("div", { style: { fontSize: 13, color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'flex', alignItems: 'center', gap: 5 }, children: [chat.isPaused && _jsx("span", { style: { fontSize: 10, background: '#fef3c7', color: '#92400e', padding: '1px 5px', borderRadius: 4, fontWeight: 700 }, children: "PAUSED" }), chat.lastMessage] })] })] }, chat.id))) })] }));
|
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export const BottomTabs = ({ active, onChange, primaryColor,
|
|
2
|
+
export const BottomTabs = ({ active, onChange, primaryColor, onBlockList }) => {
|
|
3
3
|
const tabs = [
|
|
4
4
|
{ key: 'home', label: 'Home', Icon: HomeIcon },
|
|
5
5
|
{ key: 'chats', label: 'Chats', Icon: ChatsIcon },
|
|
6
6
|
{ key: 'tickets', label: 'Tickets', Icon: TicketsIcon },
|
|
7
7
|
];
|
|
8
|
-
return (
|
|
9
|
-
display: 'flex',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
return (_jsxs("div", { style: {
|
|
9
|
+
display: 'flex', borderTop: '1px solid #eef0f5',
|
|
10
|
+
backgroundColor: '#fff', flexShrink: 0,
|
|
11
|
+
}, children: [tabs.map(tab => {
|
|
12
|
+
const isActive = active === tab.key;
|
|
13
|
+
return (_jsxs("button", { onClick: () => onChange(tab.key), style: {
|
|
14
|
+
flex: 1, padding: '10px 0 8px',
|
|
15
|
+
display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
|
|
16
|
+
background: 'transparent', border: 'none', cursor: 'pointer',
|
|
17
|
+
fontSize: '10px', fontWeight: isActive ? 700 : 500,
|
|
18
|
+
color: isActive ? primaryColor : '#9aa3af',
|
|
19
|
+
borderTop: isActive ? `2px solid ${primaryColor}` : '2px solid transparent',
|
|
20
|
+
transition: 'color 0.15s',
|
|
21
|
+
fontFamily: 'inherit',
|
|
22
|
+
}, children: [_jsx(tab.Icon, { a: isActive, c: isActive ? primaryColor : '#b0bec5' }), tab.label] }, tab.key));
|
|
23
|
+
}), _jsxs("button", { onClick: onBlockList, style: {
|
|
24
|
+
padding: '10px 14px 8px',
|
|
17
25
|
display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
|
|
18
26
|
background: 'transparent', border: 'none', cursor: 'pointer',
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
transition: 'color 0.15s',
|
|
22
|
-
|
|
23
|
-
}, children: [_jsx(tab.Icon, { active: isActive, color: isActive ? primaryColor : '#b0bec5' }), tab.label] }, tab.key));
|
|
24
|
-
}) }));
|
|
27
|
+
fontSize: '10px', fontWeight: 500, color: '#9aa3af',
|
|
28
|
+
borderTop: '2px solid transparent',
|
|
29
|
+
transition: 'color 0.15s', fontFamily: 'inherit',
|
|
30
|
+
}, title: "Block List", children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "#b0bec5", strokeWidth: "1.8" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07", stroke: "#b0bec5", strokeWidth: "1.8", strokeLinecap: "round" })] }), "Blocked"] })] }));
|
|
25
31
|
};
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const
|
|
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" })] }));
|
|
32
|
+
const HomeIcon = ({ a, c }) => (_jsxs("svg", { width: "20", height: "20", 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: c, strokeWidth: a ? 2.2 : 1.8, fill: a ? `${c}20` : 'none', strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M9 21V12h6v9", stroke: c, strokeWidth: a ? 2.2 : 1.8, strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
33
|
+
const ChatsIcon = ({ a, c }) => (_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: c, strokeWidth: a ? 2.2 : 1.8, fill: a ? `${c}20` : 'none', strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
34
|
+
const TicketsIcon = ({ a, c }) => (_jsxs("svg", { width: "20", height: "20", 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: c, strokeWidth: a ? 2.2 : 1.8, fill: a ? `${c}20` : 'none', strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M15 5v4h4M9 13h6M9 17h4", stroke: c, strokeWidth: a ? 2.2 : 1.8, strokeLinecap: "round" })] }));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Ticket, WidgetConfig } from '../../types';
|
|
3
3
|
interface TicketScreenProps {
|
|
4
4
|
tickets: Ticket[];
|
|
5
|
-
|
|
6
|
-
onRaiseTicket: (title: string,
|
|
5
|
+
config: WidgetConfig;
|
|
6
|
+
onRaiseTicket: (title: string, desc: string, priority: Ticket['priority']) => void;
|
|
7
7
|
}
|
|
8
8
|
export declare const TicketScreen: React.FC<TicketScreenProps>;
|
|
9
9
|
export {};
|
|
@@ -1,71 +1,54 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
|
|
4
|
-
export const TicketScreen = ({ tickets, theme, onRaiseTicket }) => {
|
|
5
|
-
const t = mergeTheme(theme);
|
|
3
|
+
export const TicketScreen = ({ tickets, config, onRaiseTicket }) => {
|
|
6
4
|
const [showForm, setShowForm] = useState(false);
|
|
7
5
|
const [title, setTitle] = useState('');
|
|
8
6
|
const [desc, setDesc] = useState('');
|
|
7
|
+
const [priority, setPriority] = useState('medium');
|
|
9
8
|
const handleSubmit = () => {
|
|
10
9
|
if (!title.trim())
|
|
11
10
|
return;
|
|
12
|
-
onRaiseTicket(title.trim(), desc.trim());
|
|
11
|
+
onRaiseTicket(title.trim(), desc.trim(), priority);
|
|
13
12
|
setTitle('');
|
|
14
13
|
setDesc('');
|
|
14
|
+
setPriority('medium');
|
|
15
15
|
setShowForm(false);
|
|
16
16
|
};
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
'in-progress': { label: 'In Progress', bg: '#
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
const sm = {
|
|
18
|
+
open: { label: 'Open', bg: `${config.primaryColor}14`, color: config.primaryColor },
|
|
19
|
+
'in-progress': { label: 'In Progress', bg: '#fef3c7', color: '#d97706' },
|
|
20
|
+
resolved: { label: 'Resolved', bg: '#f0fdf4', color: '#16a34a' },
|
|
21
|
+
closed: { label: 'Closed', bg: '#f3f4f6', color: '#6b7280' },
|
|
22
22
|
};
|
|
23
|
-
const
|
|
24
|
-
low: { label: '
|
|
25
|
-
medium: { label: '
|
|
26
|
-
high: { label: '
|
|
23
|
+
const pm = {
|
|
24
|
+
low: { label: 'Low', color: '#6b7280' },
|
|
25
|
+
medium: { label: 'Medium', color: '#d97706' },
|
|
26
|
+
high: { label: 'High', color: '#ef4444' },
|
|
27
27
|
};
|
|
28
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsx("div", { style: {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
})) })] }));
|
|
28
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsx("div", { style: {
|
|
29
|
+
background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
|
|
30
|
+
padding: '18px 18px 22px', flexShrink: 0, position: 'relative',
|
|
31
|
+
}, children: _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }, children: [_jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: 20, fontWeight: 800, color: '#fff', letterSpacing: '-0.02em' }, children: "Tickets" }), _jsxs("p", { style: { margin: '3px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: [tickets.length, " ticket", tickets.length !== 1 ? 's' : '', " raised"] })] }), _jsx("button", { onClick: () => setShowForm(v => !v), style: {
|
|
32
|
+
background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: 20,
|
|
33
|
+
padding: '7px 14px', color: '#fff', fontWeight: 700, fontSize: 13,
|
|
34
|
+
cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 5,
|
|
35
|
+
}, children: showForm ? '✕ Cancel' : '+ New' })] }) }), showForm && (_jsxs("div", { style: { padding: '16px', borderBottom: '1px solid #eef0f5', background: '#fafcff', flexShrink: 0, animation: 'cw-fadeUp 0.2s ease' }, children: [_jsx("input", { placeholder: "Title *", value: title, onChange: e => setTitle(e.target.value), style: inputStyle(config.primaryColor), onFocus: e => (e.target.style.borderColor = config.primaryColor), onBlur: e => (e.target.style.borderColor = '#e5e7eb') }), _jsx("textarea", { placeholder: "Describe the issue\u2026", value: desc, onChange: e => setDesc(e.target.value), rows: 3, style: Object.assign(Object.assign({}, inputStyle(config.primaryColor)), { resize: 'none', marginTop: 8 }), onFocus: e => (e.target.style.borderColor = config.primaryColor), onBlur: e => (e.target.style.borderColor = '#e5e7eb') }), _jsx("div", { style: { display: 'flex', gap: 8, marginTop: 8, marginBottom: 12 }, children: ['low', 'medium', 'high'].map(p => (_jsx("button", { onClick: () => setPriority(p), style: {
|
|
36
|
+
flex: 1, padding: '6px', border: `1.5px solid ${priority === p ? pm[p].color : '#e5e7eb'}`,
|
|
37
|
+
borderRadius: 8, background: priority === p ? pm[p].color + '15' : '#fff',
|
|
38
|
+
color: pm[p].color, fontWeight: 700, fontSize: 12, cursor: 'pointer', textTransform: 'capitalize',
|
|
39
|
+
transition: 'all 0.15s',
|
|
40
|
+
}, children: pm[p].label }, p))) }), _jsx("button", { onClick: handleSubmit, disabled: !title.trim(), style: {
|
|
41
|
+
width: '100%', padding: '10px', borderRadius: 10, border: 'none',
|
|
42
|
+
background: title.trim() ? config.primaryColor : '#e5e7eb',
|
|
43
|
+
color: title.trim() ? '#fff' : '#9ca3af',
|
|
44
|
+
fontWeight: 700, fontSize: 14, cursor: title.trim() ? 'pointer' : 'not-allowed',
|
|
45
|
+
}, children: "Submit Ticket" })] })), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: tickets.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\uD83C\uDFAB" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No tickets yet" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Raise a ticket for major issues" })] })) : tickets.map((t, i) => (_jsxs("div", { style: { padding: '14px 16px', borderBottom: '1px solid #f0f2f5', animation: `cw-fadeUp 0.3s ease both`, animationDelay: `${i * 0.05}s` }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 5 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: 14, color: '#1a2332', flex: 1, paddingRight: 10 }, children: t.title }), _jsx("span", { style: { fontSize: 10, fontWeight: 700, padding: '3px 9px', borderRadius: 20, backgroundColor: sm[t.status].bg, color: sm[t.status].color, whiteSpace: 'nowrap', textTransform: 'uppercase', letterSpacing: '0.04em', flexShrink: 0 }, children: sm[t.status].label })] }), t.description && _jsx("p", { style: { margin: '0 0 7px', fontSize: 13, color: '#7b8fa1', lineHeight: 1.5 }, children: t.description }), _jsxs("div", { style: { display: 'flex', gap: 10, fontSize: 11, color: '#b0bec5' }, children: [_jsxs("span", { style: { color: pm[t.priority].color, fontWeight: 700 }, children: ["\u25CF ", pm[t.priority].label] }), _jsxs("span", { children: ["#", t.id] }), _jsx("span", { children: new Date(t.createdAt).toLocaleDateString([], { month: 'short', day: 'numeric' }) })] })] }, t.id))) })] }));
|
|
71
46
|
};
|
|
47
|
+
function inputStyle(primaryColor) {
|
|
48
|
+
return {
|
|
49
|
+
width: '100%', padding: '9px 13px', borderRadius: 10,
|
|
50
|
+
border: '1.5px solid #e5e7eb', outline: 'none',
|
|
51
|
+
fontSize: 14, color: '#1a2332', boxSizing: 'border-box',
|
|
52
|
+
fontFamily: 'inherit', transition: 'border-color 0.2s',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ChatUser,
|
|
2
|
+
import { ChatUser, UserListContext } from '../../types';
|
|
3
3
|
interface UserListScreenProps {
|
|
4
4
|
context: UserListContext;
|
|
5
5
|
users: ChatUser[];
|
|
6
|
-
|
|
7
|
-
error: string | null;
|
|
8
|
-
theme?: ChatWidgetTheme;
|
|
6
|
+
primaryColor: string;
|
|
9
7
|
onBack: () => void;
|
|
10
8
|
onSelectUser: (user: ChatUser) => void;
|
|
11
9
|
}
|
|
@@ -1,64 +1,35 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
-
import {
|
|
3
|
-
export const UserListScreen = ({ context, users,
|
|
4
|
-
const t = mergeTheme(theme);
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { avatarColor, initials } from '../../utils/chat';
|
|
3
|
+
export const UserListScreen = ({ context, users, primaryColor, onBack, onSelectUser, }) => {
|
|
5
4
|
const title = context === 'support' ? 'Need Support' : 'New Conversation';
|
|
6
|
-
const subtitle = context === 'support'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
5
|
+
const subtitle = context === 'support' ? 'Choose a support agent' : 'Choose a colleague';
|
|
6
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease' }, children: [_jsxs("div", { style: { background: `linear-gradient(135deg,${primaryColor},${primaryColor}cc)`, padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0 }, children: [_jsx(BackBtn, { onClick: onBack }), _jsxs("div", { children: [_jsx("div", { style: { fontWeight: 700, fontSize: 16, color: '#fff' }, children: title }), _jsx("div", { style: { fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: subtitle })] })] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: users.length === 0 ? (_jsx(Empty, {})) : users.map((u, i) => (_jsxs("button", { onClick: () => onSelectUser(u), style: {
|
|
7
|
+
width: '100%', padding: '13px 18px', display: 'flex',
|
|
8
|
+
alignItems: 'center', gap: 13, background: 'transparent',
|
|
9
|
+
border: 'none', borderBottom: '1px solid #f0f2f5',
|
|
10
|
+
cursor: 'pointer', textAlign: 'left',
|
|
11
|
+
animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s`,
|
|
12
|
+
transition: 'background 0.14s',
|
|
13
|
+
}, onMouseEnter: e => e.currentTarget.style.background = '#f8faff', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: { position: 'relative', flexShrink: 0 }, children: [_jsx("div", { style: {
|
|
14
|
+
width: 44, height: 44, borderRadius: '50%',
|
|
15
|
+
backgroundColor: avatarColor(u.name),
|
|
16
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
17
|
+
color: '#fff', fontWeight: 700, fontSize: 14,
|
|
18
|
+
}, children: initials(u.name) }), _jsx("span", { style: {
|
|
19
|
+
position: 'absolute', bottom: 1, right: 1,
|
|
20
|
+
width: 11, height: 11, borderRadius: '50%', border: '2px solid #fff',
|
|
21
|
+
backgroundColor: u.status === 'online' ? '#22c55e' : u.status === 'away' ? '#f59e0b' : '#d1d5db',
|
|
22
|
+
} })] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 14, color: '#1a2332', marginBottom: 2 }, children: u.name }), _jsxs("div", { style: { fontSize: 12, color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [u.designation, " \u00B7 ", u.project] })] }), _jsx("span", { style: {
|
|
23
|
+
fontSize: 10, fontWeight: 700, padding: '3px 9px', borderRadius: 20,
|
|
24
|
+
textTransform: 'uppercase', letterSpacing: '0.05em', flexShrink: 0,
|
|
25
|
+
background: u.type === 'developer' ? `${primaryColor}15` : '#f0fdf4',
|
|
26
|
+
color: u.type === 'developer' ? primaryColor : '#16a34a',
|
|
27
|
+
border: `1px solid ${u.type === 'developer' ? primaryColor + '30' : '#16a34a30'}`,
|
|
28
|
+
}, children: u.type === 'developer' ? 'Dev' : 'User' })] }, u.uid))) })] }));
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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" })] }));
|
|
30
|
+
const BackBtn = ({ onClick }) => (_jsx("button", { onClick: onClick, style: {
|
|
31
|
+
background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
|
|
32
|
+
width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
33
|
+
cursor: 'pointer', flexShrink: 0,
|
|
34
|
+
}, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
35
|
+
const Empty = () => (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\uD83D\uDC65" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No users available" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Check back later" })] }));
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { LocalEnvConfig, RemoteChatData } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Loads remote widget config once via GET. Uses query params `key` and `widget` so the
|
|
4
|
+
* server can validate the request without custom headers (avoids CORS preflight failures).
|
|
5
|
+
*/
|
|
6
|
+
export declare function fetchRemoteChatData(apiKey: string, widgetId: string): Promise<RemoteChatData>;
|
|
7
|
+
export declare function loadLocalConfig(): LocalEnvConfig;
|
package/dist/config/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** Default JSON endpoint; override with REACT_APP_CHAT_CONFIG_URL / NEXT_PUBLIC_CHAT_CONFIG_URL */
|
|
2
|
+
const DEFAULT_CHAT_DATA_BASE = 'https://window.mscorpres.com/TEST/chatData.json';
|
|
3
|
+
const DEMO_API_KEY = 'demo1234';
|
|
4
|
+
const DEMO_WIDGET_ID = 'demo';
|
|
1
5
|
function getEnv(key) {
|
|
2
6
|
var _a, _b, _c;
|
|
3
7
|
if (typeof process !== 'undefined' && process.env) {
|
|
@@ -5,34 +9,33 @@ function getEnv(key) {
|
|
|
5
9
|
}
|
|
6
10
|
return undefined;
|
|
7
11
|
}
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
console.warn(`[ChatWidget] Invalid CHAT_STATUS "${v}". Defaulting to DISABLE.`);
|
|
12
|
-
return 'DISABLE';
|
|
12
|
+
function getChatDataBaseUrl() {
|
|
13
|
+
var _a;
|
|
14
|
+
return ((_a = getEnv('CHAT_CONFIG_URL')) === null || _a === void 0 ? void 0 : _a.trim()) || DEFAULT_CHAT_DATA_BASE;
|
|
13
15
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Loads remote widget config once via GET. Uses query params `key` and `widget` so the
|
|
18
|
+
* server can validate the request without custom headers (avoids CORS preflight failures).
|
|
19
|
+
*/
|
|
20
|
+
export async function fetchRemoteChatData(apiKey, widgetId) {
|
|
21
|
+
const base = getChatDataBaseUrl();
|
|
22
|
+
const url = new URL(base, typeof window !== 'undefined' ? window.location.origin : 'https://localhost');
|
|
23
|
+
url.searchParams.set('key', apiKey);
|
|
24
|
+
url.searchParams.set('widget', widgetId);
|
|
25
|
+
const res = await fetch(url.toString(), {
|
|
26
|
+
method: 'GET',
|
|
27
|
+
credentials: 'omit',
|
|
28
|
+
mode: 'cors',
|
|
29
|
+
headers: { Accept: 'application/json' },
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok)
|
|
32
|
+
throw new Error(`Failed to load chat config: ${res.status}`);
|
|
33
|
+
return res.json();
|
|
19
34
|
}
|
|
20
|
-
export function
|
|
35
|
+
export function loadLocalConfig() {
|
|
21
36
|
var _a, _b;
|
|
22
|
-
const portStr = getEnv('CHAT_HOST_PORT');
|
|
23
|
-
const hostPort = portStr ? parseInt(portStr, 10) : null;
|
|
24
37
|
return {
|
|
25
|
-
|
|
26
|
-
|
|
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')),
|
|
38
|
+
apiKey: (_a = getEnv('CHAT_API_KEY')) !== null && _a !== void 0 ? _a : DEMO_API_KEY,
|
|
39
|
+
widgetId: (_b = getEnv('CHAT_WIDGET_ID')) !== null && _b !== void 0 ? _b : DEMO_WIDGET_ID,
|
|
30
40
|
};
|
|
31
41
|
}
|
|
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
|
-
}
|
package/dist/hooks/useChat.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { ChatMessage, ChatUser } from '../types';
|
|
2
|
-
export declare function useChat(): {
|
|
2
|
+
export declare function useChat(initialMessages?: ChatMessage[]): {
|
|
3
3
|
messages: ChatMessage[];
|
|
4
4
|
activeUser: ChatUser | null;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
isPaused: boolean;
|
|
6
|
+
isReported: boolean;
|
|
7
|
+
selectUser: (user: ChatUser, history?: ChatMessage[]) => void;
|
|
8
|
+
sendMessage: (text: string, type?: ChatMessage["type"], extra?: Partial<ChatMessage>) => void;
|
|
9
|
+
togglePause: () => void;
|
|
10
|
+
reportChat: () => void;
|
|
7
11
|
clearChat: () => void;
|
|
12
|
+
setMessages: import("react").Dispatch<import("react").SetStateAction<ChatMessage[]>>;
|
|
8
13
|
};
|
package/dist/hooks/useChat.js
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
import { useState, useCallback } from 'react';
|
|
2
|
-
export function useChat() {
|
|
3
|
-
const [messages, setMessages] = useState(
|
|
2
|
+
export function useChat(initialMessages = []) {
|
|
3
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
4
4
|
const [activeUser, setActiveUser] = useState(null);
|
|
5
|
-
const
|
|
5
|
+
const [isPaused, setIsPaused] = useState(false);
|
|
6
|
+
const [isReported, setIsReported] = useState(false);
|
|
7
|
+
const selectUser = useCallback((user, history = []) => {
|
|
6
8
|
setActiveUser(user);
|
|
7
|
-
setMessages(
|
|
8
|
-
|
|
9
|
+
setMessages(history);
|
|
10
|
+
setIsPaused(false);
|
|
11
|
+
setIsReported(false);
|
|
12
|
+
// TODO: socket.emit('join', { roomId: user.uid });
|
|
13
|
+
// TODO: socket.on('message', msg => setMessages(prev => [...prev, msg]));
|
|
9
14
|
}, []);
|
|
10
|
-
const sendMessage = useCallback((text) => {
|
|
11
|
-
if (!activeUser ||
|
|
15
|
+
const sendMessage = useCallback((text, type = 'text', extra = {}) => {
|
|
16
|
+
if (!activeUser || isPaused)
|
|
12
17
|
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
|
-
};
|
|
18
|
+
const msg = Object.assign({ id: `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`, senderId: 'me', receiverId: activeUser.uid, text, timestamp: new Date().toISOString(), type, status: 'sent' }, extra);
|
|
21
19
|
setMessages(prev => [...prev, msg]);
|
|
22
|
-
// TODO: socket.emit('message', msg)
|
|
23
|
-
}, [activeUser]);
|
|
20
|
+
// TODO: socket.emit('message', msg);
|
|
21
|
+
}, [activeUser, isPaused]);
|
|
22
|
+
const togglePause = useCallback(() => setIsPaused(p => !p), []);
|
|
23
|
+
const reportChat = useCallback(() => { setIsReported(true); /* TODO: API call */ }, []);
|
|
24
24
|
const clearChat = useCallback(() => { setMessages([]); setActiveUser(null); }, []);
|
|
25
|
-
return {
|
|
25
|
+
return {
|
|
26
|
+
messages, activeUser, isPaused, isReported,
|
|
27
|
+
selectUser, sendMessage, togglePause, reportChat, clearChat,
|
|
28
|
+
setMessages,
|
|
29
|
+
};
|
|
26
30
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { fetchRemoteChatData } from '../config';
|
|
3
|
+
export function useRemoteConfig(apiKey, widgetId) {
|
|
4
|
+
const [data, setData] = useState(null);
|
|
5
|
+
const [loading, setLoading] = useState(true);
|
|
6
|
+
const [error, setError] = useState(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
let cancelled = false;
|
|
9
|
+
setLoading(true);
|
|
10
|
+
fetchRemoteChatData(apiKey, widgetId)
|
|
11
|
+
.then(d => { if (!cancelled) {
|
|
12
|
+
setData(d);
|
|
13
|
+
setError(null);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
} })
|
|
16
|
+
.catch(e => {
|
|
17
|
+
if (!cancelled) {
|
|
18
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
19
|
+
setError(msg || 'Network error while loading configuration');
|
|
20
|
+
setLoading(false);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return () => { cancelled = true; };
|
|
24
|
+
}, [apiKey, widgetId]);
|
|
25
|
+
return { data, loading, error };
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CallSession, ChatUser } from '../types';
|
|
2
|
+
export declare function useWebRTC(): {
|
|
3
|
+
session: CallSession;
|
|
4
|
+
localVideoRef: import("react").MutableRefObject<HTMLVideoElement | null>;
|
|
5
|
+
remoteVideoRef: import("react").MutableRefObject<HTMLVideoElement | null>;
|
|
6
|
+
startCall: (peer: ChatUser, withVideo?: boolean) => Promise<void>;
|
|
7
|
+
acceptCall: (offer: RTCSessionDescriptionInit, peer: ChatUser, withVideo?: boolean) => Promise<void>;
|
|
8
|
+
endCall: () => void;
|
|
9
|
+
toggleMute: () => void;
|
|
10
|
+
toggleCamera: () => void;
|
|
11
|
+
};
|