ajaxter-chat 3.0.16 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/components/BlockList/index.d.ts +1 -0
  2. package/dist/components/BlockList/index.d.ts.map +1 -0
  3. package/dist/components/BlockList/index.js +55 -28
  4. package/dist/components/BlockList/index.js.map +1 -0
  5. package/dist/components/CallScreen/index.d.ts +3 -0
  6. package/dist/components/CallScreen/index.d.ts.map +1 -0
  7. package/dist/components/CallScreen/index.js +107 -29
  8. package/dist/components/CallScreen/index.js.map +1 -0
  9. package/dist/components/ChatScreen/index.d.ts +1 -0
  10. package/dist/components/ChatScreen/index.d.ts.map +1 -0
  11. package/dist/components/ChatScreen/index.js +493 -294
  12. package/dist/components/ChatScreen/index.js.map +1 -0
  13. package/dist/components/ChatWidget.d.ts +1 -0
  14. package/dist/components/ChatWidget.d.ts.map +1 -0
  15. package/dist/components/ChatWidget.js +359 -250
  16. package/dist/components/ChatWidget.js.map +1 -0
  17. package/dist/components/EmojiPicker/index.d.ts +1 -0
  18. package/dist/components/EmojiPicker/index.d.ts.map +1 -0
  19. package/dist/components/EmojiPicker/index.js +19 -7
  20. package/dist/components/EmojiPicker/index.js.map +1 -0
  21. package/dist/components/ErrorBoundary/index.d.ts +20 -0
  22. package/dist/components/ErrorBoundary/index.d.ts.map +1 -0
  23. package/dist/components/ErrorBoundary/index.js +76 -0
  24. package/dist/components/ErrorBoundary/index.js.map +1 -0
  25. package/dist/components/HomeScreen/index.d.ts +1 -0
  26. package/dist/components/HomeScreen/index.d.ts.map +1 -0
  27. package/dist/components/HomeScreen/index.js +236 -158
  28. package/dist/components/HomeScreen/index.js.map +1 -0
  29. package/dist/components/MaintenanceView/index.d.ts +1 -0
  30. package/dist/components/MaintenanceView/index.d.ts.map +1 -0
  31. package/dist/components/MaintenanceView/index.js +28 -12
  32. package/dist/components/MaintenanceView/index.js.map +1 -0
  33. package/dist/components/MiniCallBar/index.d.ts +15 -0
  34. package/dist/components/MiniCallBar/index.d.ts.map +1 -0
  35. package/dist/components/MiniCallBar/index.js +116 -0
  36. package/dist/components/MiniCallBar/index.js.map +1 -0
  37. package/dist/components/PermissionsGateScreen/index.d.ts +1 -0
  38. package/dist/components/PermissionsGateScreen/index.d.ts.map +1 -0
  39. package/dist/components/PermissionsGateScreen/index.js +82 -28
  40. package/dist/components/PermissionsGateScreen/index.js.map +1 -0
  41. package/dist/components/RecentChatsScreen/index.d.ts +1 -0
  42. package/dist/components/RecentChatsScreen/index.d.ts.map +1 -0
  43. package/dist/components/RecentChatsScreen/index.js +79 -19
  44. package/dist/components/RecentChatsScreen/index.js.map +1 -0
  45. package/dist/components/SlideNavMenu.d.ts +1 -0
  46. package/dist/components/SlideNavMenu.d.ts.map +1 -0
  47. package/dist/components/SlideNavMenu.js +82 -63
  48. package/dist/components/SlideNavMenu.js.map +1 -0
  49. package/dist/components/Tabs/BottomTabs.d.ts +1 -0
  50. package/dist/components/Tabs/BottomTabs.d.ts.map +1 -0
  51. package/dist/components/Tabs/BottomTabs.js +34 -19
  52. package/dist/components/Tabs/BottomTabs.js.map +1 -0
  53. package/dist/components/TicketDetailScreen/index.d.ts +1 -0
  54. package/dist/components/TicketDetailScreen/index.d.ts.map +1 -0
  55. package/dist/components/TicketDetailScreen/index.js +66 -27
  56. package/dist/components/TicketDetailScreen/index.js.map +1 -0
  57. package/dist/components/TicketFormScreen/index.d.ts +1 -0
  58. package/dist/components/TicketFormScreen/index.d.ts.map +1 -0
  59. package/dist/components/TicketFormScreen/index.js +99 -49
  60. package/dist/components/TicketFormScreen/index.js.map +1 -0
  61. package/dist/components/TicketScreen/index.d.ts +1 -0
  62. package/dist/components/TicketScreen/index.d.ts.map +1 -0
  63. package/dist/components/TicketScreen/index.js +95 -26
  64. package/dist/components/TicketScreen/index.js.map +1 -0
  65. package/dist/components/UserListScreen/index.d.ts +1 -0
  66. package/dist/components/UserListScreen/index.d.ts.map +1 -0
  67. package/dist/components/UserListScreen/index.js +127 -53
  68. package/dist/components/UserListScreen/index.js.map +1 -0
  69. package/dist/components/ViewerBlockedScreen/index.d.ts +1 -0
  70. package/dist/components/ViewerBlockedScreen/index.d.ts.map +1 -0
  71. package/dist/components/ViewerBlockedScreen/index.js +113 -61
  72. package/dist/components/ViewerBlockedScreen/index.js.map +1 -0
  73. package/dist/config/index.d.ts +1 -0
  74. package/dist/config/index.d.ts.map +1 -0
  75. package/dist/config/index.js +7 -2
  76. package/dist/config/index.js.map +1 -0
  77. package/dist/hooks/useChat.d.ts +9 -1
  78. package/dist/hooks/useChat.d.ts.map +1 -0
  79. package/dist/hooks/useChat.js +60 -18
  80. package/dist/hooks/useChat.js.map +1 -0
  81. package/dist/hooks/useRemoteConfig.d.ts +1 -0
  82. package/dist/hooks/useRemoteConfig.d.ts.map +1 -0
  83. package/dist/hooks/useRemoteConfig.js +12 -8
  84. package/dist/hooks/useRemoteConfig.js.map +1 -0
  85. package/dist/hooks/useSocket.d.ts +40 -0
  86. package/dist/hooks/useSocket.d.ts.map +1 -0
  87. package/dist/hooks/useSocket.js +190 -0
  88. package/dist/hooks/useSocket.js.map +1 -0
  89. package/dist/hooks/useWebRTC.d.ts +10 -2
  90. package/dist/hooks/useWebRTC.d.ts.map +1 -0
  91. package/dist/hooks/useWebRTC.js +101 -69
  92. package/dist/hooks/useWebRTC.js.map +1 -0
  93. package/dist/index.d.ts +6 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +67 -21
  96. package/dist/index.js.map +1 -0
  97. package/dist/types/index.d.ts +1 -0
  98. package/dist/types/index.d.ts.map +1 -0
  99. package/dist/types/index.js +3 -1
  100. package/dist/types/index.js.map +1 -0
  101. package/dist/utils/chat.d.ts +1 -0
  102. package/dist/utils/chat.d.ts.map +1 -0
  103. package/dist/utils/chat.js +17 -7
  104. package/dist/utils/chat.js.map +1 -0
  105. package/dist/utils/fileName.d.ts +1 -0
  106. package/dist/utils/fileName.d.ts.map +1 -0
  107. package/dist/utils/fileName.js +5 -1
  108. package/dist/utils/fileName.js.map +1 -0
  109. package/dist/utils/messageSound.d.ts +1 -0
  110. package/dist/utils/messageSound.d.ts.map +1 -0
  111. package/dist/utils/messageSound.js +9 -3
  112. package/dist/utils/messageSound.js.map +1 -0
  113. package/dist/utils/presenceStatus.d.ts +1 -0
  114. package/dist/utils/presenceStatus.d.ts.map +1 -0
  115. package/dist/utils/presenceStatus.js +11 -4
  116. package/dist/utils/presenceStatus.js.map +1 -0
  117. package/dist/utils/privacyConsent.d.ts +1 -0
  118. package/dist/utils/privacyConsent.d.ts.map +1 -0
  119. package/dist/utils/privacyConsent.js +9 -3
  120. package/dist/utils/privacyConsent.js.map +1 -0
  121. package/dist/utils/reenableRequest.d.ts +1 -0
  122. package/dist/utils/reenableRequest.d.ts.map +1 -0
  123. package/dist/utils/reenableRequest.js +5 -1
  124. package/dist/utils/reenableRequest.js.map +1 -0
  125. package/dist/utils/theme.d.ts +1 -0
  126. package/dist/utils/theme.d.ts.map +1 -0
  127. package/dist/utils/theme.js +10 -4
  128. package/dist/utils/theme.js.map +1 -0
  129. package/dist/utils/widgetPermissions.d.ts +1 -0
  130. package/dist/utils/widgetPermissions.d.ts.map +1 -0
  131. package/dist/utils/widgetPermissions.js +13 -5
  132. package/dist/utils/widgetPermissions.js.map +1 -0
  133. package/dist/utils/widgetSession.d.ts +1 -0
  134. package/dist/utils/widgetSession.d.ts.map +1 -0
  135. package/dist/utils/widgetSession.js +9 -3
  136. package/dist/utils/widgetSession.js.map +1 -0
  137. package/package.json +3 -3
  138. package/src/components/CallScreen/index.tsx +23 -1
  139. package/src/components/ChatScreen/index.tsx +2 -1
  140. package/src/components/ChatWidget.tsx +314 -263
  141. package/src/components/ErrorBoundary/index.tsx +62 -0
  142. package/src/components/HomeScreen/index.tsx +0 -3
  143. package/src/components/MiniCallBar/index.tsx +150 -0
  144. package/src/hooks/useChat.ts +59 -12
  145. package/src/hooks/useSocket.ts +228 -0
  146. package/src/hooks/useWebRTC.ts +99 -64
  147. package/src/index.ts +7 -2
