ajaxter-chat 3.0.4 → 3.0.6
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/dist/components/ChatScreen/index.d.ts +6 -1
- package/dist/components/ChatScreen/index.js +180 -47
- package/dist/components/ChatWidget.js +43 -3
- package/dist/components/HomeScreen/index.d.ts +2 -1
- package/dist/components/HomeScreen/index.js +130 -51
- package/dist/components/SlideNavMenu.d.ts +14 -0
- package/dist/components/SlideNavMenu.js +74 -0
- package/dist/components/UserListScreen/index.d.ts +2 -0
- package/dist/components/UserListScreen/index.js +8 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/index.d.ts +19 -0
- package/package.json +1 -1
- package/public/chatData.json +6 -0
- package/src/components/ChatScreen/index.tsx +378 -171
- package/src/components/ChatWidget.tsx +47 -3
- package/src/components/HomeScreen/index.tsx +244 -80
- package/src/components/SlideNavMenu.tsx +142 -0
- package/src/components/UserListScreen/index.tsx +10 -3
- package/src/index.ts +1 -0
- package/src/types/index.ts +19 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ChatMessage, ChatUser, WidgetConfig } from '../../types';
|
|
2
|
+
import { ChatMessage, ChatUser, WidgetConfig, UserListContext } from '../../types';
|
|
3
3
|
interface ChatScreenProps {
|
|
4
4
|
activeUser: ChatUser;
|
|
5
5
|
messages: ChatMessage[];
|
|
@@ -14,6 +14,11 @@ interface ChatScreenProps {
|
|
|
14
14
|
onReport: () => void;
|
|
15
15
|
onBlock: () => void;
|
|
16
16
|
onStartCall: (withVideo: boolean) => void;
|
|
17
|
+
/** Navigate to support list, colleague list, or tickets (from slide menu) */
|
|
18
|
+
onNavAction: (ctx: UserListContext | 'ticket') => void;
|
|
19
|
+
/** Other devs (excl. viewer) — for transfer when staff chats with a customer */
|
|
20
|
+
otherDevelopers?: ChatUser[];
|
|
21
|
+
onTransferToDeveloper?: (dev: ChatUser) => void;
|
|
17
22
|
}
|
|
18
23
|
export declare const ChatScreen: React.FC<ChatScreenProps>;
|
|
19
24
|
export {};
|
|
@@ -2,10 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
|
3
3
|
import { avatarColor, initials, formatTime, formatDate, generateTranscript, downloadText } from '../../utils/chat';
|
|
4
4
|
import { EmojiPicker } from '../EmojiPicker';
|
|
5
|
-
|
|
5
|
+
import { SlideNavMenu } from '../SlideNavMenu';
|
|
6
|
+
export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported, isBlocked, onSend, onBack, onClose, onTogglePause, onReport, onBlock, onStartCall, onNavAction, otherDevelopers = [], onTransferToDeveloper, }) => {
|
|
7
|
+
var _a;
|
|
6
8
|
const [text, setText] = useState('');
|
|
7
9
|
const [showEmoji, setShowEmoji] = useState(false);
|
|
8
10
|
const [showMenu, setShowMenu] = useState(false);
|
|
11
|
+
const [slideMenuOpen, setSlideMenuOpen] = useState(false);
|
|
12
|
+
const [transferOpen, setTransferOpen] = useState(false);
|
|
9
13
|
const [isRecording, setIsRecording] = useState(false);
|
|
10
14
|
const [recordSec, setRecordSec] = useState(0);
|
|
11
15
|
const [showConfirm, setShowConfirm] = useState(null);
|
|
@@ -14,6 +18,7 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
14
18
|
const fileRef = useRef(null);
|
|
15
19
|
const recordTimer = useRef(null);
|
|
16
20
|
const mediaRecorder = useRef(null);
|
|
21
|
+
const recordChunks = useRef([]);
|
|
17
22
|
useEffect(() => { var _a; (_a = endRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
|
|
18
23
|
const handleSend = useCallback(() => {
|
|
19
24
|
var _a;
|
|
@@ -29,22 +34,29 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
29
34
|
handleSend();
|
|
30
35
|
}
|
|
31
36
|
};
|
|
32
|
-
// Voice recording
|
|
33
37
|
const startRecording = async () => {
|
|
34
38
|
if (isPaused || isBlocked)
|
|
35
39
|
return;
|
|
36
40
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
41
|
+
recordChunks.current = [];
|
|
37
42
|
const mr = new MediaRecorder(stream);
|
|
38
43
|
mediaRecorder.current = mr;
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
mr.ondataavailable = e => { if (e.data.size)
|
|
45
|
+
recordChunks.current.push(e.data); };
|
|
41
46
|
mr.onstop = () => {
|
|
42
47
|
stream.getTracks().forEach(t => t.stop());
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
const chunks = recordChunks.current;
|
|
49
|
+
if (!chunks.length) {
|
|
50
|
+
setRecordSec(0);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const blob = new Blob(chunks, { type: chunks[0] instanceof Blob ? chunks[0].type : 'audio/webm' });
|
|
54
|
+
const voiceUrl = URL.createObjectURL(blob);
|
|
55
|
+
const dur = Math.max(1, recordSec);
|
|
56
|
+
onSend('Voice message', 'voice', { voiceDuration: dur, voiceUrl });
|
|
45
57
|
setRecordSec(0);
|
|
46
58
|
};
|
|
47
|
-
mr.start();
|
|
59
|
+
mr.start(200);
|
|
48
60
|
setIsRecording(true);
|
|
49
61
|
recordTimer.current = setInterval(() => setRecordSec(s => s + 1), 1000);
|
|
50
62
|
};
|
|
@@ -55,25 +67,24 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
55
67
|
clearInterval(recordTimer.current);
|
|
56
68
|
setIsRecording(false);
|
|
57
69
|
};
|
|
58
|
-
// Attachment
|
|
59
70
|
const handleFileChange = (e) => {
|
|
60
71
|
var _a;
|
|
61
72
|
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
62
73
|
if (!file || isPaused || isBlocked)
|
|
63
74
|
return;
|
|
64
|
-
|
|
75
|
+
const attachmentUrl = URL.createObjectURL(file);
|
|
76
|
+
onSend(file.name, 'attachment', {
|
|
65
77
|
attachmentName: file.name,
|
|
66
78
|
attachmentSize: `${(file.size / 1024).toFixed(1)} KB`,
|
|
79
|
+
attachmentUrl,
|
|
67
80
|
});
|
|
68
81
|
e.target.value = '';
|
|
69
82
|
};
|
|
70
|
-
// Download transcript
|
|
71
83
|
const handleTranscript = () => {
|
|
72
84
|
const content = generateTranscript(messages, activeUser);
|
|
73
85
|
downloadText(content, `chat-${activeUser.name.replace(/\s+/g, '_')}-${Date.now()}.txt`);
|
|
74
86
|
setShowMenu(false);
|
|
75
87
|
};
|
|
76
|
-
// Confirm actions
|
|
77
88
|
const handleConfirm = (action) => {
|
|
78
89
|
setShowConfirm(null);
|
|
79
90
|
setShowMenu(false);
|
|
@@ -86,50 +97,168 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
86
97
|
};
|
|
87
98
|
const peerAvatar = avatarColor(activeUser.name);
|
|
88
99
|
const peerInit = initials(activeUser.name);
|
|
89
|
-
// Group messages by date
|
|
90
100
|
const grouped = groupByDate(messages);
|
|
91
|
-
|
|
101
|
+
const viewerIsDev = config.viewerType === 'developer';
|
|
102
|
+
const headerRole = viewerIsDev
|
|
103
|
+
? (activeUser.type === 'user' ? 'Customer' : 'Developer')
|
|
104
|
+
: 'Support';
|
|
105
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease', position: 'relative', overflow: 'hidden' }, children: [_jsx(SlideNavMenu, { open: slideMenuOpen, onClose: () => setSlideMenuOpen(false), primaryColor: config.primaryColor, chatType: config.chatType, viewerType: (_a = config.viewerType) !== null && _a !== void 0 ? _a : 'user', onSelect: onNavAction, onBackHome: onBack }), _jsxs("div", { style: {
|
|
92
106
|
background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
|
|
93
|
-
padding: '12px
|
|
94
|
-
}, children: [_jsx("button", { onClick:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0,
|
|
108
|
+
}, children: [_jsx("button", { type: "button", onClick: () => setSlideMenuOpen(true), style: hdrBtn, "aria-label": "Open menu", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [_jsx("line", { x1: "3", y1: "6", x2: "21", y2: "6", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" }), _jsx("line", { x1: "3", y1: "12", x2: "21", y2: "12", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" }), _jsx("line", { x1: "3", y1: "18", x2: "21", y2: "18", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round" })] }) }), _jsxs("div", { style: { width: 36, height: 36, borderRadius: '50%', backgroundColor: peerAvatar, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontWeight: 700, fontSize: 13, flexShrink: 0, position: 'relative' }, children: [peerInit, _jsx("span", { style: { position: 'absolute', bottom: 0, right: 0, width: 9, height: 9, borderRadius: '50%', border: '2px solid', borderColor: 'transparent', backgroundColor: activeUser.status === 'online' ? '#22c55e' : activeUser.status === 'away' ? '#f59e0b' : '#9ca3af' } })] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 14, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: activeUser.name }), _jsx("div", { style: { fontSize: 11, color: 'rgba(255,255,255,0.8)' }, children: activeUser.designation })] }), _jsx("span", { style: { fontSize: 13, fontWeight: 700, color: '#fff', opacity: 0.95, flexShrink: 0 }, children: headerRole }), config.allowWebCall && (_jsx("button", { type: "button", onClick: () => onStartCall(false), style: hdrBtn, title: "Voice Call", children: _jsx("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07A19.5 19.5 0 013.07 10.8a19.79 19.79 0 01-3.07-8.68A2 2 0 012 0h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L6.09 7.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 14.92v2z", fill: "#fff" }) }) })), _jsx("button", { type: "button", onClick: () => setShowMenu(v => !v), style: Object.assign(Object.assign({}, hdrBtn), { background: 'rgba(255,255,255,0.2)' }), title: "More options", "aria-expanded": showMenu, children: _jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "5", r: "1.5", fill: "#fff" }), _jsx("circle", { cx: "12", cy: "12", r: "1.5", fill: "#fff" }), _jsx("circle", { cx: "12", cy: "19", r: "1.5", fill: "#fff" })] }) })] }), showMenu && (_jsxs("div", { style: { position: 'absolute', top: 52, right: 12, zIndex: 120, background: '#fff', borderRadius: 12, boxShadow: '0 8px 30px rgba(0,0,0,0.16)', padding: '6px', minWidth: 200, animation: 'cw-fadeUp 0.18s ease' }, children: [config.allowTranscriptDownload && (_jsx(MenuItem, { icon: "\uD83D\uDCE5", label: "Download Transcript", onClick: handleTranscript })), viewerIsDev && activeUser.type === 'user' && otherDevelopers.length > 0 && onTransferToDeveloper && (_jsx(MenuItem, { icon: "\uD83D\uDD00", label: "Transfer to developer", onClick: () => { setShowMenu(false); setTransferOpen(true); } })), _jsx(MenuItem, { icon: isPaused ? '▶️' : '⏸', label: isPaused ? 'Resume Chat' : 'Pause Chat', onClick: () => { setShowMenu(false); setShowConfirm('pause'); } }), config.allowReport && !isReported && (_jsx(MenuItem, { icon: "\u26A0\uFE0F", label: "Report Chat", onClick: () => { setShowMenu(false); setShowConfirm('report'); } })), config.allowBlock && activeUser.type === 'user' && !isBlocked && (_jsx(MenuItem, { icon: "\uD83D\uDEAB", label: "Block User", onClick: () => { setShowMenu(false); setShowConfirm('block'); }, danger: true })), _jsx("div", { style: { borderTop: '1px solid #f0f2f5', margin: '4px 0' } }), _jsx(MenuItem, { icon: "\u2715", label: "Close Chat", onClick: onClose })] })), isPaused && (_jsxs("div", { style: { background: '#fef3c7', padding: '8px 16px', fontSize: 12, fontWeight: 600, color: '#92400e', textAlign: 'center', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }, children: ["\u23F8 Chat is paused \u2014 users cannot send messages", _jsx("button", { type: "button", onClick: onTogglePause, style: { background: '#92400e', color: '#fff', border: 'none', borderRadius: 6, padding: '2px 8px', fontSize: 11, cursor: 'pointer', marginLeft: 4 }, children: "Resume" })] })), isBlocked && (_jsx("div", { style: { background: '#fee2e2', padding: '8px 16px', fontSize: 12, fontWeight: 600, color: '#991b1b', textAlign: 'center', flexShrink: 0 }, children: "\uD83D\uDEAB This user is blocked" })), isReported && (_jsx("div", { style: { background: '#fef3c7', padding: '6px 16px', fontSize: 11, color: '#92400e', textAlign: 'center', flexShrink: 0 }, children: "\u26A0\uFE0F This chat has been reported" })), _jsxs("div", { style: { flex: 1, overflowY: 'auto', padding: '14px', display: 'flex', flexDirection: 'column', gap: 10, background: '#f8f9fc' }, className: "cw-scroll", children: [grouped.map(({ date, msgs }) => (_jsxs(React.Fragment, { children: [_jsx(DateDivider, { label: date }), msgs.map(msg => (_jsx(Bubble, { msg: msg, primaryColor: config.primaryColor }, msg.id)))] }, date))), messages.length === 0 && (_jsxs("div", { style: { margin: 'auto', textAlign: 'center', color: '#c4cad4', fontSize: 13 }, children: [_jsx("div", { style: { fontSize: 28, marginBottom: 8 }, children: "\uD83D\uDCAC" }), "Say hello to ", activeUser.name, "!"] })), _jsx("div", { ref: endRef })] }), _jsxs("div", { style: { borderTop: '1px solid #eef0f5', padding: '10px 12px 8px', background: '#fff', flexShrink: 0, position: 'relative' }, children: [showEmoji && config.allowEmoji && (_jsx(EmojiPicker, { primaryColor: config.primaryColor, onSelect: e => setText(t => t + e), onClose: () => setShowEmoji(false) })), isRecording && (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, padding: '8px 12px', background: '#fee2e2', borderRadius: 10 }, children: [_jsx("span", { style: { width: 8, height: 8, borderRadius: '50%', background: '#ef4444', display: 'inline-block', animation: 'cw-pulse 1s infinite' } }), _jsxs("span", { style: { fontSize: 13, color: '#991b1b', fontWeight: 600 }, children: ["Recording ", recordSec, "s"] }), _jsx("button", { type: "button", onClick: stopRecording, style: { marginLeft: 'auto', background: '#ef4444', color: '#fff', border: 'none', borderRadius: 6, padding: '4px 12px', fontSize: 12, cursor: 'pointer', fontWeight: 600 }, children: "Stop & send" })] })), _jsxs("div", { style: {
|
|
109
|
+
border: `1.5px solid ${isPaused || isBlocked ? '#e5e7eb' : '#bfdbfe'}`,
|
|
110
|
+
borderRadius: 16,
|
|
111
|
+
padding: '10px 12px 8px',
|
|
112
|
+
background: isPaused || isBlocked ? '#f9fafb' : '#fff',
|
|
113
|
+
}, children: [_jsx("textarea", { ref: inputRef, value: text, onChange: e => setText(e.target.value), onKeyDown: handleKey, placeholder: isPaused || isBlocked ? 'Chat is unavailable' : 'Compose your message…', disabled: isPaused || isBlocked || isRecording, rows: 2, style: {
|
|
114
|
+
width: '100%',
|
|
115
|
+
resize: 'none',
|
|
116
|
+
border: 'none',
|
|
117
|
+
outline: 'none',
|
|
118
|
+
fontSize: 14,
|
|
119
|
+
lineHeight: 1.45,
|
|
120
|
+
color: '#1a2332',
|
|
121
|
+
background: 'transparent',
|
|
122
|
+
maxHeight: 88,
|
|
123
|
+
overflowY: 'auto',
|
|
105
124
|
fontFamily: 'inherit',
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
marginBottom: 8,
|
|
126
|
+
} }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 2 }, children: [config.allowEmoji && (_jsx(ActionBtn, { onClick: () => setShowEmoji(v => !v), title: "Emoji", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "#94a3b8", strokeWidth: "1.8" }), _jsx("path", { d: "M8 14s1.5 2 4 2 4-2 4-2", stroke: "#94a3b8", strokeWidth: "1.8", strokeLinecap: "round" }), _jsx("circle", { cx: "9", cy: "9", r: "1", fill: "#94a3b8" }), _jsx("circle", { cx: "15", cy: "9", r: "1", fill: "#94a3b8" })] }) })), config.allowAttachment && (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileRef, type: "file", style: { display: 'none' }, onChange: handleFileChange }), _jsx(ActionBtn, { onClick: () => { var _a; return (_a = fileRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, title: "Attach file", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66L9.41 17.41a2 2 0 01-2.83-2.83l8.49-8.48", stroke: "#94a3b8", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })), config.allowVoiceMessage && !isRecording && (_jsx(ActionBtn, { onClick: startRecording, title: "Voice message", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z", stroke: "#94a3b8", strokeWidth: "1.8", strokeLinecap: "round" }), _jsx("path", { d: "M19 10v2a7 7 0 01-14 0v-2M12 19v4M8 23h8", stroke: "#94a3b8", strokeWidth: "1.8", strokeLinecap: "round" })] }) }))] }), _jsx("button", { type: "button", onClick: handleSend, disabled: !text.trim() || isPaused || isBlocked || isRecording, style: {
|
|
127
|
+
width: 36,
|
|
128
|
+
height: 36,
|
|
129
|
+
borderRadius: '50%',
|
|
130
|
+
backgroundColor: text.trim() && !isPaused && !isBlocked ? config.primaryColor : '#e2e8f0',
|
|
131
|
+
border: 'none',
|
|
132
|
+
cursor: text.trim() && !isPaused && !isBlocked ? 'pointer' : 'default',
|
|
133
|
+
display: 'flex',
|
|
134
|
+
alignItems: 'center',
|
|
135
|
+
justifyContent: 'center',
|
|
136
|
+
flexShrink: 0,
|
|
137
|
+
transition: 'background 0.15s',
|
|
138
|
+
}, title: "Send", children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: text.trim() && !isPaused && !isBlocked ? '#fff' : '#94a3b8', strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), (config.footerPoweredBy || config.branch) && (_jsxs("p", { style: { margin: '10px 0 0', textAlign: 'center', fontSize: 12, color: '#94a3b8' }, children: [config.footerPoweredBy, config.footerPoweredBy && config.branch ? ' · ' : '', config.branch && _jsx("span", { style: { fontWeight: 600, color: '#64748b' }, children: config.branch })] }))] }), transferOpen && otherDevelopers.length > 0 && onTransferToDeveloper && (_jsx("div", { style: {
|
|
139
|
+
position: 'absolute',
|
|
140
|
+
inset: 0,
|
|
141
|
+
background: 'rgba(0,0,0,0.45)',
|
|
142
|
+
display: 'flex',
|
|
143
|
+
alignItems: 'center',
|
|
144
|
+
justifyContent: 'center',
|
|
145
|
+
zIndex: 280,
|
|
146
|
+
padding: 16,
|
|
147
|
+
}, children: _jsxs("div", { style: {
|
|
148
|
+
background: '#fff',
|
|
149
|
+
borderRadius: 16,
|
|
150
|
+
padding: '18px 16px',
|
|
151
|
+
width: '100%',
|
|
152
|
+
maxWidth: 320,
|
|
153
|
+
maxHeight: '70%',
|
|
154
|
+
overflow: 'hidden',
|
|
155
|
+
display: 'flex',
|
|
156
|
+
flexDirection: 'column',
|
|
157
|
+
boxShadow: '0 16px 48px rgba(0,0,0,0.22)',
|
|
158
|
+
}, children: [_jsx("div", { style: { fontWeight: 800, fontSize: 16, color: '#1a2332', marginBottom: 6 }, children: "Transfer chat to" }), _jsx("p", { style: { fontSize: 12, color: '#7b8fa1', margin: '0 0 12px', lineHeight: 1.5 }, children: "Assign this conversation to another developer. History is kept and a handoff note is added." }), _jsx("div", { className: "cw-scroll", style: { flex: 1, overflowY: 'auto', margin: '0 -4px' }, children: otherDevelopers.map(dev => (_jsxs("button", { type: "button", onClick: () => {
|
|
159
|
+
onTransferToDeveloper(dev);
|
|
160
|
+
setTransferOpen(false);
|
|
161
|
+
}, style: {
|
|
162
|
+
width: '100%',
|
|
163
|
+
textAlign: 'left',
|
|
164
|
+
padding: '12px 12px',
|
|
165
|
+
marginBottom: 6,
|
|
166
|
+
border: '1px solid #eef0f5',
|
|
167
|
+
borderRadius: 12,
|
|
168
|
+
background: '#f8fafc',
|
|
169
|
+
cursor: 'pointer',
|
|
170
|
+
fontSize: 14,
|
|
171
|
+
fontWeight: 600,
|
|
172
|
+
color: '#1e293b',
|
|
173
|
+
}, children: [dev.name, _jsx("span", { style: { display: 'block', fontSize: 11, fontWeight: 500, color: '#64748b', marginTop: 2 }, children: dev.designation })] }, dev.uid))) }), _jsx("button", { type: "button", onClick: () => setTransferOpen(false), style: {
|
|
174
|
+
marginTop: 12,
|
|
175
|
+
padding: '10px',
|
|
176
|
+
borderRadius: 10,
|
|
177
|
+
border: '1.5px solid #e5e7eb',
|
|
178
|
+
background: '#fff',
|
|
179
|
+
fontWeight: 600,
|
|
180
|
+
fontSize: 13,
|
|
181
|
+
color: '#475569',
|
|
182
|
+
cursor: 'pointer',
|
|
183
|
+
}, children: "Cancel" })] }) })), showConfirm && (_jsx("div", { style: {
|
|
117
184
|
position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.45)',
|
|
118
185
|
display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 300,
|
|
119
186
|
borderRadius: 'inherit',
|
|
120
|
-
}, children: _jsxs("div", { style: { background: '#fff', borderRadius: 16, padding: '24px 20px', width: 280, boxShadow: '0 16px 48px rgba(0,0,0,0.22)', animation: 'cw-fadeUp 0.2s ease' }, children: [_jsxs("div", { style: { fontWeight: 800, fontSize: 16, color: '#1a2332', marginBottom: 8 }, children: [showConfirm === 'pause' && (isPaused ? 'Resume Chat?' : 'Pause Chat?'), showConfirm === 'report' && 'Report this chat?', showConfirm === 'block' && 'Block this user?'] }), _jsxs("p", { style: { fontSize: 13, color: '#7b8fa1', lineHeight: 1.6, margin: '0 0 18px' }, children: [showConfirm === 'pause' && (isPaused ? 'The user will be able to send messages again.' : 'The user will not be able to send new messages.'), showConfirm === 'report' && 'This chat will be flagged for review by the admin team.', showConfirm === 'block' && 'This user will be blocked and added to your block list. You can unblock them later.'] }), _jsxs("div", { style: { display: 'flex', gap: 10 }, children: [_jsx("button", { onClick: () => setShowConfirm(null), style: { flex: 1, padding: '9px', borderRadius: 10, border: '1.5px solid #e5e7eb', background: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 600, color: '#374151' }, children: "Cancel" }), _jsx("button", { onClick: () => handleConfirm(showConfirm), style: {
|
|
187
|
+
}, children: _jsxs("div", { style: { background: '#fff', borderRadius: 16, padding: '24px 20px', width: 280, boxShadow: '0 16px 48px rgba(0,0,0,0.22)', animation: 'cw-fadeUp 0.2s ease' }, children: [_jsxs("div", { style: { fontWeight: 800, fontSize: 16, color: '#1a2332', marginBottom: 8 }, children: [showConfirm === 'pause' && (isPaused ? 'Resume Chat?' : 'Pause Chat?'), showConfirm === 'report' && 'Report this chat?', showConfirm === 'block' && 'Block this user?'] }), _jsxs("p", { style: { fontSize: 13, color: '#7b8fa1', lineHeight: 1.6, margin: '0 0 18px' }, children: [showConfirm === 'pause' && (isPaused ? 'The user will be able to send messages again.' : 'The user will not be able to send new messages.'), showConfirm === 'report' && 'This chat will be flagged for review by the admin team.', showConfirm === 'block' && 'This user will be blocked and added to your block list. You can unblock them later.'] }), _jsxs("div", { style: { display: 'flex', gap: 10 }, children: [_jsx("button", { type: "button", onClick: () => setShowConfirm(null), style: { flex: 1, padding: '9px', borderRadius: 10, border: '1.5px solid #e5e7eb', background: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 600, color: '#374151' }, children: "Cancel" }), _jsx("button", { type: "button", onClick: () => handleConfirm(showConfirm), style: {
|
|
121
188
|
flex: 1, padding: '9px', borderRadius: 10, border: 'none',
|
|
122
189
|
background: showConfirm === 'block' ? '#ef4444' : config.primaryColor,
|
|
123
190
|
color: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 700,
|
|
124
191
|
}, children: "Confirm" })] })] }) }))] }));
|
|
125
192
|
};
|
|
126
|
-
|
|
127
|
-
const Bubble = ({ msg, peer, primaryColor }) => {
|
|
193
|
+
const VoiceRow = ({ msg, isMe, primaryColor }) => {
|
|
128
194
|
var _a;
|
|
195
|
+
const audioRef = useRef(null);
|
|
196
|
+
const [playing, setPlaying] = useState(false);
|
|
197
|
+
const [current, setCurrent] = useState(0);
|
|
198
|
+
const [dur, setDur] = useState((_a = msg.voiceDuration) !== null && _a !== void 0 ? _a : 0);
|
|
199
|
+
const url = msg.voiceUrl;
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
const a = audioRef.current;
|
|
202
|
+
if (!a || !url)
|
|
203
|
+
return;
|
|
204
|
+
const onMeta = () => setDur(a.duration || msg.voiceDuration || 0);
|
|
205
|
+
const onTime = () => setCurrent(a.currentTime);
|
|
206
|
+
a.addEventListener('loadedmetadata', onMeta);
|
|
207
|
+
a.addEventListener('timeupdate', onTime);
|
|
208
|
+
return () => {
|
|
209
|
+
a.removeEventListener('loadedmetadata', onMeta);
|
|
210
|
+
a.removeEventListener('timeupdate', onTime);
|
|
211
|
+
};
|
|
212
|
+
}, [url, msg.voiceDuration]);
|
|
213
|
+
const toggle = () => {
|
|
214
|
+
const a = audioRef.current;
|
|
215
|
+
if (!a)
|
|
216
|
+
return;
|
|
217
|
+
if (playing) {
|
|
218
|
+
a.pause();
|
|
219
|
+
setPlaying(false);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
void a.play().then(() => setPlaying(true)).catch(() => { });
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const pct = dur > 0 ? Math.min(100, (current / dur) * 100) : 0;
|
|
226
|
+
const timeLabel = fmtTime(Math.floor(current)) + ' / ' + fmtTime(Math.floor(dur || msg.voiceDuration || 0));
|
|
227
|
+
if (!url) {
|
|
228
|
+
return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { fontSize: 13 }, children: "\uD83C\uDFA4" }), _jsxs("span", { style: { fontSize: 13 }, children: ["Voice message", msg.voiceDuration ? ` · ${msg.voiceDuration}s` : ''] })] }));
|
|
229
|
+
}
|
|
230
|
+
return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10, minWidth: 200 }, children: [url && (_jsx("audio", { ref: audioRef, src: url, preload: "metadata", onPlay: () => setPlaying(true), onPause: () => setPlaying(false), onEnded: () => { setPlaying(false); setCurrent(0); } })), _jsx("button", { type: "button", onClick: toggle, style: {
|
|
231
|
+
width: 36,
|
|
232
|
+
height: 36,
|
|
233
|
+
borderRadius: '50%',
|
|
234
|
+
border: 'none',
|
|
235
|
+
background: isMe ? 'rgba(255,255,255,0.95)' : '#fff',
|
|
236
|
+
color: isMe ? primaryColor : primaryColor,
|
|
237
|
+
cursor: 'pointer',
|
|
238
|
+
display: 'flex',
|
|
239
|
+
alignItems: 'center',
|
|
240
|
+
justifyContent: 'center',
|
|
241
|
+
flexShrink: 0,
|
|
242
|
+
boxShadow: '0 1px 4px rgba(0,0,0,0.12)',
|
|
243
|
+
}, "aria-label": playing ? 'Pause' : 'Play', children: playing ? (_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: [_jsx("rect", { x: "6", y: "4", width: "4", height: "16" }), _jsx("rect", { x: "14", y: "4", width: "4", height: "16" })] })) : (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M8 5v14l11-7z" }) })) }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { height: 4, borderRadius: 2, background: isMe ? 'rgba(255,255,255,0.35)' : '#e2e8f0', overflow: 'hidden' }, children: _jsx("div", { style: { width: `${pct}%`, height: '100%', background: isMe ? '#fff' : primaryColor, borderRadius: 2, transition: 'width 0.1s linear' } }) }), _jsx("div", { style: { fontSize: 11, marginTop: 4, opacity: 0.9 }, children: timeLabel })] })] }));
|
|
244
|
+
};
|
|
245
|
+
const AttachmentRow = ({ msg, isMe, primaryColor }) => {
|
|
246
|
+
var _a;
|
|
247
|
+
const name = (_a = msg.attachmentName) !== null && _a !== void 0 ? _a : 'File';
|
|
248
|
+
const href = msg.attachmentUrl;
|
|
249
|
+
return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }, children: [_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: _jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66L9.41 17.41a2 2 0 01-2.83-2.83l8.49-8.48", stroke: isMe ? '#fff' : '#334155', strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 14, wordBreak: 'break-word' }, children: name }), msg.attachmentSize && _jsx("div", { style: { fontSize: 11, opacity: 0.8 }, children: msg.attachmentSize })] }), href && (_jsx("a", { href: href, download: name, style: {
|
|
250
|
+
fontSize: 12,
|
|
251
|
+
fontWeight: 700,
|
|
252
|
+
color: isMe ? '#fff' : primaryColor,
|
|
253
|
+
textDecoration: 'underline',
|
|
254
|
+
whiteSpace: 'nowrap',
|
|
255
|
+
}, children: "Download" }))] }));
|
|
256
|
+
};
|
|
257
|
+
const Bubble = ({ msg, primaryColor }) => {
|
|
129
258
|
const isMe = msg.senderId === 'me';
|
|
130
|
-
const content = msg.type === 'voice' ? (
|
|
259
|
+
const content = msg.type === 'voice' ? (_jsx(VoiceRow, { msg: msg, isMe: isMe, primaryColor: primaryColor })) : msg.type === 'attachment' ? (_jsx(AttachmentRow, { msg: msg, isMe: isMe, primaryColor: primaryColor })) : (_jsx("span", { children: msg.text }));
|
|
131
260
|
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: isMe ? 'flex-end' : 'flex-start', gap: 3 }, children: [_jsx("div", { style: {
|
|
132
|
-
maxWidth: '
|
|
261
|
+
maxWidth: '85%', padding: '10px 13px',
|
|
133
262
|
borderRadius: isMe ? '18px 18px 4px 18px' : '18px 18px 18px 4px',
|
|
134
263
|
backgroundColor: isMe ? primaryColor : '#fff',
|
|
135
264
|
color: isMe ? '#fff' : '#1a2332',
|
|
@@ -138,24 +267,23 @@ const Bubble = ({ msg, peer, primaryColor }) => {
|
|
|
138
267
|
wordBreak: 'break-word',
|
|
139
268
|
}, children: content }), _jsx("span", { style: { fontSize: 11, color: '#b0bec5', padding: '0 4px' }, children: formatTime(msg.timestamp) })] }));
|
|
140
269
|
};
|
|
141
|
-
const DateDivider = ({ label }) => (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10, margin: '4px 0' }, children: [_jsx("div", { style: { flex: 1, height: 1, background: '#e5e7eb' } }), _jsx("span", { style: { fontSize: 11, fontWeight: 600, color: '#
|
|
142
|
-
const MenuItem = ({ icon, label, onClick, danger }) => (_jsxs("button", { onClick: onClick, style: {
|
|
270
|
+
const DateDivider = ({ label }) => (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10, margin: '4px 0' }, children: [_jsx("div", { style: { flex: 1, height: 1, background: '#e5e7eb' } }), _jsx("span", { style: { fontSize: 11, fontWeight: 600, color: '#64748b', whiteSpace: 'nowrap' }, children: label }), _jsx("div", { style: { flex: 1, height: 1, background: '#e5e7eb' } })] }));
|
|
271
|
+
const MenuItem = ({ icon, label, onClick, danger }) => (_jsxs("button", { type: "button", onClick: onClick, style: {
|
|
143
272
|
display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 12px',
|
|
144
273
|
background: 'none', border: 'none', borderRadius: 8, cursor: 'pointer', textAlign: 'left',
|
|
145
274
|
fontSize: 13, fontWeight: 600, color: danger ? '#ef4444' : '#374151',
|
|
146
275
|
transition: 'background 0.12s',
|
|
147
276
|
}, onMouseEnter: e => e.currentTarget.style.background = danger ? '#fee2e2' : '#f3f4f6', onMouseLeave: e => e.currentTarget.style.background = 'none', children: [_jsx("span", { children: icon }), " ", label] }));
|
|
148
|
-
const ActionBtn = ({ onClick, title, children }) => (_jsx("button", { onClick: onClick, title: title, style: {
|
|
149
|
-
background: 'none', border: 'none', cursor: 'pointer', padding: '
|
|
277
|
+
const ActionBtn = ({ onClick, title, children }) => (_jsx("button", { type: "button", onClick: onClick, title: title, style: {
|
|
278
|
+
background: 'none', border: 'none', cursor: 'pointer', padding: '8px',
|
|
150
279
|
borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
|
|
151
280
|
transition: 'background 0.13s',
|
|
152
|
-
}, onMouseEnter: e => e.currentTarget.style.background = '#
|
|
281
|
+
}, onMouseEnter: e => e.currentTarget.style.background = '#f1f5f9', onMouseLeave: e => e.currentTarget.style.background = 'none', children: children }));
|
|
153
282
|
const hdrBtn = {
|
|
154
283
|
background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '50%',
|
|
155
284
|
width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
156
285
|
cursor: 'pointer', flexShrink: 0,
|
|
157
286
|
};
|
|
158
|
-
// Group messages by date
|
|
159
287
|
function groupByDate(messages) {
|
|
160
288
|
const map = new Map();
|
|
161
289
|
messages.forEach(m => {
|
|
@@ -166,3 +294,8 @@ function groupByDate(messages) {
|
|
|
166
294
|
});
|
|
167
295
|
return Array.from(map.entries()).map(([date, msgs]) => ({ date, msgs }));
|
|
168
296
|
}
|
|
297
|
+
function fmtTime(sec) {
|
|
298
|
+
const m = Math.floor(sec / 60);
|
|
299
|
+
const s = Math.max(0, sec % 60);
|
|
300
|
+
return `${m}:${String(s).padStart(2, '0')}`;
|
|
301
|
+
}
|
|
@@ -19,7 +19,7 @@ import { BottomTabs } from './Tabs/BottomTabs';
|
|
|
19
19
|
const DRAWER_W_NORMAL = 380;
|
|
20
20
|
const DRAWER_W_MAX = 480;
|
|
21
21
|
export const ChatWidget = ({ theme: localTheme }) => {
|
|
22
|
-
var _a, _b;
|
|
22
|
+
var _a, _b, _c, _d;
|
|
23
23
|
/* SSR guard */
|
|
24
24
|
const [mounted, setMounted] = useState(false);
|
|
25
25
|
useEffect(() => { setMounted(true); }, []);
|
|
@@ -96,6 +96,17 @@ export const ChatWidget = ({ theme: localTheme }) => {
|
|
|
96
96
|
setScreen('user-list');
|
|
97
97
|
}
|
|
98
98
|
}, []);
|
|
99
|
+
const handleNavFromMenu = useCallback((ctx) => {
|
|
100
|
+
clearChat();
|
|
101
|
+
if (ctx === 'ticket') {
|
|
102
|
+
setActiveTab('tickets');
|
|
103
|
+
setScreen('tickets');
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
setUserListCtx(ctx);
|
|
107
|
+
setScreen('user-list');
|
|
108
|
+
}
|
|
109
|
+
}, [clearChat]);
|
|
99
110
|
const handleSelectUser = useCallback((user) => {
|
|
100
111
|
var _a;
|
|
101
112
|
// Load history from sample chats if available
|
|
@@ -161,10 +172,39 @@ export const ChatWidget = ({ theme: localTheme }) => {
|
|
|
161
172
|
const widgetConfig = data === null || data === void 0 ? void 0 : data.widget;
|
|
162
173
|
const primaryColor = theme.primaryColor;
|
|
163
174
|
const allUsers = data ? [...data.developers, ...data.users] : [];
|
|
175
|
+
const viewerIsDev = (widgetConfig === null || widgetConfig === void 0 ? void 0 : widgetConfig.viewerType) === 'developer';
|
|
176
|
+
const viewerUid = widgetConfig === null || widgetConfig === void 0 ? void 0 : widgetConfig.viewerUid;
|
|
164
177
|
const filteredUsers = screen === 'user-list'
|
|
165
|
-
? allUsers.filter(u =>
|
|
178
|
+
? allUsers.filter(u => {
|
|
179
|
+
if (userListCtx === 'support') {
|
|
180
|
+
if (viewerIsDev)
|
|
181
|
+
return u.type === 'user';
|
|
182
|
+
return u.type === 'developer';
|
|
183
|
+
}
|
|
184
|
+
if (viewerIsDev) {
|
|
185
|
+
return u.type === 'developer' && u.uid !== viewerUid;
|
|
186
|
+
}
|
|
187
|
+
return u.type === 'user';
|
|
188
|
+
})
|
|
166
189
|
: [];
|
|
190
|
+
const otherDevelopers = (_c = data === null || data === void 0 ? void 0 : data.developers.filter(d => d.uid !== viewerUid)) !== null && _c !== void 0 ? _c : [];
|
|
167
191
|
const blockedUsers = allUsers.filter(u => blockedUids.includes(u.uid));
|
|
192
|
+
const handleTransferToDeveloper = useCallback((dev) => {
|
|
193
|
+
var _a;
|
|
194
|
+
if (!activeUser || !widgetConfig)
|
|
195
|
+
return;
|
|
196
|
+
const agent = ((_a = widgetConfig.viewerName) === null || _a === void 0 ? void 0 : _a.trim()) || 'Agent';
|
|
197
|
+
const transferNote = {
|
|
198
|
+
id: `tr_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
199
|
+
senderId: 'me',
|
|
200
|
+
receiverId: dev.uid,
|
|
201
|
+
text: `— ${agent} transferred this conversation from ${activeUser.name} to ${dev.name} —`,
|
|
202
|
+
timestamp: new Date().toISOString(),
|
|
203
|
+
type: 'text',
|
|
204
|
+
status: 'sent',
|
|
205
|
+
};
|
|
206
|
+
selectUser(dev, [...messages, transferNote]);
|
|
207
|
+
}, [activeUser, messages, selectUser, widgetConfig]);
|
|
168
208
|
/* Position */
|
|
169
209
|
const posStyle = theme.buttonPosition === 'bottom-left'
|
|
170
210
|
? { left: 24, right: 'auto' }
|
|
@@ -220,7 +260,7 @@ export const ChatWidget = ({ theme: localTheme }) => {
|
|
|
220
260
|
zIndex: 20, display: 'flex', gap: 6,
|
|
221
261
|
}, children: [_jsx(CornerBtn, { onClick: () => setIsMaximized(m => !m), title: isMaximized ? 'Minimize' : 'Maximize', children: isMaximized
|
|
222
262
|
? _jsx("svg", { width: "12", height: "12", 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" }) })
|
|
223
|
-
: _jsx("svg", { width: "12", height: "12", 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" }) }) }), _jsx(CornerBtn, { onClick: closeDrawer, title: "Close", children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round" }) }) })] })), widgetConfig.status === 'MAINTENANCE' && (_jsx(MaintenanceView, { primaryColor: primaryColor })), widgetConfig.status === 'DISABLE' && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', padding: 32, textAlign: 'center', gap: 12 }, children: [_jsx("div", { style: { fontSize: 40 }, children: "\uD83D\uDD12" }), _jsx("p", { style: { fontWeight: 700, color: '#1a2332' }, children: "Chat is disabled" }), _jsx("button", { onClick: closeDrawer, style: { padding: '9px 20px', borderRadius: 10, border: 'none', background: primaryColor, color: '#fff', cursor: 'pointer', fontWeight: 700 }, children: "Close" })] })), widgetConfig.status === 'ACTIVE' && (_jsxs("div", { className: "cw-scroll", style: { flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [screen === 'home' && (_jsx(HomeScreen, { config: widgetConfig, onNavigate: handleCardClick })), screen === 'user-list' && (_jsx(UserListScreen, { context: userListCtx, users: filteredUsers, primaryColor: primaryColor, onBack: () => setScreen('home'), onSelectUser: handleSelectUser })), screen === 'chat' && activeUser && (_jsx(ChatScreen, { activeUser: activeUser, messages: messages, config: widgetConfig, isPaused: isPaused, isReported: isReported, isBlocked: isBlocked, onSend: sendMessage, onBack: () => { clearChat(); setScreen('home'); setActiveTab('home'); }, onClose: closeDrawer, onTogglePause: handleTogglePause, onReport: reportChat, onBlock: handleBlock, onStartCall: handleStartCall })), screen === 'call' && callSession.peer && (_jsx(CallScreen, { session: callSession, localVideoRef: localVideoRef, remoteVideoRef: remoteVideoRef, onEnd: handleEndCall, onToggleMute: toggleMute, onToggleCamera: toggleCamera, primaryColor: primaryColor })), screen === 'recent-chats' && (_jsx(RecentChatsScreen, { chats: recentChats, config: widgetConfig, onSelectChat: handleSelectUser })), screen === 'tickets' && (_jsx(TicketScreen, { tickets: tickets, config: widgetConfig, onRaiseTicket: handleRaiseTicket })), screen === 'block-list' && (_jsx(BlockListScreen, { blockedUsers: blockedUsers, config: widgetConfig, onUnblock: handleUnblock, onBack: () => { setScreen('home'); setActiveTab('home'); } }))] })), widgetConfig.status === 'ACTIVE' &&
|
|
263
|
+
: _jsx("svg", { width: "12", height: "12", 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" }) }) }), _jsx(CornerBtn, { onClick: closeDrawer, title: "Close", children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round" }) }) })] })), widgetConfig.status === 'MAINTENANCE' && (_jsx(MaintenanceView, { primaryColor: primaryColor })), widgetConfig.status === 'DISABLE' && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', padding: 32, textAlign: 'center', gap: 12 }, children: [_jsx("div", { style: { fontSize: 40 }, children: "\uD83D\uDD12" }), _jsx("p", { style: { fontWeight: 700, color: '#1a2332' }, children: "Chat is disabled" }), _jsx("button", { onClick: closeDrawer, style: { padding: '9px 20px', borderRadius: 10, border: 'none', background: primaryColor, color: '#fff', cursor: 'pointer', fontWeight: 700 }, children: "Close" })] })), widgetConfig.status === 'ACTIVE' && (_jsxs("div", { className: "cw-scroll", style: { flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [screen === 'home' && (_jsx(HomeScreen, { config: widgetConfig, onNavigate: handleCardClick, tickets: tickets })), screen === 'user-list' && (_jsx(UserListScreen, { context: userListCtx, users: filteredUsers, primaryColor: primaryColor, viewerType: (_d = widgetConfig.viewerType) !== null && _d !== void 0 ? _d : 'user', onBack: () => setScreen('home'), onSelectUser: handleSelectUser })), screen === 'chat' && activeUser && (_jsx(ChatScreen, { activeUser: activeUser, messages: messages, config: widgetConfig, isPaused: isPaused, isReported: isReported, isBlocked: isBlocked, onSend: sendMessage, onBack: () => { clearChat(); setScreen('home'); setActiveTab('home'); }, onClose: closeDrawer, onTogglePause: handleTogglePause, onReport: reportChat, onBlock: handleBlock, onStartCall: handleStartCall, onNavAction: handleNavFromMenu, otherDevelopers: otherDevelopers, onTransferToDeveloper: handleTransferToDeveloper })), screen === 'call' && callSession.peer && (_jsx(CallScreen, { session: callSession, localVideoRef: localVideoRef, remoteVideoRef: remoteVideoRef, onEnd: handleEndCall, onToggleMute: toggleMute, onToggleCamera: toggleCamera, primaryColor: primaryColor })), screen === 'recent-chats' && (_jsx(RecentChatsScreen, { chats: recentChats, config: widgetConfig, onSelectChat: handleSelectUser })), screen === 'tickets' && (_jsx(TicketScreen, { tickets: tickets, config: widgetConfig, onRaiseTicket: handleRaiseTicket })), screen === 'block-list' && (_jsx(BlockListScreen, { blockedUsers: blockedUsers, config: widgetConfig, onUnblock: handleUnblock, onBack: () => { setScreen('home'); setActiveTab('home'); } }))] })), widgetConfig.status === 'ACTIVE' &&
|
|
224
264
|
screen !== 'chat' &&
|
|
225
265
|
screen !== 'call' &&
|
|
226
266
|
screen !== 'user-list' &&
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { WidgetConfig, UserListContext } from '../../types';
|
|
2
|
+
import { WidgetConfig, UserListContext, Ticket } from '../../types';
|
|
3
3
|
interface HomeScreenProps {
|
|
4
4
|
config: WidgetConfig;
|
|
5
5
|
onNavigate: (ctx: UserListContext | 'ticket') => void;
|
|
6
|
+
tickets: Ticket[];
|
|
6
7
|
}
|
|
7
8
|
export declare const HomeScreen: React.FC<HomeScreenProps>;
|
|
8
9
|
export {};
|