ajaxter-chat 3.0.9 → 3.0.11

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.
@@ -23,7 +23,9 @@ export const HomeScreen = ({ config, onNavigate, onOpenTicket, tickets }) => {
23
23
  return;
24
24
  window.location.href = `tel:${raw.replace(/\s/g, '')}`;
25
25
  };
26
- 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, viewerType: (_d = config.viewerType) !== null && _d !== void 0 ? _d : 'user', onSelect: onNavigate }), _jsx("div", { style: {
26
+ 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, viewerType: (_d = config.viewerType) !== null && _d !== void 0 ? _d : 'user', onSelect: ctx => {
27
+ onNavigate(ctx, { fromMenu: true });
28
+ } }), _jsx("div", { style: {
27
29
  flexShrink: 0,
28
30
  padding: '14px 16px 10px',
29
31
  display: 'flex',
@@ -51,7 +53,7 @@ export const HomeScreen = ({ config, onNavigate, onOpenTicket, tickets }) => {
51
53
  color: '#0f172a',
52
54
  letterSpacing: '-0.03em',
53
55
  lineHeight: 1.2,
54
- }, 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: pendingTickets.length > 0 ? (pendingTickets.map(t => (_jsxs("button", { type: "button", onClick: () => onOpenTicket(t.id), style: {
56
+ }, 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 with tickets" }), _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 28 }, children: pendingTickets.length > 0 ? (pendingTickets.map(t => (_jsxs("button", { type: "button", onClick: () => onOpenTicket(t.id), style: {
55
57
  width: '100%',
56
58
  textAlign: 'left',
57
59
  padding: '14px 16px',
@@ -75,7 +77,7 @@ export const HomeScreen = ({ config, onNavigate, onOpenTicket, tickets }) => {
75
77
  color: '#64748b',
76
78
  fontSize: 14,
77
79
  fontWeight: 500,
78
- }, children: "Start via Raise ticket below" })] })) }), _jsx("h2", { style: { margin: '0 0 12px', fontSize: 15, fontWeight: 800, color: '#0f172a' }, children: viewerIsDev ? 'Support tools' : 'Talk to our experts' }), showSupport && (_jsxs("button", { type: "button", onClick: () => onNavigate('support'), style: {
80
+ }, children: "Start via Raise ticket below" })] })) }), _jsx("h2", { style: { margin: '0 0 12px', fontSize: 15, fontWeight: 800, color: '#0f172a' }, children: viewerIsDev ? 'Support tools' : 'Talk to support experts' }), showSupport && (_jsxs("button", { type: "button", onClick: () => onNavigate('support'), style: {
79
81
  width: '100%',
80
82
  display: 'flex',
81
83
  alignItems: 'center',
@@ -149,5 +151,5 @@ export const HomeScreen = ({ config, onNavigate, onOpenTicket, tickets }) => {
149
151
  fontSize: 14,
150
152
  fontWeight: 700,
151
153
  cursor: config.supportPhone ? 'pointer' : 'not-allowed',
152
- }, 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"] })] })] })] })] }));
154
+ }, 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" }) }), "Get Free Widget"] })] })] })] })] }));
153
155
  };
@@ -12,6 +12,7 @@ interface RecentChatsScreenProps {
12
12
  chats: RecentChat[];
13
13
  config: WidgetConfig;
14
14
  onSelectChat: (user: ChatUser) => void;
15
+ animateEntrance?: boolean;
15
16
  }
16
17
  export declare const RecentChatsScreen: React.FC<RecentChatsScreenProps>;
17
18
  export {};
@@ -1,8 +1,30 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useMemo, useRef, useEffect } from 'react';
2
3
  import { avatarColor, initials, formatTime } from '../../utils/chat';
3
- export const RecentChatsScreen = ({ chats, config, onSelectChat }) => (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: { background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`, padding: '18px 18px 22px', flexShrink: 0 }, children: [_jsx("h2", { style: { margin: 0, fontSize: 20, fontWeight: 800, color: '#fff', letterSpacing: '-0.02em' }, children: "Recent Chats" }), _jsx("p", { style: { margin: '3px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: "Your conversation history" })] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: chats.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\uD83D\uDCAC" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No chats yet" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Start a conversation from home" })] })) : chats.map((chat, i) => (_jsxs("button", { onClick: () => onSelectChat(chat.user), style: {
4
- width: '100%', padding: '13px 16px', display: 'flex', alignItems: 'center', gap: 13,
5
- background: 'transparent', border: 'none', borderBottom: '1px solid #f0f2f5',
6
- cursor: 'pointer', textAlign: 'left', animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s`,
7
- transition: 'background 0.14s',
8
- }, onMouseEnter: e => e.currentTarget.style.background = '#f8faff', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: { position: 'relative', flexShrink: 0 }, children: [_jsx("div", { style: { width: 46, height: 46, borderRadius: '50%', backgroundColor: avatarColor(chat.user.name), display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontWeight: 700, fontSize: 15 }, children: initials(chat.user.name) }), chat.unread > 0 && (_jsx("span", { style: { position: 'absolute', top: -2, right: -2, width: 18, height: 18, borderRadius: '50%', background: '#ef4444', color: '#fff', fontSize: 10, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', border: '2px solid #fff' }, children: chat.unread }))] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: 3 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: 14, color: '#1a2332' }, children: chat.user.name }), _jsx("span", { style: { fontSize: 11, color: '#b0bec5' }, children: formatTime(chat.lastTime) })] }), _jsxs("div", { style: { fontSize: 13, color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'flex', alignItems: 'center', gap: 5 }, children: [chat.isPaused && _jsx("span", { style: { fontSize: 10, background: '#fef3c7', color: '#92400e', padding: '1px 5px', borderRadius: 4, fontWeight: 700 }, children: "PAUSED" }), chat.lastMessage] })] })] }, chat.id))) })] }));
4
+ function matchesChat(chat, q) {
5
+ if (!q.trim())
6
+ return true;
7
+ const s = q.trim().toLowerCase();
8
+ return (chat.user.name.toLowerCase().includes(s) ||
9
+ chat.lastMessage.toLowerCase().includes(s));
10
+ }
11
+ export const RecentChatsScreen = ({ chats, config, onSelectChat, animateEntrance = false, }) => {
12
+ const [query, setQuery] = useState('');
13
+ const searchRef = useRef(null);
14
+ useEffect(() => {
15
+ var _a;
16
+ (_a = searchRef.current) === null || _a === void 0 ? void 0 : _a.focus();
17
+ }, []);
18
+ const filtered = useMemo(() => chats.filter(c => matchesChat(c, query)), [chats, query]);
19
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsxs("div", { style: { background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`, padding: '18px 18px 14px', flexShrink: 0 }, children: [_jsx("h2", { style: { margin: 0, fontSize: 20, fontWeight: 800, color: '#fff', letterSpacing: '-0.02em' }, children: "Recent Chats" }), _jsx("p", { style: { margin: '3px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: "Your conversation history" })] }), _jsx("div", { style: { padding: '10px 14px', background: '#fff', borderBottom: '1px solid #eef0f5', flexShrink: 0 }, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px', borderRadius: 10, border: '1.5px solid #e5e7eb', background: '#f8fafc' }, children: [_jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0, opacity: 0.55 }, children: [_jsx("circle", { cx: "11", cy: "11", r: "7", stroke: "#64748b", strokeWidth: "2" }), _jsx("path", { d: "M20 20l-4-4", stroke: "#64748b", strokeWidth: "2", strokeLinecap: "round" })] }), _jsx("input", { ref: searchRef, type: "search", value: query, onChange: e => setQuery(e.target.value), placeholder: "Search chats\u2026", autoComplete: "off", "aria-label": "Search chats", style: {
20
+ flex: 1,
21
+ minWidth: 0,
22
+ border: 'none',
23
+ outline: 'none',
24
+ background: 'transparent',
25
+ fontSize: 14,
26
+ padding: '10px 0',
27
+ fontFamily: 'inherit',
28
+ color: '#1a2332',
29
+ } })] }) }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: filtered.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: query.trim() ? '🔍' : '💬' }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: query.trim() ? 'No matches' : 'No chats yet' }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: query.trim() ? 'Try a different search' : 'Start a conversation from home' })] })) : filtered.map((chat, i) => (_jsxs("button", { onClick: () => onSelectChat(chat.user), style: Object.assign(Object.assign({ width: '100%', padding: '13px 16px', display: 'flex', alignItems: 'center', gap: 13, background: 'transparent', border: 'none', borderBottom: '1px solid #f0f2f5', cursor: 'pointer', textAlign: 'left' }, (animateEntrance ? { animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s` } : {})), { transition: 'background 0.14s' }), onMouseEnter: e => e.currentTarget.style.background = '#f8faff', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: { position: 'relative', flexShrink: 0 }, children: [_jsx("div", { style: { width: 46, height: 46, borderRadius: '50%', backgroundColor: avatarColor(chat.user.name), display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', fontWeight: 700, fontSize: 15 }, children: initials(chat.user.name) }), chat.unread > 0 && (_jsx("span", { style: { position: 'absolute', top: -2, right: -2, width: 18, height: 18, borderRadius: '50%', background: '#ef4444', color: '#fff', fontSize: 10, fontWeight: 700, display: 'flex', alignItems: 'center', justifyContent: 'center', border: '2px solid #fff' }, children: chat.unread }))] }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', marginBottom: 3 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: 14, color: '#1a2332' }, children: chat.user.name }), _jsx("span", { style: { fontSize: 11, color: '#b0bec5' }, children: formatTime(chat.lastTime) })] }), _jsxs("div", { style: { fontSize: 13, color: '#7b8fa1', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'flex', alignItems: 'center', gap: 5 }, children: [chat.isPaused && _jsx("span", { style: { fontSize: 10, background: '#fef3c7', color: '#92400e', padding: '1px 5px', borderRadius: 4, fontWeight: 700 }, children: "PAUSED" }), chat.lastMessage] })] })] }, chat.id))) })] }));
30
+ };
@@ -28,7 +28,7 @@ export const TicketFormScreen = ({ config, onSubmit, onCancel }) => {
28
28
  return;
29
29
  onSubmit(title.trim(), desc.trim(), priority);
30
30
  };
31
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', background: '#fff' }, children: [_jsxs("div", { style: {
31
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', background: '#fff', minHeight: 0 }, children: [_jsxs("div", { style: {
32
32
  background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
33
33
  padding: '14px 18px',
34
34
  display: 'flex',
@@ -45,7 +45,7 @@ export const TicketFormScreen = ({ config, onSubmit, onCancel }) => {
45
45
  alignItems: 'center',
46
46
  justifyContent: 'center',
47
47
  cursor: 'pointer',
48
- }, children: _jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: 18, fontWeight: 800, color: '#fff' }, children: "New ticket" }), _jsx("p", { style: { margin: '4px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.85)' }, children: "Describe your issue below" })] })] }), _jsxs("div", { className: "cw-scroll", style: { flex: 1, overflowY: 'auto', padding: '20px 18px' }, children: [_jsx("input", { placeholder: "Title *", value: title, onChange: e => setTitle(e.target.value), style: inputStyle(config.primaryColor), onFocus: e => (e.target.style.borderColor = config.primaryColor), onBlur: e => (e.target.style.borderColor = '#e5e7eb') }), _jsx("textarea", { placeholder: "Describe the issue\u2026", value: desc, onChange: e => setDesc(e.target.value), rows: 5, style: Object.assign(Object.assign({}, inputStyle(config.primaryColor)), { resize: 'none', marginTop: 12 }), onFocus: e => (e.target.style.borderColor = config.primaryColor), onBlur: e => (e.target.style.borderColor = '#e5e7eb') }), _jsx("div", { style: { display: 'flex', gap: 8, marginTop: 12, marginBottom: 20 }, children: ['low', 'medium', 'high'].map(p => (_jsx("button", { type: "button", onClick: () => setPriority(p), style: {
48
+ }, children: _jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: _jsx("path", { d: "M19 12H5M5 12L12 19M5 12L12 5", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: 18, fontWeight: 800, color: '#fff' }, children: "Raise a ticket" }), _jsx("p", { style: { margin: '4px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.85)' }, children: "Please fill out the ticket form below and we will get back to you as soon as possible." })] })] }), _jsxs("div", { className: "cw-scroll", style: { flex: 1, overflowY: 'auto', padding: '20px 18px', minHeight: 0 }, children: [_jsx("input", { placeholder: "Title *", value: title, onChange: e => setTitle(e.target.value), style: inputStyle(config.primaryColor), onFocus: e => (e.target.style.borderColor = config.primaryColor), onBlur: e => (e.target.style.borderColor = '#e5e7eb') }), _jsx("textarea", { placeholder: "Describe the issue\u2026", value: desc, onChange: e => setDesc(e.target.value), rows: 5, style: Object.assign(Object.assign({}, inputStyle(config.primaryColor)), { resize: 'none', marginTop: 12 }), onFocus: e => (e.target.style.borderColor = config.primaryColor), onBlur: e => (e.target.style.borderColor = '#e5e7eb') }), _jsx("div", { style: { display: 'flex', gap: 8, marginTop: 12, paddingBottom: 8 }, children: ['low', 'medium', 'high'].map(p => (_jsx("button", { type: "button", onClick: () => setPriority(p), style: {
49
49
  flex: 1,
50
50
  padding: '8px',
51
51
  border: `1.5px solid ${priority === p ? pm[p].color : '#e5e7eb'}`,
@@ -56,15 +56,21 @@ export const TicketFormScreen = ({ config, onSubmit, onCancel }) => {
56
56
  fontSize: 12,
57
57
  cursor: 'pointer',
58
58
  textTransform: 'capitalize',
59
- }, children: pm[p].label }, p))) }), _jsx("button", { type: "button", onClick: handleSubmit, disabled: !title.trim(), style: {
60
- width: '100%',
61
- padding: '12px',
62
- borderRadius: 10,
63
- border: 'none',
64
- background: title.trim() ? config.primaryColor : '#e5e7eb',
65
- color: title.trim() ? '#fff' : '#9ca3af',
66
- fontWeight: 700,
67
- fontSize: 15,
68
- cursor: title.trim() ? 'pointer' : 'not-allowed',
69
- }, children: "Submit ticket" })] })] }));
59
+ }, children: pm[p].label }, p))) })] }), _jsx("div", { style: {
60
+ flexShrink: 0,
61
+ padding: '12px 18px 18px',
62
+ borderTop: '1px solid #eef0f5',
63
+ background: '#fff',
64
+ boxShadow: '0 -4px 20px rgba(15,23,42,0.06)',
65
+ }, children: _jsx("button", { type: "button", onClick: handleSubmit, disabled: !title.trim(), style: {
66
+ width: '100%',
67
+ padding: '14px',
68
+ borderRadius: 10,
69
+ border: 'none',
70
+ background: title.trim() ? config.primaryColor : '#e5e7eb',
71
+ color: title.trim() ? '#fff' : '#9ca3af',
72
+ fontWeight: 700,
73
+ fontSize: 15,
74
+ cursor: title.trim() ? 'pointer' : 'not-allowed',
75
+ }, children: "Submit ticket" }) })] }));
70
76
  };
