ajaxter-chat 3.0.3 → 3.0.5
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 +3 -1
- package/dist/components/ChatScreen/index.js +129 -47
- package/dist/components/ChatWidget.js +12 -1
- package/dist/components/HomeScreen/index.d.ts +2 -1
- package/dist/components/HomeScreen/index.js +128 -51
- package/dist/components/SlideNavMenu.d.ts +12 -0
- package/dist/components/SlideNavMenu.js +73 -0
- package/dist/config/index.js +5 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/index.d.ts +10 -0
- package/package.json +1 -1
- package/public/chatData.json +3 -0
- package/src/components/ChatScreen/index.tsx +276 -172
- package/src/components/ChatWidget.tsx +13 -1
- package/src/components/HomeScreen/index.tsx +240 -80
- package/src/components/SlideNavMenu.tsx +138 -0
- package/src/config/index.ts +5 -1
- package/src/index.ts +1 -0
- package/src/types/index.ts +10 -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,8 @@ 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;
|
|
17
19
|
}
|
|
18
20
|
export declare const ChatScreen: React.FC<ChatScreenProps>;
|
|
19
21
|
export {};
|
|
@@ -2,10 +2,12 @@ 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, }) => {
|
|
6
7
|
const [text, setText] = useState('');
|
|
7
8
|
const [showEmoji, setShowEmoji] = useState(false);
|
|
8
9
|
const [showMenu, setShowMenu] = useState(false);
|
|
10
|
+
const [slideMenuOpen, setSlideMenuOpen] = useState(false);
|
|
9
11
|
const [isRecording, setIsRecording] = useState(false);
|
|
10
12
|
const [recordSec, setRecordSec] = useState(0);
|
|
11
13
|
const [showConfirm, setShowConfirm] = useState(null);
|
|
@@ -14,6 +16,7 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
14
16
|
const fileRef = useRef(null);
|
|
15
17
|
const recordTimer = useRef(null);
|
|
16
18
|
const mediaRecorder = useRef(null);
|
|
19
|
+
const recordChunks = useRef([]);
|
|
17
20
|
useEffect(() => { var _a; (_a = endRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
|
|
18
21
|
const handleSend = useCallback(() => {
|
|
19
22
|
var _a;
|
|
@@ -29,22 +32,29 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
29
32
|
handleSend();
|
|
30
33
|
}
|
|
31
34
|
};
|
|
32
|
-
// Voice recording
|
|
33
35
|
const startRecording = async () => {
|
|
34
36
|
if (isPaused || isBlocked)
|
|
35
37
|
return;
|
|
36
38
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
39
|
+
recordChunks.current = [];
|
|
37
40
|
const mr = new MediaRecorder(stream);
|
|
38
41
|
mediaRecorder.current = mr;
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
mr.ondataavailable = e => { if (e.data.size)
|
|
43
|
+
recordChunks.current.push(e.data); };
|
|
41
44
|
mr.onstop = () => {
|
|
42
45
|
stream.getTracks().forEach(t => t.stop());
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
const chunks = recordChunks.current;
|
|
47
|
+
if (!chunks.length) {
|
|
48
|
+
setRecordSec(0);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const blob = new Blob(chunks, { type: chunks[0] instanceof Blob ? chunks[0].type : 'audio/webm' });
|
|
52
|
+
const voiceUrl = URL.createObjectURL(blob);
|
|
53
|
+
const dur = Math.max(1, recordSec);
|
|
54
|
+
onSend('Voice message', 'voice', { voiceDuration: dur, voiceUrl });
|
|
45
55
|
setRecordSec(0);
|
|
46
56
|
};
|
|
47
|
-
mr.start();
|
|
57
|
+
mr.start(200);
|
|
48
58
|
setIsRecording(true);
|
|
49
59
|
recordTimer.current = setInterval(() => setRecordSec(s => s + 1), 1000);
|
|
50
60
|
};
|
|
@@ -55,25 +65,24 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
55
65
|
clearInterval(recordTimer.current);
|
|
56
66
|
setIsRecording(false);
|
|
57
67
|
};
|
|
58
|
-
// Attachment
|
|
59
68
|
const handleFileChange = (e) => {
|
|
60
69
|
var _a;
|
|
61
70
|
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
62
71
|
if (!file || isPaused || isBlocked)
|
|
63
72
|
return;
|
|
64
|
-
|
|
73
|
+
const attachmentUrl = URL.createObjectURL(file);
|
|
74
|
+
onSend(file.name, 'attachment', {
|
|
65
75
|
attachmentName: file.name,
|
|
66
76
|
attachmentSize: `${(file.size / 1024).toFixed(1)} KB`,
|
|
77
|
+
attachmentUrl,
|
|
67
78
|
});
|
|
68
79
|
e.target.value = '';
|
|
69
80
|
};
|
|
70
|
-
// Download transcript
|
|
71
81
|
const handleTranscript = () => {
|
|
72
82
|
const content = generateTranscript(messages, activeUser);
|
|
73
83
|
downloadText(content, `chat-${activeUser.name.replace(/\s+/g, '_')}-${Date.now()}.txt`);
|
|
74
84
|
setShowMenu(false);
|
|
75
85
|
};
|
|
76
|
-
// Confirm actions
|
|
77
86
|
const handleConfirm = (action) => {
|
|
78
87
|
setShowConfirm(null);
|
|
79
88
|
setShowMenu(false);
|
|
@@ -86,50 +95,119 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
|
|
|
86
95
|
};
|
|
87
96
|
const peerAvatar = avatarColor(activeUser.name);
|
|
88
97
|
const peerInit = initials(activeUser.name);
|
|
89
|
-
// Group messages by date
|
|
90
98
|
const grouped = groupByDate(messages);
|
|
91
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease', position: 'relative' }, children: [_jsxs("div", { style: {
|
|
99
|
+
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, onSelect: onNavAction, onBackHome: onBack }), _jsxs("div", { style: {
|
|
92
100
|
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
|
-
|
|
101
|
+
padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0,
|
|
102
|
+
}, 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: "Support" }), 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 })), _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: {
|
|
103
|
+
border: `1.5px solid ${isPaused || isBlocked ? '#e5e7eb' : '#bfdbfe'}`,
|
|
104
|
+
borderRadius: 16,
|
|
105
|
+
padding: '10px 12px 8px',
|
|
106
|
+
background: isPaused || isBlocked ? '#f9fafb' : '#fff',
|
|
107
|
+
}, 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: {
|
|
108
|
+
width: '100%',
|
|
109
|
+
resize: 'none',
|
|
110
|
+
border: 'none',
|
|
111
|
+
outline: 'none',
|
|
112
|
+
fontSize: 14,
|
|
113
|
+
lineHeight: 1.45,
|
|
114
|
+
color: '#1a2332',
|
|
115
|
+
background: 'transparent',
|
|
116
|
+
maxHeight: 88,
|
|
117
|
+
overflowY: 'auto',
|
|
105
118
|
fontFamily: 'inherit',
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
marginBottom: 8,
|
|
120
|
+
} }), _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: {
|
|
121
|
+
width: 36,
|
|
122
|
+
height: 36,
|
|
123
|
+
borderRadius: '50%',
|
|
124
|
+
backgroundColor: text.trim() && !isPaused && !isBlocked ? config.primaryColor : '#e2e8f0',
|
|
125
|
+
border: 'none',
|
|
126
|
+
cursor: text.trim() && !isPaused && !isBlocked ? 'pointer' : 'default',
|
|
127
|
+
display: 'flex',
|
|
128
|
+
alignItems: 'center',
|
|
129
|
+
justifyContent: 'center',
|
|
130
|
+
flexShrink: 0,
|
|
131
|
+
transition: 'background 0.15s',
|
|
132
|
+
}, 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 })] }))] }), showConfirm && (_jsx("div", { style: {
|
|
117
133
|
position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.45)',
|
|
118
134
|
display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 300,
|
|
119
135
|
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: {
|
|
136
|
+
}, 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
137
|
flex: 1, padding: '9px', borderRadius: 10, border: 'none',
|
|
122
138
|
background: showConfirm === 'block' ? '#ef4444' : config.primaryColor,
|
|
123
139
|
color: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 700,
|
|
124
140
|
}, children: "Confirm" })] })] }) }))] }));
|
|
125
141
|
};
|
|
126
|
-
|
|
127
|
-
const Bubble = ({ msg, peer, primaryColor }) => {
|
|
142
|
+
const VoiceRow = ({ msg, isMe, primaryColor }) => {
|
|
128
143
|
var _a;
|
|
144
|
+
const audioRef = useRef(null);
|
|
145
|
+
const [playing, setPlaying] = useState(false);
|
|
146
|
+
const [current, setCurrent] = useState(0);
|
|
147
|
+
const [dur, setDur] = useState((_a = msg.voiceDuration) !== null && _a !== void 0 ? _a : 0);
|
|
148
|
+
const url = msg.voiceUrl;
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const a = audioRef.current;
|
|
151
|
+
if (!a || !url)
|
|
152
|
+
return;
|
|
153
|
+
const onMeta = () => setDur(a.duration || msg.voiceDuration || 0);
|
|
154
|
+
const onTime = () => setCurrent(a.currentTime);
|
|
155
|
+
a.addEventListener('loadedmetadata', onMeta);
|
|
156
|
+
a.addEventListener('timeupdate', onTime);
|
|
157
|
+
return () => {
|
|
158
|
+
a.removeEventListener('loadedmetadata', onMeta);
|
|
159
|
+
a.removeEventListener('timeupdate', onTime);
|
|
160
|
+
};
|
|
161
|
+
}, [url, msg.voiceDuration]);
|
|
162
|
+
const toggle = () => {
|
|
163
|
+
const a = audioRef.current;
|
|
164
|
+
if (!a)
|
|
165
|
+
return;
|
|
166
|
+
if (playing) {
|
|
167
|
+
a.pause();
|
|
168
|
+
setPlaying(false);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
void a.play().then(() => setPlaying(true)).catch(() => { });
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const pct = dur > 0 ? Math.min(100, (current / dur) * 100) : 0;
|
|
175
|
+
const timeLabel = fmtTime(Math.floor(current)) + ' / ' + fmtTime(Math.floor(dur || msg.voiceDuration || 0));
|
|
176
|
+
if (!url) {
|
|
177
|
+
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` : ''] })] }));
|
|
178
|
+
}
|
|
179
|
+
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: {
|
|
180
|
+
width: 36,
|
|
181
|
+
height: 36,
|
|
182
|
+
borderRadius: '50%',
|
|
183
|
+
border: 'none',
|
|
184
|
+
background: isMe ? 'rgba(255,255,255,0.95)' : '#fff',
|
|
185
|
+
color: isMe ? primaryColor : primaryColor,
|
|
186
|
+
cursor: 'pointer',
|
|
187
|
+
display: 'flex',
|
|
188
|
+
alignItems: 'center',
|
|
189
|
+
justifyContent: 'center',
|
|
190
|
+
flexShrink: 0,
|
|
191
|
+
boxShadow: '0 1px 4px rgba(0,0,0,0.12)',
|
|
192
|
+
}, "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 })] })] }));
|
|
193
|
+
};
|
|
194
|
+
const AttachmentRow = ({ msg, isMe, primaryColor }) => {
|
|
195
|
+
var _a;
|
|
196
|
+
const name = (_a = msg.attachmentName) !== null && _a !== void 0 ? _a : 'File';
|
|
197
|
+
const href = msg.attachmentUrl;
|
|
198
|
+
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: {
|
|
199
|
+
fontSize: 12,
|
|
200
|
+
fontWeight: 700,
|
|
201
|
+
color: isMe ? '#fff' : primaryColor,
|
|
202
|
+
textDecoration: 'underline',
|
|
203
|
+
whiteSpace: 'nowrap',
|
|
204
|
+
}, children: "Download" }))] }));
|
|
205
|
+
};
|
|
206
|
+
const Bubble = ({ msg, primaryColor }) => {
|
|
129
207
|
const isMe = msg.senderId === 'me';
|
|
130
|
-
const content = msg.type === 'voice' ? (
|
|
208
|
+
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
209
|
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: isMe ? 'flex-end' : 'flex-start', gap: 3 }, children: [_jsx("div", { style: {
|
|
132
|
-
maxWidth: '
|
|
210
|
+
maxWidth: '85%', padding: '10px 13px',
|
|
133
211
|
borderRadius: isMe ? '18px 18px 4px 18px' : '18px 18px 18px 4px',
|
|
134
212
|
backgroundColor: isMe ? primaryColor : '#fff',
|
|
135
213
|
color: isMe ? '#fff' : '#1a2332',
|
|
@@ -138,24 +216,23 @@ const Bubble = ({ msg, peer, primaryColor }) => {
|
|
|
138
216
|
wordBreak: 'break-word',
|
|
139
217
|
}, children: content }), _jsx("span", { style: { fontSize: 11, color: '#b0bec5', padding: '0 4px' }, children: formatTime(msg.timestamp) })] }));
|
|
140
218
|
};
|
|
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: {
|
|
219
|
+
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' } })] }));
|
|
220
|
+
const MenuItem = ({ icon, label, onClick, danger }) => (_jsxs("button", { type: "button", onClick: onClick, style: {
|
|
143
221
|
display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 12px',
|
|
144
222
|
background: 'none', border: 'none', borderRadius: 8, cursor: 'pointer', textAlign: 'left',
|
|
145
223
|
fontSize: 13, fontWeight: 600, color: danger ? '#ef4444' : '#374151',
|
|
146
224
|
transition: 'background 0.12s',
|
|
147
225
|
}, 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: '
|
|
226
|
+
const ActionBtn = ({ onClick, title, children }) => (_jsx("button", { type: "button", onClick: onClick, title: title, style: {
|
|
227
|
+
background: 'none', border: 'none', cursor: 'pointer', padding: '8px',
|
|
150
228
|
borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
|
|
151
229
|
transition: 'background 0.13s',
|
|
152
|
-
}, onMouseEnter: e => e.currentTarget.style.background = '#
|
|
230
|
+
}, onMouseEnter: e => e.currentTarget.style.background = '#f1f5f9', onMouseLeave: e => e.currentTarget.style.background = 'none', children: children }));
|
|
153
231
|
const hdrBtn = {
|
|
154
232
|
background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '50%',
|
|
155
233
|
width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
156
234
|
cursor: 'pointer', flexShrink: 0,
|
|
157
235
|
};
|
|
158
|
-
// Group messages by date
|
|
159
236
|
function groupByDate(messages) {
|
|
160
237
|
const map = new Map();
|
|
161
238
|
messages.forEach(m => {
|
|
@@ -166,3 +243,8 @@ function groupByDate(messages) {
|
|
|
166
243
|
});
|
|
167
244
|
return Array.from(map.entries()).map(([date, msgs]) => ({ date, msgs }));
|
|
168
245
|
}
|
|
246
|
+
function fmtTime(sec) {
|
|
247
|
+
const m = Math.floor(sec / 60);
|
|
248
|
+
const s = Math.max(0, sec % 60);
|
|
249
|
+
return `${m}:${String(s).padStart(2, '0')}`;
|
|
250
|
+
}
|
|
@@ -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
|
|
@@ -220,7 +231,7 @@ export const ChatWidget = ({ theme: localTheme }) => {
|
|
|
220
231
|
zIndex: 20, display: 'flex', gap: 6,
|
|
221
232
|
}, children: [_jsx(CornerBtn, { onClick: () => setIsMaximized(m => !m), title: isMaximized ? 'Minimize' : 'Maximize', children: isMaximized
|
|
222
233
|
? _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' &&
|
|
234
|
+
: _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, 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 })), 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
235
|
screen !== 'chat' &&
|
|
225
236
|
screen !== 'call' &&
|
|
226
237
|
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 {};
|
|
@@ -1,55 +1,132 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { SlideNavMenu } from '../SlideNavMenu';
|
|
4
|
+
export const HomeScreen = ({ config, onNavigate, tickets }) => {
|
|
5
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
3
6
|
const showSupport = config.chatType === 'SUPPORT' || config.chatType === 'BOTH';
|
|
4
7
|
const showChat = config.chatType === 'CHAT' || config.chatType === 'BOTH';
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
key: 'conversation',
|
|
15
|
-
icon: '💬',
|
|
16
|
-
title: 'New Conversation',
|
|
17
|
-
subtitle: 'With your colleague',
|
|
18
|
-
onClick: () => onNavigate('conversation'),
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
key: 'ticket',
|
|
22
|
-
icon: '🎫',
|
|
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
|
-
background: `linear-gradient(145deg, ${config.primaryColor}, ${config.primaryColor}dd)`,
|
|
30
|
-
padding: '36px 24px 52px',
|
|
8
|
+
const continueItems = tickets.slice(0, 2);
|
|
9
|
+
const handleCallUs = () => {
|
|
10
|
+
var _a;
|
|
11
|
+
const raw = (_a = config.supportPhone) === null || _a === void 0 ? void 0 : _a.trim();
|
|
12
|
+
if (!raw)
|
|
13
|
+
return;
|
|
14
|
+
window.location.href = `tel:${raw.replace(/\s/g, '')}`;
|
|
15
|
+
};
|
|
16
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', position: 'relative', overflow: 'hidden', background: '#fafbfc' }, children: [_jsx(SlideNavMenu, { open: menuOpen, onClose: () => setMenuOpen(false), primaryColor: config.primaryColor, chatType: config.chatType, onSelect: onNavigate }), _jsx("div", { style: {
|
|
31
17
|
flexShrink: 0,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
18
|
+
padding: '14px 16px 10px',
|
|
19
|
+
display: 'flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
gap: 12,
|
|
22
|
+
background: '#fff',
|
|
23
|
+
borderBottom: '1px solid #eef0f5',
|
|
24
|
+
}, children: _jsxs("button", { type: "button", "aria-label": "Open menu", onClick: () => setMenuOpen(true), style: {
|
|
25
|
+
width: 40,
|
|
26
|
+
height: 40,
|
|
27
|
+
borderRadius: 10,
|
|
28
|
+
border: 'none',
|
|
29
|
+
background: '#f1f5f9',
|
|
30
|
+
cursor: 'pointer',
|
|
31
|
+
display: 'flex',
|
|
32
|
+
flexDirection: 'column',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
gap: 5,
|
|
36
|
+
flexShrink: 0,
|
|
37
|
+
}, children: [_jsx("span", { style: { width: 18, height: 2, background: '#334155', borderRadius: 1 } }), _jsx("span", { style: { width: 18, height: 2, background: '#334155', borderRadius: 1 } }), _jsx("span", { style: { width: 18, height: 2, background: '#334155', borderRadius: 1 } })] }) }), _jsxs("div", { className: "cw-scroll", style: { flex: 1, overflowY: 'auto', padding: '20px 18px 28px' }, children: [_jsx("h1", { style: {
|
|
38
|
+
margin: '0 0 8px',
|
|
39
|
+
fontSize: 24,
|
|
40
|
+
fontWeight: 800,
|
|
41
|
+
color: '#0f172a',
|
|
42
|
+
letterSpacing: '-0.03em',
|
|
43
|
+
lineHeight: 1.2,
|
|
44
|
+
}, children: config.welcomeTitle }), _jsx("p", { style: { margin: '0 0 28px', fontSize: 14, color: '#64748b', lineHeight: 1.55 }, children: config.welcomeSubtitle }), _jsx("h2", { style: { margin: '0 0 12px', fontSize: 15, fontWeight: 800, color: '#0f172a' }, children: "Continue Conversations" }), _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 28 }, children: continueItems.length > 0 ? (continueItems.map(t => (_jsx("button", { type: "button", onClick: () => onNavigate('ticket'), style: {
|
|
45
|
+
width: '100%',
|
|
46
|
+
textAlign: 'left',
|
|
47
|
+
padding: '14px 16px',
|
|
48
|
+
borderRadius: 14,
|
|
49
|
+
border: 'none',
|
|
50
|
+
background: '#e0f2fe',
|
|
51
|
+
color: '#0369a1',
|
|
52
|
+
fontSize: 14,
|
|
53
|
+
fontWeight: 600,
|
|
54
|
+
cursor: 'pointer',
|
|
55
|
+
boxShadow: '0 1px 3px rgba(0,0,0,0.06)',
|
|
56
|
+
}, children: t.title }, t.id)))) : (_jsxs(_Fragment, { children: [_jsx("div", { style: {
|
|
57
|
+
padding: '14px 16px',
|
|
58
|
+
borderRadius: 14,
|
|
59
|
+
background: '#e0f2fe',
|
|
60
|
+
color: '#64748b',
|
|
61
|
+
fontSize: 14,
|
|
62
|
+
fontWeight: 500,
|
|
63
|
+
}, children: "No open tickets yet" }), _jsx("div", { style: {
|
|
64
|
+
padding: '14px 16px',
|
|
65
|
+
borderRadius: 14,
|
|
66
|
+
background: '#e0f2fe',
|
|
67
|
+
color: '#64748b',
|
|
68
|
+
fontSize: 14,
|
|
69
|
+
fontWeight: 500,
|
|
70
|
+
}, children: "Start via Raise ticket below" })] })) }), _jsx("h2", { style: { margin: '0 0 12px', fontSize: 15, fontWeight: 800, color: '#0f172a' }, children: "Talk to our experts" }), showSupport && (_jsxs("button", { type: "button", onClick: () => onNavigate('support'), style: {
|
|
71
|
+
width: '100%',
|
|
72
|
+
display: 'flex',
|
|
73
|
+
alignItems: 'center',
|
|
74
|
+
justifyContent: 'center',
|
|
75
|
+
gap: 10,
|
|
76
|
+
padding: '14px 18px',
|
|
77
|
+
marginBottom: showChat ? 10 : 14,
|
|
78
|
+
borderRadius: 14,
|
|
79
|
+
border: 'none',
|
|
80
|
+
background: '#ede9fe',
|
|
81
|
+
color: '#5b21b6',
|
|
82
|
+
fontSize: 15,
|
|
83
|
+
fontWeight: 700,
|
|
84
|
+
cursor: 'pointer',
|
|
85
|
+
boxShadow: '0 2px 8px rgba(91,33,182,0.12)',
|
|
86
|
+
}, children: [_jsx("span", { style: { fontSize: 18 }, children: "\uD83D\uDC64" }), "Support"] })), showChat && showSupport && (_jsx("button", { type: "button", onClick: () => onNavigate('conversation'), style: {
|
|
87
|
+
width: '100%',
|
|
88
|
+
padding: '12px 16px',
|
|
89
|
+
marginBottom: 14,
|
|
90
|
+
borderRadius: 12,
|
|
91
|
+
border: '1.5px solid #e9d5ff',
|
|
92
|
+
background: '#fff',
|
|
93
|
+
color: '#6d28d9',
|
|
94
|
+
fontSize: 14,
|
|
95
|
+
fontWeight: 600,
|
|
96
|
+
cursor: 'pointer',
|
|
97
|
+
}, children: "New Conversation" })), showChat && !showSupport && (_jsxs("button", { type: "button", onClick: () => onNavigate('conversation'), style: {
|
|
98
|
+
width: '100%',
|
|
99
|
+
display: 'flex',
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
gap: 10,
|
|
103
|
+
padding: '14px 18px',
|
|
104
|
+
marginBottom: 14,
|
|
105
|
+
borderRadius: 14,
|
|
106
|
+
border: 'none',
|
|
107
|
+
background: '#ede9fe',
|
|
108
|
+
color: '#5b21b6',
|
|
109
|
+
fontSize: 15,
|
|
110
|
+
fontWeight: 700,
|
|
111
|
+
cursor: 'pointer',
|
|
112
|
+
}, children: [_jsx("span", { style: { fontSize: 18 }, children: "\uD83D\uDCAC" }), "New Conversation"] })), _jsxs("div", { style: {
|
|
113
|
+
borderRadius: 18,
|
|
114
|
+
padding: '22px 20px 20px',
|
|
115
|
+
background: 'linear-gradient(145deg, #fce7f3 0%, #e9d5ff 45%, #ddd6fe 100%)',
|
|
116
|
+
position: 'relative',
|
|
117
|
+
overflow: 'hidden',
|
|
118
|
+
}, children: [_jsx("div", { style: { position: 'absolute', top: -20, right: -20, width: 100, height: 100, borderRadius: '50%', background: 'rgba(255,255,255,0.35)' } }), _jsx("p", { style: { margin: '0 0 16px', fontSize: 15, fontWeight: 700, color: '#4c1d95', lineHeight: 1.45, position: 'relative' }, children: "Need specialized help? Our teams are ready to assist you with any questions." }), _jsxs("button", { type: "button", onClick: handleCallUs, disabled: !config.supportPhone, style: {
|
|
119
|
+
display: 'inline-flex',
|
|
120
|
+
alignItems: 'center',
|
|
121
|
+
gap: 8,
|
|
122
|
+
padding: '10px 18px',
|
|
123
|
+
borderRadius: 12,
|
|
124
|
+
border: 'none',
|
|
125
|
+
background: config.supportPhone ? config.primaryColor : '#94a3b8',
|
|
126
|
+
color: '#fff',
|
|
127
|
+
fontSize: 14,
|
|
128
|
+
fontWeight: 700,
|
|
129
|
+
cursor: config.supportPhone ? 'pointer' : 'not-allowed',
|
|
130
|
+
position: 'relative',
|
|
131
|
+
}, children: [_jsx("svg", { width: "16", height: "16", 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" }) }), "Call Us"] })] })] })] }));
|
|
54
132
|
};
|
|
55
|
-
const SendArrow = ({ color }) => (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 }, children: _jsx("path", { d: "M5 12h14M12 5l7 7-7 7", stroke: color, strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|