@@ -1,58 +1,93 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import React, { useState, useRef, useEffect, useCallback } from 'react';
3
- import { avatarColor, initials, formatTime, formatDate, generateTranscript, downloadText } from '../../utils/chat';
4
- import { shortAttachmentLabel } from '../../utils/fileName';
5
- import { shouldShowPrivacyNotice, dismissPrivacyNotice } from '../../utils/privacyConsent';
6
- import { EmojiPicker } from '../EmojiPicker';
7
- export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported, isBlocked, onSend, onBack, onClose, onTogglePause, onReport, onBlock, onStartCall, onNavAction, otherDevelopers = [], onTransferToDeveloper, messageSoundEnabled = true, onToggleMessageSound, }) => {
8
- const [text, setText] = useState('');
9
- const [showEmoji, setShowEmoji] = useState(false);
10
- const [showMenu, setShowMenu] = useState(false);
11
- const [transferOpen, setTransferOpen] = useState(false);
12
- const [isRecording, setIsRecording] = useState(false);
13
- const [recordSec, setRecordSec] = useState(0);
14
- const [showConfirm, setShowConfirm] = useState(null);
15
- const [showPrivacy, setShowPrivacy] = useState(false);
16
- const [pendingAttach, setPendingAttach] = useState(null);
17
- const [waveBars, setWaveBars] = useState(() => Array(24).fill(0.08));
18
- const endRef = useRef(null);
19
- const inputRef = useRef(null);
20
- const fileRef = useRef(null);
21
- const recordTimer = useRef(null);
22
- const mediaRecorder = useRef(null);
23
- const recordChunks = useRef([]);
24
- const discardRecordingRef = useRef(false);
25
- const waveStreamRef = useRef(null);
26
- const audioCtxRef = useRef(null);
27
- const analyserRef = useRef(null);
28
- const waveRafRef = useRef(0);
29
- useEffect(() => { var _a; (_a = endRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ChatScreen = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const chat_1 = require("../../utils/chat");
39
+ const fileName_1 = require("../../utils/fileName");
40
+ const privacyConsent_1 = require("../../utils/privacyConsent");
41
+ const EmojiPicker_1 = require("../EmojiPicker");
42
+ const ChatScreen = ({ activeUser, messages, config, isPaused, isReported, isBlocked, onSend, onBack, onClose, onTogglePause, onReport, onBlock, onStartCall, onNavAction, otherDevelopers = [], onTransferToDeveloper, messageSoundEnabled = true, onToggleMessageSound, }) => {
43
+ const [text, setText] = (0, react_1.useState)('');
44
+ const [showEmoji, setShowEmoji] = (0, react_1.useState)(false);
45
+ const [showMenu, setShowMenu] = (0, react_1.useState)(false);
46
+ const [transferOpen, setTransferOpen] = (0, react_1.useState)(false);
47
+ const [isRecording, setIsRecording] = (0, react_1.useState)(false);
48
+ const [recordSec, setRecordSec] = (0, react_1.useState)(0);
49
+ const [showConfirm, setShowConfirm] = (0, react_1.useState)(null);
50
+ const [showPrivacy, setShowPrivacy] = (0, react_1.useState)(false);
51
+ const [pendingAttach, setPendingAttach] = (0, react_1.useState)(null);
52
+ const [waveBars, setWaveBars] = (0, react_1.useState)(() => Array(24).fill(0.08));
53
+ const endRef = (0, react_1.useRef)(null);
54
+ const inputRef = (0, react_1.useRef)(null);
55
+ const fileRef = (0, react_1.useRef)(null);
56
+ const recordTimer = (0, react_1.useRef)(null);
57
+ const mediaRecorder = (0, react_1.useRef)(null);
58
+ const recordChunks = (0, react_1.useRef)([]);
59
+ const discardRecordingRef = (0, react_1.useRef)(false);
60
+ const waveStreamRef = (0, react_1.useRef)(null);
61
+ const audioCtxRef = (0, react_1.useRef)(null);
62
+ const analyserRef = (0, react_1.useRef)(null);
63
+ const waveRafRef = (0, react_1.useRef)(0);
64
+ (0, react_1.useEffect)(() => { var _a; (_a = endRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
30
65
  const privacyEnabled = config.showPrivacyNotice !== false;
31
- useEffect(() => {
66
+ (0, react_1.useEffect)(() => {
32
67
  if (!privacyEnabled)
33
68
  return;
34
- setShowPrivacy(shouldShowPrivacyNotice(config.id));
69
+ setShowPrivacy((0, privacyConsent_1.shouldShowPrivacyNotice)(config.id));
35
70
  }, [config.id, privacyEnabled]);
36
- useEffect(() => {
71
+ (0, react_1.useEffect)(() => {
37
72
  if (!privacyEnabled)
38
73
  return;
39
74
  const id = window.setInterval(() => {
40
- setShowPrivacy(shouldShowPrivacyNotice(config.id));
75
+ setShowPrivacy((0, privacyConsent_1.shouldShowPrivacyNotice)(config.id));
41
76
  }, 60000);
42
77
  return () => window.clearInterval(id);
43
78
  }, [config.id, privacyEnabled]);
44
- const dismissPrivacy = useCallback(() => {
45
- dismissPrivacyNotice(config.id);
79
+ const dismissPrivacy = (0, react_1.useCallback)(() => {
80
+ (0, privacyConsent_1.dismissPrivacyNotice)(config.id);
46
81
  setShowPrivacy(false);
47
82
  }, [config.id]);
48
- const clearPendingAttach = useCallback((revoke) => {
83
+ const clearPendingAttach = (0, react_1.useCallback)((revoke) => {
49
84
  setPendingAttach(prev => {
50
85
  if (prev && revoke)
51
86
  URL.revokeObjectURL(prev.url);
52
87
  return null;
53
88
  });
54
89
  }, []);
55
- const handleSend = useCallback(() => {
90
+ const handleSend = (0, react_1.useCallback)(() => {
56
91
  var _a, _b;
57
92
  if (isPaused || isBlocked)
58
93
  return;
@@ -82,8 +117,8 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
82
117
  handleSend();
83
118
  }
84
119
  };
85
- const recordSecRef = useRef(0);
86
- const stopWaveLoop = useCallback(() => {
120
+ const recordSecRef = (0, react_1.useRef)(0);
121
+ const stopWaveLoop = (0, react_1.useCallback)(() => {
87
122
  var _a;
88
123
  if (waveRafRef.current) {
89
124
  cancelAnimationFrame(waveRafRef.current);
@@ -232,8 +267,8 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
232
267
  e.target.value = '';
233
268
  };
234
269
  const handleTranscript = () => {
235
- const content = generateTranscript(messages, activeUser);
236
- downloadText(content, `chat-${activeUser.name.replace(/\s+/g, '_')}-${Date.now()}.txt`);
270
+ const content = (0, chat_1.generateTranscript)(messages, activeUser);
271
+ (0, chat_1.downloadText)(content, `chat-${activeUser.name.replace(/\s+/g, '_')}-${Date.now()}.txt`);
237
272
  setShowMenu(false);
238
273
  };
239
274
  const handleConfirm = (action) => {
@@ -246,235 +281,361 @@ export const ChatScreen = ({ activeUser, messages, config, isPaused, isReported,
246
281
  if (action === 'pause')
247
282
  onTogglePause();
248
283
  };
249
- const peerAvatar = avatarColor(activeUser.name);
250
- const peerInit = initials(activeUser.name);
284
+ const peerAvatar = (0, chat_1.avatarColor)(activeUser.name);
285
+ const peerInit = (0, chat_1.initials)(activeUser.name);
251
286
  const grouped = groupByDate(messages);
252
287
  const viewerIsDev = config.viewerType === 'developer';
253
288
  const headerRole = viewerIsDev
254
289
  ? (activeUser.type === 'user' ? 'Customer' : 'Developer')
255
290
  : 'Support';
256
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease', position: 'relative', overflow: 'hidden' }, children: [_jsxs("div", { style: {
257
- background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
258
- padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0,
259
- }, children: [_jsx("button", { type: "button", onClick: onBack, style: hdrBtn, "aria-label": "Back", 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" }) }) }), _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 }), onToggleMessageSound && (_jsxs("label", { style: {
291
+ return (react_1.default.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease', position: 'relative', overflow: 'hidden' } },
292
+ react_1.default.createElement("div", { style: {
293
+ background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
294
+ padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0,
295
+ } },
296
+ react_1.default.createElement("button", { type: "button", onClick: onBack, style: hdrBtn, "aria-label": "Back" },
297
+ react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none" },
298
+ react_1.default.createElement("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }))),
299
+ react_1.default.createElement("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' } },
300
+ peerInit,
301
+ react_1.default.createElement("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' } })),
302
+ react_1.default.createElement("div", { style: { flex: 1, minWidth: 0 } },
303
+ react_1.default.createElement("div", { style: { fontWeight: 700, fontSize: 14, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, activeUser.name),
304
+ react_1.default.createElement("div", { style: { fontSize: 11, color: 'rgba(255,255,255,0.8)' } }, activeUser.designation)),
305
+ react_1.default.createElement("span", { style: { fontSize: 13, fontWeight: 700, color: '#fff', opacity: 0.95, flexShrink: 0 } }, headerRole),
306
+ onToggleMessageSound && (react_1.default.createElement("label", { style: {
307
+ display: 'flex',
308
+ alignItems: 'center',
309
+ gap: 6,
310
+ cursor: 'pointer',
311
+ flexShrink: 0,
312
+ marginLeft: 4,
313
+ } },
314
+ react_1.default.createElement("button", { type: "button", role: "switch", "aria-checked": messageSoundEnabled, onClick: () => onToggleMessageSound(!messageSoundEnabled), "aria-label": "Toggle message sound", title: "Toggle message sound", style: {
315
+ width: 36,
316
+ height: 20,
317
+ borderRadius: 10,
318
+ border: 'none',
319
+ background: messageSoundEnabled ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.2)',
320
+ position: 'relative',
321
+ cursor: 'pointer',
322
+ padding: 0,
323
+ } },
324
+ react_1.default.createElement("span", { style: {
325
+ position: 'absolute',
326
+ top: 2,
327
+ left: messageSoundEnabled ? 18 : 2,
328
+ width: 16,
329
+ height: 16,
330
+ borderRadius: '50%',
331
+ background: '#fff',
332
+ transition: 'left 0.15s ease',
333
+ } })))),
334
+ config.allowWebCall && (react_1.default.createElement("button", { type: "button", onClick: () => onStartCall(false), style: hdrBtn, title: "Voice Call" },
335
+ react_1.default.createElement("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none" },
336
+ react_1.default.createElement("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" })))),
337
+ react_1.default.createElement("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 },
338
+ react_1.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none" },
339
+ react_1.default.createElement("circle", { cx: "12", cy: "5", r: "1.5", fill: "#fff" }),
340
+ react_1.default.createElement("circle", { cx: "12", cy: "12", r: "1.5", fill: "#fff" }),
341
+ react_1.default.createElement("circle", { cx: "12", cy: "19", r: "1.5", fill: "#fff" })))),
342
+ showMenu && (react_1.default.createElement("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' } },
343
+ navEntriesForChat(config.chatType, viewerIsDev).map(item => (react_1.default.createElement(MenuItem, { key: item.key, icon: item.icon, label: item.label, onClick: () => { setShowMenu(false); onNavAction(item.key); } }))),
344
+ react_1.default.createElement("div", { style: { borderTop: '1px solid #f0f2f5', margin: '4px 0' } }),
345
+ config.allowTranscriptDownload && (react_1.default.createElement(MenuItem, { icon: "\uD83D\uDCE5", label: "Download Transcript", onClick: handleTranscript })),
346
+ viewerIsDev && activeUser.type === 'user' && otherDevelopers.length > 0 && onTransferToDeveloper && (react_1.default.createElement(MenuItem, { icon: "\uD83D\uDD00", label: "Transfer to developer", onClick: () => { setShowMenu(false); setTransferOpen(true); } })),
347
+ react_1.default.createElement(MenuItem, { icon: isPaused ? '▶️' : '⏸', label: isPaused ? 'Resume Chat' : 'Pause Chat', onClick: () => { setShowMenu(false); setShowConfirm('pause'); } }),
348
+ config.allowReport && !isReported && (react_1.default.createElement(MenuItem, { icon: "\u26A0\uFE0F", label: "Report Chat", onClick: () => { setShowMenu(false); setShowConfirm('report'); } })),
349
+ config.allowBlock && activeUser.type === 'user' && !isBlocked && (react_1.default.createElement(MenuItem, { icon: "\uD83D\uDEAB", label: "Block User", onClick: () => { setShowMenu(false); setShowConfirm('block'); }, danger: true })),
350
+ react_1.default.createElement("div", { style: { borderTop: '1px solid #f0f2f5', margin: '4px 0' } }),
351
+ react_1.default.createElement(MenuItem, { icon: "\u2715", label: "Close Chat", onClick: onClose }))),
352
+ isPaused && (react_1.default.createElement("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 } },
353
+ "\u23F8 Chat is paused \u2014 users cannot send messages",
354
+ react_1.default.createElement("button", { type: "button", onClick: onTogglePause, style: { background: '#92400e', color: '#fff', border: 'none', borderRadius: 6, padding: '2px 8px', fontSize: 11, cursor: 'pointer', marginLeft: 4 } }, "Resume"))),
355
+ isBlocked && (react_1.default.createElement("div", { style: { background: '#fee2e2', padding: '8px 16px', fontSize: 12, fontWeight: 600, color: '#991b1b', textAlign: 'center', flexShrink: 0 } }, "\uD83D\uDEAB This user is blocked")),
356
+ isReported && (react_1.default.createElement("div", { style: { background: '#fef3c7', padding: '6px 16px', fontSize: 11, color: '#92400e', textAlign: 'center', flexShrink: 0 } }, "\u26A0\uFE0F This chat has been reported")),
357
+ react_1.default.createElement("div", { style: { flex: 1, overflowY: 'auto', padding: '14px', display: 'flex', flexDirection: 'column', gap: 10, background: '#f8f9fc' }, className: "cw-scroll" },
358
+ grouped.map(({ date, msgs }) => (react_1.default.createElement(react_1.default.Fragment, { key: date },
359
+ react_1.default.createElement(DateDivider, { label: date }),
360
+ msgs.map(msg => (react_1.default.createElement(Bubble, { key: msg.id, msg: msg, primaryColor: config.primaryColor })))))),
361
+ messages.length === 0 && (react_1.default.createElement("div", { style: { margin: 'auto', textAlign: 'center', color: '#c4cad4', fontSize: 13 } },
362
+ react_1.default.createElement("div", { style: { fontSize: 28, marginBottom: 8 } }, "\uD83D\uDCAC"),
363
+ "Say hello to ",
364
+ activeUser.name,
365
+ "!")),
366
+ react_1.default.createElement("div", { ref: endRef })),
367
+ react_1.default.createElement("div", { style: { borderTop: '1px solid #eef0f5', padding: '10px 12px 8px', background: '#fff', flexShrink: 0, position: 'relative' } },
368
+ privacyEnabled && showPrivacy && (react_1.default.createElement("div", { style: {
369
+ position: 'relative',
370
+ marginBottom: 10,
371
+ padding: '12px 36px 12px 12px',
372
+ borderRadius: 12,
373
+ background: '#fff',
374
+ border: '1px solid #e8ecf1',
375
+ boxShadow: '0 1px 4px rgba(15,23,42,0.06)',
376
+ } },
377
+ react_1.default.createElement("button", { type: "button", "aria-label": "Dismiss privacy notice", onClick: dismissPrivacy, style: {
378
+ position: 'absolute',
379
+ top: 8,
380
+ right: 8,
381
+ width: 26,
382
+ height: 26,
383
+ borderRadius: '50%',
384
+ border: 'none',
385
+ background: '#f1f5f9',
386
+ cursor: 'pointer',
387
+ display: 'flex',
388
+ alignItems: 'center',
389
+ justifyContent: 'center',
390
+ padding: 0,
391
+ lineHeight: 1,
392
+ } },
393
+ react_1.default.createElement("span", { style: { fontSize: 14, color: '#475569', fontWeight: 700 } }, "\u00D7")),
394
+ react_1.default.createElement("p", { style: { margin: 0, fontSize: 12, color: '#64748b', lineHeight: 1.55 } },
395
+ "By chatting here, you agree we and authorized partners may process, monitor, and record this chat and your data in line with",
396
+ ' ',
397
+ config.privacyPolicyUrl ? (react_1.default.createElement("a", { href: config.privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", style: { color: config.primaryColor, textDecoration: 'underline', fontWeight: 600 } }, "Privacy Policy")) : (react_1.default.createElement("span", { style: { textDecoration: 'underline', fontWeight: 600 } }, "Privacy Policy")),
398
+ "."))),
399
+ showEmoji && config.allowEmoji && (react_1.default.createElement(EmojiPicker_1.EmojiPicker, { primaryColor: config.primaryColor, onSelect: e => setText(t => t + e), onClose: () => setShowEmoji(false) })),
400
+ isRecording && (react_1.default.createElement("div", { style: {
401
+ marginBottom: 10,
402
+ padding: '12px 12px 14px',
403
+ background: '#fff',
404
+ borderRadius: 14,
405
+ border: '1px solid #e8ecf1',
406
+ boxShadow: '0 1px 4px rgba(15,23,42,0.06)',
407
+ } },
408
+ react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 10, marginBottom: 10 } },
409
+ react_1.default.createElement("button", { type: "button", onClick: cancelRecording, title: "Discard recording", "aria-label": "Discard recording", style: {
410
+ background: 'none',
411
+ border: 'none',
412
+ cursor: 'pointer',
413
+ padding: 6,
414
+ lineHeight: 0,
415
+ flexShrink: 0,
416
+ } },
417
+ react_1.default.createElement("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none" },
418
+ react_1.default.createElement("path", { d: "M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round" }),
419
+ react_1.default.createElement("path", { d: "M10 11v6M14 11v6", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round" }))),
420
+ react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'flex-end', gap: 3, height: 44, flex: 1, justifyContent: 'flex-end', minWidth: 0 } }, waveBars.map((h, i) => (react_1.default.createElement("span", { key: i, style: {
421
+ width: 3,
422
+ borderRadius: 2,
423
+ background: '#cbd5e1',
424
+ height: `${8 + h * 36}px`,
425
+ transition: 'height 0.05s ease-out',
426
+ } }))))),
427
+ react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 } },
428
+ react_1.default.createElement("div", { style: { flex: 1 } }),
429
+ react_1.default.createElement("div", { style: {
430
+ background: '#ef4444',
431
+ color: '#fff',
432
+ fontWeight: 700,
433
+ fontSize: 13,
434
+ padding: '6px 14px',
435
+ borderRadius: 999,
436
+ minWidth: 52,
437
+ textAlign: 'center',
438
+ } }, fmtTime(recordSec)),
439
+ react_1.default.createElement("button", { type: "button", onClick: stopRecordingSend, title: "Send voice message", "aria-label": "Send voice message", style: {
440
+ width: 44,
441
+ height: 44,
442
+ borderRadius: '50%',
443
+ border: 'none',
444
+ background: config.primaryColor,
445
+ cursor: 'pointer',
446
+ display: 'flex',
447
+ alignItems: 'center',
448
+ justifyContent: 'center',
449
+ flexShrink: 0,
450
+ boxShadow: `0 4px 14px ${config.primaryColor}55`,
451
+ } },
452
+ react_1.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none" },
453
+ react_1.default.createElement("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })))))),
454
+ react_1.default.createElement("div", { style: {
455
+ border: `1.5px solid ${isPaused || isBlocked ? '#e5e7eb' : '#bfdbfe'}`,
456
+ borderRadius: 16,
457
+ padding: '10px 12px 8px',
458
+ background: isPaused || isBlocked ? '#f9fafb' : '#fff',
459
+ } },
460
+ pendingAttach && (react_1.default.createElement("div", { style: {
461
+ display: 'flex',
462
+ alignItems: 'center',
463
+ gap: 10,
464
+ marginBottom: 10,
465
+ padding: '8px 10px',
466
+ borderRadius: 10,
467
+ background: '#f8fafc',
468
+ border: '1px solid #fecaca',
469
+ position: 'relative',
470
+ } },
471
+ react_1.default.createElement("div", { style: {
472
+ width: 40,
473
+ height: 40,
474
+ borderRadius: 8,
475
+ background: config.primaryColor,
260
476
  display: 'flex',
261
477
  alignItems: 'center',
262
- gap: 6,
478
+ justifyContent: 'center',
479
+ flexShrink: 0,
480
+ } },
481
+ react_1.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none" },
482
+ react_1.default.createElement("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: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }))),
483
+ react_1.default.createElement("div", { style: { flex: 1, minWidth: 0 } },
484
+ react_1.default.createElement("div", { style: { fontWeight: 700, fontSize: 13, color: '#1a2332', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, title: pendingAttach.file.name }, pendingAttach.file.name),
485
+ react_1.default.createElement("div", { style: { fontSize: 11, color: '#94a3b8', fontWeight: 600, textTransform: 'uppercase' } }, (pendingAttach.file.type.split('/')[1] || 'file').slice(0, 8))),
486
+ react_1.default.createElement("button", { type: "button", onClick: () => clearPendingAttach(true), title: "Remove attachment", "aria-label": "Remove attachment", style: {
487
+ position: 'absolute',
488
+ top: 6,
489
+ right: 6,
490
+ width: 22,
491
+ height: 22,
492
+ borderRadius: '50%',
493
+ border: 'none',
494
+ background: '#ef4444',
495
+ color: '#fff',
263
496
  cursor: 'pointer',
497
+ fontSize: 15,
498
+ fontWeight: 700,
499
+ lineHeight: 1,
500
+ display: 'flex',
501
+ alignItems: 'center',
502
+ justifyContent: 'center',
503
+ padding: 0,
504
+ } }, "\u00D7"))),
505
+ react_1.default.createElement("textarea", { ref: inputRef, value: text, onChange: e => setText(e.target.value), onKeyDown: handleKey, onPaste: handlePaste, placeholder: isPaused || isBlocked ? 'Chat is unavailable' : 'Compose your message…', disabled: isPaused || isBlocked || isRecording, rows: 2, style: {
506
+ width: '100%',
507
+ resize: 'none',
508
+ border: 'none',
509
+ outline: 'none',
510
+ fontSize: 14,
511
+ lineHeight: 1.45,
512
+ color: '#1a2332',
513
+ background: 'transparent',
514
+ maxHeight: 88,
515
+ overflowY: 'auto',
516
+ fontFamily: 'inherit',
517
+ marginBottom: 8,
518
+ } }),
519
+ react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
520
+ react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 2 } },
521
+ config.allowEmoji && (react_1.default.createElement(ActionBtn, { onClick: () => setShowEmoji(v => !v), title: "Emoji" },
522
+ react_1.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none" },
523
+ react_1.default.createElement("circle", { cx: "12", cy: "12", r: "10", stroke: "#94a3b8", strokeWidth: "1.8" }),
524
+ react_1.default.createElement("path", { d: "M8 14s1.5 2 4 2 4-2 4-2", stroke: "#94a3b8", strokeWidth: "1.8", strokeLinecap: "round" }),
525
+ react_1.default.createElement("circle", { cx: "9", cy: "9", r: "1", fill: "#94a3b8" }),
526
+ react_1.default.createElement("circle", { cx: "15", cy: "9", r: "1", fill: "#94a3b8" })))),
527
+ config.allowAttachment && (react_1.default.createElement(react_1.default.Fragment, null,
528
+ react_1.default.createElement("input", { ref: fileRef, type: "file", style: { display: 'none' }, onChange: handleFileChange }),
529
+ react_1.default.createElement(ActionBtn, { onClick: () => { var _a; return (_a = fileRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, title: "Attach file" },
530
+ react_1.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none" },
531
+ react_1.default.createElement("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" }))))),
532
+ config.allowVoiceMessage && !isRecording && (react_1.default.createElement(ActionBtn, { onClick: startRecording, title: "Voice message" },
533
+ react_1.default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none" },
534
+ react_1.default.createElement("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" }),
535
+ react_1.default.createElement("path", { d: "M19 10v2a7 7 0 01-14 0v-2M12 19v4M8 23h8", stroke: "#94a3b8", strokeWidth: "1.8", strokeLinecap: "round" }))))),
536
+ react_1.default.createElement("button", { type: "button", onClick: handleSend, disabled: (!text.trim() && !pendingAttach) || isPaused || isBlocked || isRecording, style: {
537
+ width: 36,
538
+ height: 36,
539
+ borderRadius: '50%',
540
+ backgroundColor: (text.trim() || pendingAttach) && !isPaused && !isBlocked ? config.primaryColor : '#e2e8f0',
541
+ border: 'none',
542
+ cursor: (text.trim() || pendingAttach) && !isPaused && !isBlocked ? 'pointer' : 'default',
543
+ display: 'flex',
544
+ alignItems: 'center',
545
+ justifyContent: 'center',
264
546
  flexShrink: 0,
265
- marginLeft: 4,
266
- }, children: [_jsx("span", { style: { fontSize: 10, color: 'rgba(255,255,255,0.85)', fontWeight: 600 }, children: "Sound" }), _jsx("button", { type: "button", role: "switch", "aria-checked": messageSoundEnabled, onClick: () => onToggleMessageSound(!messageSoundEnabled), style: {
267
- width: 36,
268
- height: 20,
269
- borderRadius: 10,
270
- border: 'none',
271
- background: messageSoundEnabled ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.2)',
272
- position: 'relative',
273
- cursor: 'pointer',
274
- padding: 0,
275
- }, children: _jsx("span", { style: {
276
- position: 'absolute',
277
- top: 2,
278
- left: messageSoundEnabled ? 18 : 2,
279
- width: 16,
280
- height: 16,
281
- borderRadius: '50%',
282
- background: '#fff',
283
- transition: 'left 0.15s ease',
284
- } }) })] })), 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: [navEntriesForChat(config.chatType, viewerIsDev).map(item => (_jsx(MenuItem, { icon: item.icon, label: item.label, onClick: () => { setShowMenu(false); onNavAction(item.key); } }, item.key))), _jsx("div", { style: { borderTop: '1px solid #f0f2f5', margin: '4px 0' } }), 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: [privacyEnabled && showPrivacy && (_jsxs("div", { style: {
285
- position: 'relative',
286
- marginBottom: 10,
287
- padding: '12px 36px 12px 12px',
288
- borderRadius: 12,
289
- background: '#fff',
290
- border: '1px solid #e8ecf1',
291
- boxShadow: '0 1px 4px rgba(15,23,42,0.06)',
292
- }, children: [_jsx("button", { type: "button", "aria-label": "Dismiss privacy notice", onClick: dismissPrivacy, style: {
293
- position: 'absolute',
294
- top: 8,
295
- right: 8,
296
- width: 26,
297
- height: 26,
298
- borderRadius: '50%',
299
- border: 'none',
300
- background: '#f1f5f9',
301
- cursor: 'pointer',
302
- display: 'flex',
303
- alignItems: 'center',
304
- justifyContent: 'center',
305
- padding: 0,
306
- lineHeight: 1,
307
- }, children: _jsx("span", { style: { fontSize: 14, color: '#475569', fontWeight: 700 }, children: "\u00D7" }) }), _jsxs("p", { style: { margin: 0, fontSize: 12, color: '#64748b', lineHeight: 1.55 }, children: ["By chatting here, you agree we and authorized partners may process, monitor, and record this chat and your data in line with", ' ', config.privacyPolicyUrl ? (_jsx("a", { href: config.privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", style: { color: config.primaryColor, textDecoration: 'underline', fontWeight: 600 }, children: "Privacy Policy" })) : (_jsx("span", { style: { textDecoration: 'underline', fontWeight: 600 }, children: "Privacy Policy" })), "."] })] })), showEmoji && config.allowEmoji && (_jsx(EmojiPicker, { primaryColor: config.primaryColor, onSelect: e => setText(t => t + e), onClose: () => setShowEmoji(false) })), isRecording && (_jsxs("div", { style: {
308
- marginBottom: 10,
309
- padding: '12px 12px 14px',
310
- background: '#fff',
311
- borderRadius: 14,
312
- border: '1px solid #e8ecf1',
313
- boxShadow: '0 1px 4px rgba(15,23,42,0.06)',
314
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 10, marginBottom: 10 }, children: [_jsx("button", { type: "button", onClick: cancelRecording, title: "Discard recording", "aria-label": "Discard recording", style: {
315
- background: 'none',
316
- border: 'none',
317
- cursor: 'pointer',
318
- padding: 6,
319
- lineHeight: 0,
320
- flexShrink: 0,
321
- }, children: _jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round" }), _jsx("path", { d: "M10 11v6M14 11v6", stroke: "#ef4444", strokeWidth: "2", strokeLinecap: "round" })] }) }), _jsx("div", { style: { display: 'flex', alignItems: 'flex-end', gap: 3, height: 44, flex: 1, justifyContent: 'flex-end', minWidth: 0 }, children: waveBars.map((h, i) => (_jsx("span", { style: {
322
- width: 3,
323
- borderRadius: 2,
324
- background: '#cbd5e1',
325
- height: `${8 + h * 36}px`,
326
- transition: 'height 0.05s ease-out',
327
- } }, i))) })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }, children: [_jsx("div", { style: { flex: 1 } }), _jsx("div", { style: {
328
- background: '#ef4444',
329
- color: '#fff',
330
- fontWeight: 700,
331
- fontSize: 13,
332
- padding: '6px 14px',
333
- borderRadius: 999,
334
- minWidth: 52,
335
- textAlign: 'center',
336
- }, children: fmtTime(recordSec) }), _jsx("button", { type: "button", onClick: stopRecordingSend, title: "Send voice message", "aria-label": "Send voice message", style: {
337
- width: 44,
338
- height: 44,
339
- borderRadius: '50%',
340
- border: 'none',
341
- background: config.primaryColor,
342
- cursor: 'pointer',
343
- display: 'flex',
344
- alignItems: 'center',
345
- justifyContent: 'center',
346
- flexShrink: 0,
347
- boxShadow: `0 4px 14px ${config.primaryColor}55`,
348
- }, children: _jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] })), _jsxs("div", { style: {
349
- border: `1.5px solid ${isPaused || isBlocked ? '#e5e7eb' : '#bfdbfe'}`,
350
- borderRadius: 16,
351
- padding: '10px 12px 8px',
352
- background: isPaused || isBlocked ? '#f9fafb' : '#fff',
353
- }, children: [pendingAttach && (_jsxs("div", { style: {
354
- display: 'flex',
355
- alignItems: 'center',
356
- gap: 10,
357
- marginBottom: 10,
358
- padding: '8px 10px',
359
- borderRadius: 10,
360
- background: '#f8fafc',
361
- border: '1px solid #fecaca',
362
- position: 'relative',
363
- }, children: [_jsx("div", { style: {
364
- width: 40,
365
- height: 40,
366
- borderRadius: 8,
367
- background: config.primaryColor,
368
- display: 'flex',
369
- alignItems: 'center',
370
- justifyContent: 'center',
371
- flexShrink: 0,
372
- }, 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: "#fff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 13, color: '#1a2332', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, title: pendingAttach.file.name, children: pendingAttach.file.name }), _jsx("div", { style: { fontSize: 11, color: '#94a3b8', fontWeight: 600, textTransform: 'uppercase' }, children: (pendingAttach.file.type.split('/')[1] || 'file').slice(0, 8) })] }), _jsx("button", { type: "button", onClick: () => clearPendingAttach(true), title: "Remove attachment", "aria-label": "Remove attachment", style: {
373
- position: 'absolute',
374
- top: 6,
375
- right: 6,
376
- width: 22,
377
- height: 22,
378
- borderRadius: '50%',
379
- border: 'none',
380
- background: '#ef4444',
381
- color: '#fff',
382
- cursor: 'pointer',
383
- fontSize: 15,
384
- fontWeight: 700,
385
- lineHeight: 1,
386
- display: 'flex',
387
- alignItems: 'center',
388
- justifyContent: 'center',
389
- padding: 0,
390
- }, children: "\u00D7" })] })), _jsx("textarea", { ref: inputRef, value: text, onChange: e => setText(e.target.value), onKeyDown: handleKey, onPaste: handlePaste, placeholder: isPaused || isBlocked ? 'Chat is unavailable' : 'Compose your message…', disabled: isPaused || isBlocked || isRecording, rows: 2, style: {
391
- width: '100%',
392
- resize: 'none',
393
- border: 'none',
394
- outline: 'none',
395
- fontSize: 14,
396
- lineHeight: 1.45,
397
- color: '#1a2332',
398
- background: 'transparent',
399
- maxHeight: 88,
400
- overflowY: 'auto',
401
- fontFamily: 'inherit',
402
- marginBottom: 8,
403
- } }), _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() && !pendingAttach) || isPaused || isBlocked || isRecording, style: {
404
- width: 36,
405
- height: 36,
406
- borderRadius: '50%',
407
- backgroundColor: (text.trim() || pendingAttach) && !isPaused && !isBlocked ? config.primaryColor : '#e2e8f0',
408
- border: 'none',
409
- cursor: (text.trim() || pendingAttach) && !isPaused && !isBlocked ? 'pointer' : 'default',
410
- display: 'flex',
411
- alignItems: 'center',
412
- justifyContent: 'center',
413
- flexShrink: 0,
414
- transition: 'background 0.15s',
415
- }, 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() || pendingAttach) && !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: {
416
- position: 'absolute',
417
- inset: 0,
418
- background: 'rgba(0,0,0,0.45)',
547
+ transition: 'background 0.15s',
548
+ }, title: "Send" },
549
+ react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none" },
550
+ react_1.default.createElement("path", { d: "M22 2L11 13M22 2L15 22L11 13L2 9L22 2Z", stroke: (text.trim() || pendingAttach) && !isPaused && !isBlocked ? '#fff' : '#94a3b8', strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }))))),
551
+ (config.footerPoweredBy || config.branch) && (react_1.default.createElement("p", { style: { margin: '10px 0 0', textAlign: 'center', fontSize: 12, color: '#94a3b8' } },
552
+ config.footerPoweredBy,
553
+ config.footerPoweredBy && config.branch ? ' · ' : '',
554
+ config.branch && react_1.default.createElement("span", { style: { fontWeight: 600, color: '#64748b' } }, config.branch)))),
555
+ transferOpen && otherDevelopers.length > 0 && onTransferToDeveloper && (react_1.default.createElement("div", { style: {
556
+ position: 'absolute',
557
+ inset: 0,
558
+ background: 'rgba(0,0,0,0.45)',
559
+ display: 'flex',
560
+ alignItems: 'center',
561
+ justifyContent: 'center',
562
+ zIndex: 280,
563
+ padding: 16,
564
+ } },
565
+ react_1.default.createElement("div", { style: {
566
+ background: '#fff',
567
+ borderRadius: 16,
568
+ padding: '18px 16px',
569
+ width: '100%',
570
+ maxWidth: 320,
571
+ maxHeight: '70%',
572
+ overflow: 'hidden',
419
573
  display: 'flex',
420
- alignItems: 'center',
421
- justifyContent: 'center',
422
- zIndex: 280,
423
- padding: 16,
424
- }, children: _jsxs("div", { style: {
425
- background: '#fff',
426
- borderRadius: 16,
427
- padding: '18px 16px',
574
+ flexDirection: 'column',
575
+ boxShadow: '0 16px 48px rgba(0,0,0,0.22)',
576
+ } },
577
+ react_1.default.createElement("div", { style: { fontWeight: 800, fontSize: 16, color: '#1a2332', marginBottom: 6 } }, "Transfer chat to"),
578
+ react_1.default.createElement("p", { style: { fontSize: 12, color: '#7b8fa1', margin: '0 0 12px', lineHeight: 1.5 } }, "Assign this conversation to another developer. History is kept and a handoff note is added."),
579
+ react_1.default.createElement("div", { className: "cw-scroll", style: { flex: 1, overflowY: 'auto', margin: '0 -4px' } }, otherDevelopers.map(dev => (react_1.default.createElement("button", { key: dev.uid, type: "button", onClick: () => {
580
+ onTransferToDeveloper(dev);
581
+ setTransferOpen(false);
582
+ }, style: {
428
583
  width: '100%',
429
- maxWidth: 320,
430
- maxHeight: '70%',
431
- overflow: 'hidden',
432
- display: 'flex',
433
- flexDirection: 'column',
434
- boxShadow: '0 16px 48px rgba(0,0,0,0.22)',
435
- }, 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: () => {
436
- onTransferToDeveloper(dev);
437
- setTransferOpen(false);
438
- }, style: {
439
- width: '100%',
440
- textAlign: 'left',
441
- padding: '12px 12px',
442
- marginBottom: 6,
443
- border: '1px solid #eef0f5',
444
- borderRadius: 12,
445
- background: '#f8fafc',
446
- cursor: 'pointer',
447
- fontSize: 14,
448
- fontWeight: 600,
449
- color: '#1e293b',
450
- }, 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: {
451
- marginTop: 12,
452
- padding: '10px',
453
- borderRadius: 10,
454
- border: '1.5px solid #e5e7eb',
455
- background: '#fff',
456
- fontWeight: 600,
457
- fontSize: 13,
458
- color: '#475569',
459
- cursor: 'pointer',
460
- }, children: "Cancel" })] }) })), showConfirm && (_jsx("div", { style: {
461
- position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.45)',
462
- display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 300,
463
- borderRadius: 'inherit',
464
- }, 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: {
465
- flex: 1, padding: '9px', borderRadius: 10, border: 'none',
466
- background: showConfirm === 'block' ? '#ef4444' : config.primaryColor,
467
- color: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 700,
468
- }, children: "Confirm" })] })] }) }))] }));
584
+ textAlign: 'left',
585
+ padding: '12px 12px',
586
+ marginBottom: 6,
587
+ border: '1px solid #eef0f5',
588
+ borderRadius: 12,
589
+ background: '#f8fafc',
590
+ cursor: 'pointer',
591
+ fontSize: 14,
592
+ fontWeight: 600,
593
+ color: '#1e293b',
594
+ } },
595
+ dev.name,
596
+ react_1.default.createElement("span", { style: { display: 'block', fontSize: 11, fontWeight: 500, color: '#64748b', marginTop: 2 } }, dev.designation))))),
597
+ react_1.default.createElement("button", { type: "button", onClick: () => setTransferOpen(false), style: {
598
+ marginTop: 12,
599
+ padding: '10px',
600
+ borderRadius: 10,
601
+ border: '1.5px solid #e5e7eb',
602
+ background: '#fff',
603
+ fontWeight: 600,
604
+ fontSize: 13,
605
+ color: '#475569',
606
+ cursor: 'pointer',
607
+ } }, "Cancel")))),
608
+ showConfirm && (react_1.default.createElement("div", { style: {
609
+ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.45)',
610
+ display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 300,
611
+ borderRadius: 'inherit',
612
+ } },
613
+ react_1.default.createElement("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' } },
614
+ react_1.default.createElement("div", { style: { fontWeight: 800, fontSize: 16, color: '#1a2332', marginBottom: 8 } },
615
+ showConfirm === 'pause' && (isPaused ? 'Resume Chat?' : 'Pause Chat?'),
616
+ showConfirm === 'report' && 'Report this chat?',
617
+ showConfirm === 'block' && 'Block this user?'),
618
+ react_1.default.createElement("p", { style: { fontSize: 13, color: '#7b8fa1', lineHeight: 1.6, margin: '0 0 18px' } },
619
+ showConfirm === 'pause' && (isPaused ? 'The user will be able to send messages again.' : 'The user will not be able to send new messages.'),
620
+ showConfirm === 'report' && 'This chat will be flagged for review by the admin team.',
621
+ showConfirm === 'block' && 'This user will be blocked and added to your block list. You can unblock them later.'),
622
+ react_1.default.createElement("div", { style: { display: 'flex', gap: 10 } },
623
+ react_1.default.createElement("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' } }, "Cancel"),
624
+ react_1.default.createElement("button", { type: "button", onClick: () => handleConfirm(showConfirm), style: {
625
+ flex: 1, padding: '9px', borderRadius: 10, border: 'none',
626
+ background: showConfirm === 'block' ? '#ef4444' : config.primaryColor,
627
+ color: '#fff', cursor: 'pointer', fontSize: 13, fontWeight: 700,
628
+ } }, "Confirm")))))));
469
629
  };
630
+ exports.ChatScreen = ChatScreen;
470
631
  const VoiceRow = ({ msg, isMe, primaryColor }) => {
471
632
  var _a;
472
- const audioRef = useRef(null);
473
- const [playing, setPlaying] = useState(false);
474
- const [current, setCurrent] = useState(0);
475
- const [dur, setDur] = useState((_a = msg.voiceDuration) !== null && _a !== void 0 ? _a : 0);
633
+ const audioRef = (0, react_1.useRef)(null);
634
+ const [playing, setPlaying] = (0, react_1.useState)(false);
635
+ const [current, setCurrent] = (0, react_1.useState)(0);
636
+ const [dur, setDur] = (0, react_1.useState)((_a = msg.voiceDuration) !== null && _a !== void 0 ? _a : 0);
476
637
  const url = msg.voiceUrl;
477
- useEffect(() => {
638
+ (0, react_1.useEffect)(() => {
478
639
  const a = audioRef.current;
479
640
  if (!a || !url)
480
641
  return;
@@ -502,64 +663,101 @@ const VoiceRow = ({ msg, isMe, primaryColor }) => {
502
663
  const pct = dur > 0 ? Math.min(100, (current / dur) * 100) : 0;
503
664
  const timeLabel = fmtTime(Math.floor(current)) + ' / ' + fmtTime(Math.floor(dur || msg.voiceDuration || 0));
504
665
  if (!url) {
505
- 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` : ''] })] }));
666
+ return (react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } },
667
+ react_1.default.createElement("span", { style: { fontSize: 13 } }, "\uD83C\uDFA4"),
668
+ react_1.default.createElement("span", { style: { fontSize: 13 } },
669
+ "Voice message",
670
+ msg.voiceDuration ? ` · ${msg.voiceDuration}s` : '')));
506
671
  }
507
- 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: {
508
- width: 36,
509
- height: 36,
510
- borderRadius: '50%',
511
- border: 'none',
512
- background: isMe ? 'rgba(255,255,255,0.95)' : '#fff',
513
- color: isMe ? primaryColor : primaryColor,
514
- cursor: 'pointer',
515
- display: 'flex',
516
- alignItems: 'center',
517
- justifyContent: 'center',
518
- flexShrink: 0,
519
- boxShadow: '0 1px 4px rgba(0,0,0,0.12)',
520
- }, "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 })] })] }));
672
+ return (react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, minWidth: 200 } },
673
+ url && (react_1.default.createElement("audio", { ref: audioRef, src: url, preload: "metadata", onPlay: () => setPlaying(true), onPause: () => setPlaying(false), onEnded: () => { setPlaying(false); setCurrent(0); } })),
674
+ react_1.default.createElement("button", { type: "button", onClick: toggle, style: {
675
+ width: 36,
676
+ height: 36,
677
+ borderRadius: '50%',
678
+ border: 'none',
679
+ background: isMe ? 'rgba(255,255,255,0.95)' : '#fff',
680
+ color: isMe ? primaryColor : primaryColor,
681
+ cursor: 'pointer',
682
+ display: 'flex',
683
+ alignItems: 'center',
684
+ justifyContent: 'center',
685
+ flexShrink: 0,
686
+ boxShadow: '0 1px 4px rgba(0,0,0,0.12)',
687
+ }, "aria-label": playing ? 'Pause' : 'Play' }, playing ? (react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" },
688
+ react_1.default.createElement("rect", { x: "6", y: "4", width: "4", height: "16" }),
689
+ react_1.default.createElement("rect", { x: "14", y: "4", width: "4", height: "16" }))) : (react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" },
690
+ react_1.default.createElement("path", { d: "M8 5v14l11-7z" })))),
691
+ react_1.default.createElement("div", { style: { flex: 1, minWidth: 0 } },
692
+ react_1.default.createElement("div", { style: { height: 4, borderRadius: 2, background: isMe ? 'rgba(255,255,255,0.35)' : '#e2e8f0', overflow: 'hidden' } },
693
+ react_1.default.createElement("div", { style: { width: `${pct}%`, height: '100%', background: isMe ? '#fff' : primaryColor, borderRadius: 2, transition: 'width 0.1s linear' } })),
694
+ react_1.default.createElement("div", { style: { fontSize: 11, marginTop: 4, opacity: 0.9 } }, timeLabel))));
521
695
  };
522
696
  const AttachmentRow = ({ msg, isMe, primaryColor }) => {
523
697
  var _a, _b;
524
698
  const name = (_a = msg.attachmentName) !== null && _a !== void 0 ? _a : 'File';
525
699
  const href = msg.attachmentUrl;
526
- const label = shortAttachmentLabel(name, 10);
700
+ const label = (0, fileName_1.shortAttachmentLabel)(name, 10);
527
701
  const mime = (_b = msg.attachmentMime) !== null && _b !== void 0 ? _b : '';
528
702
  const isImage = mime.startsWith('image/') || /\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(name);
529
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'stretch', gap: 8, flexWrap: 'wrap' }, children: [isImage && href && (_jsx("a", { href: href, download: name, title: name, style: { alignSelf: 'flex-start', lineHeight: 0 }, children: _jsx("img", { src: href, alt: "", style: { maxWidth: 220, maxHeight: 200, borderRadius: 10, objectFit: 'cover', display: 'block' } }) })), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10 }, children: [!isImage && (_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: [href ? (_jsxs("a", { href: href, download: name, title: name, style: {
530
- fontWeight: 700,
531
- fontSize: 14,
532
- wordBreak: 'break-word',
533
- color: isMe ? '#fff' : primaryColor,
534
- textDecoration: 'underline',
535
- }, children: ["[", label, "]"] })) : (_jsxs("div", { style: { fontWeight: 700, fontSize: 14, wordBreak: 'break-word' }, title: name, children: ["[", label, "]"] })), msg.attachmentSize && _jsx("div", { style: { fontSize: 11, opacity: 0.8 }, children: msg.attachmentSize })] })] })] }));
703
+ return (react_1.default.createElement("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'stretch', gap: 8, flexWrap: 'wrap' } },
704
+ isImage && href && (react_1.default.createElement("a", { href: href, download: name, title: name, style: { alignSelf: 'flex-start', lineHeight: 0 } },
705
+ react_1.default.createElement("img", { src: href, alt: "", style: { maxWidth: 220, maxHeight: 200, borderRadius: 10, objectFit: 'cover', display: 'block' } }))),
706
+ react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10 } },
707
+ !isImage && (react_1.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 } },
708
+ react_1.default.createElement("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" }))),
709
+ react_1.default.createElement("div", { style: { flex: 1, minWidth: 0 } },
710
+ href ? (react_1.default.createElement("a", { href: href, download: name, title: name, style: {
711
+ fontWeight: 700,
712
+ fontSize: 14,
713
+ wordBreak: 'break-word',
714
+ color: isMe ? '#fff' : primaryColor,
715
+ textDecoration: 'underline',
716
+ } },
717
+ "[",
718
+ label,
719
+ "]")) : (react_1.default.createElement("div", { style: { fontWeight: 700, fontSize: 14, wordBreak: 'break-word' }, title: name },
720
+ "[",
721
+ label,
722
+ "]")),
723
+ msg.attachmentSize && react_1.default.createElement("div", { style: { fontSize: 11, opacity: 0.8 } }, msg.attachmentSize)))));
536
724
  };
537
725
  const Bubble = ({ msg, primaryColor }) => {
538
726
  const isMe = msg.senderId === 'me';
539
727
  const caption = msg.text.trim();
540
- const content = msg.type === 'voice' ? (_jsx(VoiceRow, { msg: msg, isMe: isMe, primaryColor: primaryColor })) : msg.type === 'attachment' ? (_jsxs(_Fragment, { children: [_jsx(AttachmentRow, { msg: msg, isMe: isMe, primaryColor: primaryColor }), caption && caption !== ' ' && (_jsx("div", { style: { marginTop: 6, fontSize: 14, whiteSpace: 'pre-wrap', wordBreak: 'break-word' }, children: msg.text }))] })) : (_jsx("span", { children: msg.text }));
541
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: isMe ? 'flex-end' : 'flex-start', gap: 3 }, children: [_jsx("div", { style: {
542
- maxWidth: '85%', padding: '10px 13px',
543
- borderRadius: isMe ? '18px 18px 4px 18px' : '18px 18px 18px 4px',
544
- backgroundColor: isMe ? primaryColor : '#fff',
545
- color: isMe ? '#fff' : '#1a2332',
546
- fontSize: 14, lineHeight: 1.5,
547
- boxShadow: '0 1px 4px rgba(0,0,0,0.07)',
548
- wordBreak: 'break-word',
549
- }, children: content }), _jsx("span", { style: { fontSize: 11, color: '#b0bec5', padding: '0 4px' }, children: formatTime(msg.timestamp) })] }));
728
+ const content = msg.type === 'voice' ? (react_1.default.createElement(VoiceRow, { msg: msg, isMe: isMe, primaryColor: primaryColor })) : msg.type === 'attachment' ? (react_1.default.createElement(react_1.default.Fragment, null,
729
+ react_1.default.createElement(AttachmentRow, { msg: msg, isMe: isMe, primaryColor: primaryColor }),
730
+ caption && caption !== ' ' && (react_1.default.createElement("div", { style: { marginTop: 6, fontSize: 14, whiteSpace: 'pre-wrap', wordBreak: 'break-word' } }, msg.text)))) : (react_1.default.createElement("span", null, msg.text));
731
+ return (react_1.default.createElement("div", { style: { display: 'flex', flexDirection: 'column', alignItems: isMe ? 'flex-end' : 'flex-start', gap: 3 } },
732
+ react_1.default.createElement("div", { style: {
733
+ maxWidth: '85%', padding: '10px 13px',
734
+ borderRadius: isMe ? '18px 18px 4px 18px' : '18px 18px 18px 4px',
735
+ backgroundColor: isMe ? primaryColor : '#fff',
736
+ color: isMe ? '#fff' : '#1a2332',
737
+ fontSize: 14, lineHeight: 1.5,
738
+ boxShadow: '0 1px 4px rgba(0,0,0,0.07)',
739
+ wordBreak: 'break-word',
740
+ } }, content),
741
+ react_1.default.createElement("span", { style: { fontSize: 11, color: '#b0bec5', padding: '0 4px' } }, (0, chat_1.formatTime)(msg.timestamp))));
550
742
  };
551
- 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' } })] }));
552
- const MenuItem = ({ icon, label, onClick, danger }) => (_jsxs("button", { type: "button", onClick: onClick, style: {
743
+ const DateDivider = ({ label }) => (react_1.default.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, margin: '4px 0' } },
744
+ react_1.default.createElement("div", { style: { flex: 1, height: 1, background: '#e5e7eb' } }),
745
+ react_1.default.createElement("span", { style: { fontSize: 11, fontWeight: 600, color: '#64748b', whiteSpace: 'nowrap' } }, label),
746
+ react_1.default.createElement("div", { style: { flex: 1, height: 1, background: '#e5e7eb' } })));
747
+ const MenuItem = ({ icon, label, onClick, danger }) => (react_1.default.createElement("button", { type: "button", onClick: onClick, style: {
553
748
  display: 'flex', alignItems: 'center', gap: 10, width: '100%', padding: '9px 12px',
554
749
  background: 'none', border: 'none', borderRadius: 8, cursor: 'pointer', textAlign: 'left',
555
750
  fontSize: 13, fontWeight: 600, color: danger ? '#ef4444' : '#374151',
556
751
  transition: 'background 0.12s',
557
- }, onMouseEnter: e => e.currentTarget.style.background = danger ? '#fee2e2' : '#f3f4f6', onMouseLeave: e => e.currentTarget.style.background = 'none', children: [_jsx("span", { children: icon }), " ", label] }));
558
- const ActionBtn = ({ onClick, title, children }) => (_jsx("button", { type: "button", onClick: onClick, title: title, style: {
752
+ }, onMouseEnter: e => e.currentTarget.style.background = danger ? '#fee2e2' : '#f3f4f6', onMouseLeave: e => e.currentTarget.style.background = 'none' },
753
+ react_1.default.createElement("span", null, icon),
754
+ " ",
755
+ label));
756
+ const ActionBtn = ({ onClick, title, children }) => (react_1.default.createElement("button", { type: "button", onClick: onClick, title: title, style: {
559
757
  background: 'none', border: 'none', cursor: 'pointer', padding: '8px',
560
758
  borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
561
759
  transition: 'background 0.13s',
562
- }, onMouseEnter: e => e.currentTarget.style.background = '#f1f5f9', onMouseLeave: e => e.currentTarget.style.background = 'none', children: children }));
760
+ }, onMouseEnter: e => e.currentTarget.style.background = '#f1f5f9', onMouseLeave: e => e.currentTarget.style.background = 'none' }, children));
563
761
  const hdrBtn = {
564
762
  background: 'rgba(255,255,255,0.2)', border: 'none', borderRadius: '50%',
565
763
  width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
@@ -579,7 +777,7 @@ function navEntriesForChat(chatType, isStaff) {
579
777
  function groupByDate(messages) {
580
778
  const map = new Map();
581
779
  messages.forEach(m => {
582
- const d = formatDate(m.timestamp);
780
+ const d = (0, chat_1.formatDate)(m.timestamp);
583
781
  if (!map.has(d))
584
782
  map.set(d, []);
585
783
  map.get(d).push(m);
@@ -591,3 +789,4 @@ function fmtTime(sec) {
591
789
  const s = Math.max(0, sec % 60);
592
790
  return `${m}:${String(s).padStart(2, '0')}`;
593
791
  }
792
+ //# sourceMappingURL=index.js.map