@@ -5,6 +5,7 @@ interface TicketScreenProps {
5
5
  config: WidgetConfig;
6
6
  onNewTicket: () => void;
7
7
  onSelectTicket: (id: string) => void;
8
+ animateEntrance?: boolean;
8
9
  }
9
10
  export declare const TicketScreen: React.FC<TicketScreenProps>;
10
11
  export {};
@@ -1,5 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export const TicketScreen = ({ tickets, config, onNewTicket, onSelectTicket }) => {
2
+ import { useState, useMemo, useRef, useEffect } from 'react';
3
+ function matchesTicket(t, q) {
4
+ if (!q.trim())
5
+ return true;
6
+ const s = q.trim().toLowerCase();
7
+ return (t.title.toLowerCase().includes(s) ||
8
+ t.description.toLowerCase().includes(s) ||
9
+ t.id.toLowerCase().includes(s));
10
+ }
11
+ export const TicketScreen = ({ tickets, config, onNewTicket, onSelectTicket, animateEntrance = false, }) => {
12
+ const [query, setQuery] = useState('');
13
+ const searchRef = useRef(null);
14
+ useEffect(() => {
15
+ var _a;
16
+ (_a = searchRef.current) === null || _a === void 0 ? void 0 : _a.focus();
17
+ }, []);
18
+ const filtered = useMemo(() => tickets.filter(t => matchesTicket(t, query)), [tickets, query]);
3
19
  const sm = {
4
20
  open: { label: 'Open', bg: `${config.primaryColor}14`, color: config.primaryColor },
5
21
  'in-progress': { label: 'In Progress', bg: '#fef3c7', color: '#d97706' },
@@ -13,15 +29,21 @@ export const TicketScreen = ({ tickets, config, onNewTicket, onSelectTicket }) =
13
29
  };
14
30
  return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' }, children: [_jsx("div", { style: {
15
31
  background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
16
- padding: '18px 18px 22px', flexShrink: 0, position: 'relative',
17
- }, children: _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }, children: [_jsxs("div", { children: [_jsx("h2", { style: { margin: 0, fontSize: 20, fontWeight: 800, color: '#fff', letterSpacing: '-0.02em' }, children: "Tickets" }), _jsxs("p", { style: { margin: '3px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: [tickets.length, " ticket", tickets.length !== 1 ? 's' : '', " raised"] })] }), _jsx("button", { type: "button", onClick: onNewTicket, style: {
32
+ padding: '18px 18px 14px', flexShrink: 0, position: 'relative',
33
+ }, children: _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }, children: [_jsxs("div", { style: { minWidth: 0 }, children: [_jsx("h2", { style: { margin: 0, fontSize: 20, fontWeight: 800, color: '#fff', letterSpacing: '-0.02em' }, children: "Tickets" }), _jsxs("p", { style: { margin: '3px 0 0', fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: [tickets.length, " ticket", tickets.length !== 1 ? 's' : '', " raised"] })] }), _jsx("button", { type: "button", onClick: onNewTicket, style: {
18
34
  background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: 20,
19
35
  padding: '7px 14px', color: '#fff', fontWeight: 700, fontSize: 13,
20
36
  cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 5,
21
- }, children: "+ New" })] }) }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: tickets.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\uD83C\uDFAB" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No tickets yet" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Raise a ticket for major issues" })] })) : tickets.map((t, i) => (_jsxs("button", { type: "button", onClick: () => onSelectTicket(t.id), style: {
22
- width: '100%', padding: '14px 16px', borderBottom: '1px solid #f0f2f5',
23
- animation: `cw-fadeUp 0.3s ease both`, animationDelay: `${i * 0.05}s`,
24
- background: 'transparent', borderLeft: 'none', borderRight: 'none', borderTop: 'none',
25
- cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit',
26
- }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 5 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: 14, color: '#1a2332', flex: 1, paddingRight: 10 }, children: t.title }), _jsx("span", { style: { fontSize: 10, fontWeight: 700, padding: '3px 9px', borderRadius: 20, backgroundColor: sm[t.status].bg, color: sm[t.status].color, whiteSpace: 'nowrap', textTransform: 'uppercase', letterSpacing: '0.04em', flexShrink: 0 }, children: sm[t.status].label })] }), t.description && _jsx("p", { style: { margin: '0 0 7px', fontSize: 13, color: '#7b8fa1', lineHeight: 1.5 }, children: t.description }), _jsxs("div", { style: { display: 'flex', gap: 10, fontSize: 11, color: '#b0bec5' }, children: [_jsxs("span", { style: { color: pm[t.priority].color, fontWeight: 700 }, children: ["\u25CF ", pm[t.priority].label] }), _jsxs("span", { children: ["#", t.id] }), _jsx("span", { children: new Date(t.createdAt).toLocaleDateString([], { month: 'short', day: 'numeric' }) })] })] }, t.id))) })] }));
37
+ flexShrink: 0,
38
+ }, children: "+ New" })] }) }), _jsx("div", { style: { padding: '10px 14px', background: '#fff', borderBottom: '1px solid #eef0f5', flexShrink: 0 }, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px', borderRadius: 10, border: '1.5px solid #e5e7eb', background: '#f8fafc' }, children: [_jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0, opacity: 0.55 }, children: [_jsx("circle", { cx: "11", cy: "11", r: "7", stroke: "#64748b", strokeWidth: "2" }), _jsx("path", { d: "M20 20l-4-4", stroke: "#64748b", strokeWidth: "2", strokeLinecap: "round" })] }), _jsx("input", { ref: searchRef, type: "search", value: query, onChange: e => setQuery(e.target.value), placeholder: "Search tickets\u2026", autoComplete: "off", "aria-label": "Search tickets", style: {
39
+ flex: 1,
40
+ minWidth: 0,
41
+ border: 'none',
42
+ outline: 'none',
43
+ background: 'transparent',
44
+ fontSize: 14,
45
+ padding: '10px 0',
46
+ fontFamily: 'inherit',
47
+ color: '#1a2332',
48
+ } })] }) }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: filtered.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: query.trim() ? '🔍' : '🎫' }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: query.trim() ? 'No matches' : 'No tickets yet' }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: query.trim() ? 'Try a different search' : 'Raise a ticket for major issues' })] })) : filtered.map((t, i) => (_jsxs("button", { type: "button", onClick: () => onSelectTicket(t.id), style: Object.assign(Object.assign({ width: '100%', padding: '14px 16px', borderBottom: '1px solid #f0f2f5' }, (animateEntrance ? { animation: `cw-fadeUp 0.3s ease both`, animationDelay: `${i * 0.05}s` } : {})), { background: 'transparent', borderLeft: 'none', borderRight: 'none', borderTop: 'none', cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit' }), children: [_jsxs("div", { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 5 }, children: [_jsx("span", { style: { fontWeight: 700, fontSize: 14, color: '#1a2332', flex: 1, paddingRight: 10 }, children: t.title }), _jsx("span", { style: { fontSize: 10, fontWeight: 700, padding: '3px 9px', borderRadius: 20, backgroundColor: sm[t.status].bg, color: sm[t.status].color, whiteSpace: 'nowrap', textTransform: 'uppercase', letterSpacing: '0.04em', flexShrink: 0 }, children: sm[t.status].label })] }), t.description && _jsx("p", { style: { margin: '0 0 7px', fontSize: 13, color: '#7b8fa1', lineHeight: 1.5 }, children: t.description }), _jsxs("div", { style: { display: 'flex', gap: 10, fontSize: 11, color: '#b0bec5' }, children: [_jsxs("span", { style: { color: pm[t.priority].color, fontWeight: 700 }, children: ["\u25CF ", pm[t.priority].label] }), _jsxs("span", { children: ["#", t.id] }), _jsx("span", { children: new Date(t.createdAt).toLocaleDateString([], { month: 'short', day: 'numeric' }) })] })] }, t.id))) })] }));
27
49
  };
@@ -10,6 +10,10 @@ interface UserListScreenProps {
10
10
  onSelectUser: (user: ChatUser) => void;
11
11
  /** Shown on “New Conversation” list — opens block list */
12
12
  onBlockList?: () => void;
13
+ /** “Need Support” (user → agents): show home icon instead of back arrow */
14
+ useHomeHeader?: boolean;
15
+ /** Stagger animation — only when opening from home burger menu */
16
+ animateEntrance?: boolean;
13
17
  }
14
18
  export declare const UserListScreen: React.FC<UserListScreenProps>;
15
19
  export {};
@@ -1,6 +1,23 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useMemo, useRef, useEffect } from 'react';
2
3
  import { avatarColor, initials } from '../../utils/chat';
3
- export const UserListScreen = ({ context, users, primaryColor, viewerType = 'user', onBack, onSelectUser, onBlockList, }) => {
4
+ function matchesUser(u, q) {
5
+ if (!q.trim())
6
+ return true;
7
+ const s = q.trim().toLowerCase();
8
+ return (u.name.toLowerCase().includes(s) ||
9
+ u.email.toLowerCase().includes(s) ||
10
+ u.designation.toLowerCase().includes(s) ||
11
+ u.project.toLowerCase().includes(s));
12
+ }
13
+ export const UserListScreen = ({ context, users, primaryColor, viewerType = 'user', onBack, onSelectUser, onBlockList, useHomeHeader = false, animateEntrance = false, }) => {
14
+ const [query, setQuery] = useState('');
15
+ const searchRef = useRef(null);
16
+ useEffect(() => {
17
+ var _a;
18
+ (_a = searchRef.current) === null || _a === void 0 ? void 0 : _a.focus();
19
+ }, []);
20
+ const filtered = useMemo(() => users.filter(u => matchesUser(u, query)), [users, query]);
4
21
  const isStaff = viewerType === 'developer';
5
22
  const title = context === 'support'
6
23
  ? (isStaff ? 'Provide Support' : 'Need Support')
@@ -8,7 +25,8 @@ export const UserListScreen = ({ context, users, primaryColor, viewerType = 'use
8
25
  const subtitle = context === 'support'
9
26
  ? (isStaff ? 'All chat users — choose who to help' : 'Choose a support agent')
10
27
  : (isStaff ? 'Chat with another developer or coordinate handoff' : 'Choose a colleague');
11
- return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease' }, children: [_jsxs("div", { style: { background: `linear-gradient(135deg,${primaryColor},${primaryColor}cc)`, padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0, position: 'relative' }, children: [_jsx(BackBtn, { onClick: onBack }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 16, color: '#fff' }, children: title }), _jsx("div", { style: { fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: subtitle })] }), context === 'conversation' && onBlockList && (_jsxs("button", { type: "button", onClick: onBlockList, style: {
28
+ const rootAnim = animateEntrance ? 'cw-slideIn 0.22s ease' : undefined;
29
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: rootAnim }, children: [_jsxs("div", { style: { background: `linear-gradient(135deg,${primaryColor},${primaryColor}cc)`, padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0, position: 'relative' }, children: [useHomeHeader ? _jsx(HomeBtn, { onClick: onBack }) : _jsx(BackBtn, { onClick: onBack }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 16, color: '#fff' }, children: title }), _jsx("div", { style: { fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: subtitle })] }), context === 'conversation' && onBlockList && (_jsxs("button", { type: "button", onClick: onBlockList, style: {
12
30
  flexShrink: 0,
13
31
  background: 'rgba(255,255,255,0.2)',
14
32
  border: 'none',
@@ -21,14 +39,19 @@ export const UserListScreen = ({ context, users, primaryColor, viewerType = 'use
21
39
  display: 'flex',
22
40
  alignItems: 'center',
23
41
  gap: 6,
24
- }, title: "Blocked users", children: [_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "1.8" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })] }), "Blocked"] }))] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: users.length === 0 ? (_jsx(Empty, {})) : users.map((u, i) => (_jsxs("button", { onClick: () => onSelectUser(u), style: {
25
- width: '100%', padding: '13px 18px', display: 'flex',
26
- alignItems: 'center', gap: 13, background: 'transparent',
27
- border: 'none', borderBottom: '1px solid #f0f2f5',
28
- cursor: 'pointer', textAlign: 'left',
29
- animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s`,
30
- transition: 'background 0.14s',
31
- }, onMouseEnter: e => e.currentTarget.style.background = '#f8faff', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: { position: 'relative', flexShrink: 0 }, children: [_jsx("div", { style: {
42
+ }, title: "Blocked users", children: [_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "1.8" }), _jsx("line", { x1: "4.93", y1: "4.93", x2: "19.07", y2: "19.07", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })] }), "Blocked"] }))] }), _jsx("div", { style: { padding: '10px 14px', background: '#fff', borderBottom: '1px solid #eef0f5', flexShrink: 0 }, children: _jsxs("label", { style: { display: 'block', margin: 0 }, children: [_jsx("span", { style: { position: 'absolute', width: 1, height: 1, padding: 0, overflow: 'hidden', clip: 'rect(0,0,0,0)' }, children: "Search" }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px', borderRadius: 10, border: '1.5px solid #e5e7eb', background: '#f8fafc' }, children: [_jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0, opacity: 0.55 }, children: [_jsx("circle", { cx: "11", cy: "11", r: "7", stroke: "#64748b", strokeWidth: "2" }), _jsx("path", { d: "M20 20l-4-4", stroke: "#64748b", strokeWidth: "2", strokeLinecap: "round" })] }), _jsx("input", { ref: searchRef, type: "search", value: query, onChange: e => setQuery(e.target.value), placeholder: "Search by name\u2026", autoComplete: "off", style: {
43
+ flex: 1,
44
+ minWidth: 0,
45
+ border: 'none',
46
+ outline: 'none',
47
+ background: 'transparent',
48
+ fontSize: 14,
49
+ padding: '10px 0',
50
+ fontFamily: 'inherit',
51
+ color: '#1a2332',
52
+ } })] })] }) }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: filtered.length === 0 ? (_jsx(Empty, { hasQuery: !!query.trim() })) : filtered.map((u, i) => (_jsxs("button", { onClick: () => onSelectUser(u), style: Object.assign(Object.assign({ width: '100%', padding: '13px 18px', display: 'flex', alignItems: 'center', gap: 13, background: 'transparent', border: 'none', borderBottom: '1px solid #f0f2f5', cursor: 'pointer', textAlign: 'left' }, (animateEntrance
53
+ ? { animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s` }
54
+ : {})), { transition: 'background 0.14s' }), onMouseEnter: e => e.currentTarget.style.background = '#f8faff', onMouseLeave: e => e.currentTarget.style.background = 'transparent', children: [_jsxs("div", { style: { position: 'relative', flexShrink: 0 }, children: [_jsx("div", { style: {
32
55
  width: 44, height: 44, borderRadius: '50%',
33
56
  backgroundColor: avatarColor(u.name),
34
57
  display: 'flex', alignItems: 'center', justifyContent: 'center',
@@ -45,9 +68,14 @@ export const UserListScreen = ({ context, users, primaryColor, viewerType = 'use
45
68
  border: `1px solid ${u.type === 'developer' ? primaryColor + '30' : '#16a34a30'}`,
46
69
  }, children: u.type === 'developer' ? 'Dev' : 'User' })] }, u.uid))) })] }));
47
70
  };
48
- const BackBtn = ({ onClick }) => (_jsx("button", { onClick: onClick, style: {
71
+ const BackBtn = ({ onClick }) => (_jsx("button", { type: "button", onClick: onClick, style: {
49
72
  background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
50
73
  width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
51
74
  cursor: 'pointer', flexShrink: 0,
52
75
  }, 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" }) }) }));
53
- const Empty = () => (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\uD83D\uDC65" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No users available" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Check back later" })] }));
76
+ const HomeBtn = ({ onClick }) => (_jsx("button", { type: "button", onClick: onClick, title: "Home", "aria-label": "Home", style: {
77
+ background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
78
+ width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
79
+ cursor: 'pointer', flexShrink: 0,
80
+ }, children: _jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [_jsx("path", { d: "M3 9.5L12 3l9 6.5V20a1 1 0 01-1 1H4a1 1 0 01-1-1V9.5z", stroke: "#fff", strokeWidth: "2.2", fill: "none", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M9 21V12h6v9", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }));
81
+ const Empty = ({ hasQuery }) => (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: hasQuery ? '🔍' : '👥' }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: hasQuery ? 'No matches' : 'No users available' }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: hasQuery ? 'Try a different search' : 'Check back later' })] }));
@@ -81,6 +81,8 @@ export interface ChatMessage {
81
81
  attachmentSize?: string;
82
82
  /** Blob URL for attachment download (local send) */
83
83
  attachmentUrl?: string;
84
+ /** e.g. image/png — used for inline image preview in bubbles */
85
+ attachmentMime?: string;
84
86
  voiceDuration?: number;
85
87
  /** Blob URL for in-bubble audio playback (local recording) */
86
88
  voiceUrl?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ajaxter-chat",
3
- "version": "3.0.9",
3
+ "version": "3.0.11",
4
4
  "description": "Drawer-based chat widget with support chat, tickets, WebRTC calling, voice messages, block list, and transcript download.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",