ajaxter-chat 1.0.3 → 3.0.1

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 (75) hide show
  1. package/README.md +124 -241
  2. package/dist/components/BlockList/index.d.ts +10 -0
  3. package/dist/components/BlockList/index.js +33 -0
  4. package/dist/components/CallScreen/index.d.ts +13 -0
  5. package/dist/components/CallScreen/index.js +48 -0
  6. package/dist/components/ChatScreen/index.d.ts +19 -0
  7. package/dist/components/ChatScreen/index.js +168 -0
  8. package/dist/components/ChatWidget.d.ts +0 -24
  9. package/dist/components/ChatWidget.js +228 -43
  10. package/dist/components/EmojiPicker/index.d.ts +8 -0
  11. package/dist/components/EmojiPicker/index.js +18 -0
  12. package/dist/components/HomeScreen/index.d.ts +8 -0
  13. package/dist/components/HomeScreen/index.js +55 -0
  14. package/dist/components/MaintenanceView/index.d.ts +0 -1
  15. package/dist/components/MaintenanceView/index.js +13 -52
  16. package/dist/components/RecentChatsScreen/index.d.ts +17 -0
  17. package/dist/components/RecentChatsScreen/index.js +8 -0
  18. package/dist/components/Tabs/BottomTabs.d.ts +10 -0
  19. package/dist/components/Tabs/BottomTabs.js +34 -0
  20. package/dist/components/TicketScreen/index.d.ts +9 -0
  21. package/dist/components/TicketScreen/index.js +54 -0
  22. package/dist/components/UserListScreen/index.d.ts +11 -0
  23. package/dist/components/UserListScreen/index.js +35 -0
  24. package/dist/config/index.d.ts +3 -16
  25. package/dist/config/index.js +20 -103
  26. package/dist/hooks/useChat.d.ts +10 -9
  27. package/dist/hooks/useChat.js +22 -40
  28. package/dist/hooks/useRemoteConfig.d.ts +6 -0
  29. package/dist/hooks/useRemoteConfig.js +22 -0
  30. package/dist/hooks/useWebRTC.d.ts +11 -0
  31. package/dist/hooks/useWebRTC.js +112 -0
  32. package/dist/index.d.ts +16 -11
  33. package/dist/index.js +15 -16
  34. package/dist/types/index.d.ts +66 -38
  35. package/dist/utils/chat.d.ts +13 -0
  36. package/dist/utils/chat.js +62 -0
  37. package/dist/utils/theme.d.ts +3 -2
  38. package/dist/utils/theme.js +13 -21
  39. package/package.json +10 -20
  40. package/public/chatData.json +162 -0
  41. package/src/components/BlockList/index.tsx +94 -0
  42. package/src/components/CallScreen/index.tsx +144 -0
  43. package/src/components/ChatScreen/index.tsx +469 -0
  44. package/src/components/ChatWidget.tsx +471 -0
  45. package/src/components/EmojiPicker/index.tsx +48 -0
  46. package/src/components/HomeScreen/index.tsx +106 -0
  47. package/src/components/MaintenanceView/index.tsx +38 -0
  48. package/src/components/RecentChatsScreen/index.tsx +63 -0
  49. package/src/components/Tabs/BottomTabs.tsx +90 -0
  50. package/src/components/TicketScreen/index.tsx +124 -0
  51. package/src/components/UserListScreen/index.tsx +103 -0
  52. package/src/config/index.ts +40 -0
  53. package/src/hooks/useChat.ts +48 -0
  54. package/src/hooks/useRemoteConfig.ts +20 -0
  55. package/src/hooks/useWebRTC.ts +130 -0
  56. package/src/index.ts +29 -0
  57. package/src/types/index.ts +127 -0
  58. package/src/utils/chat.ts +70 -0
  59. package/src/utils/theme.ts +27 -0
  60. package/dist/components/BottomNav/index.d.ts +0 -10
  61. package/dist/components/BottomNav/index.js +0 -32
  62. package/dist/components/ChatBox/index.d.ts +0 -15
  63. package/dist/components/ChatBox/index.js +0 -228
  64. package/dist/components/ChatButton/index.d.ts +0 -9
  65. package/dist/components/ChatButton/index.js +0 -17
  66. package/dist/components/ChatWindow/index.d.ts +0 -10
  67. package/dist/components/ChatWindow/index.js +0 -286
  68. package/dist/components/HomeView/index.d.ts +0 -12
  69. package/dist/components/HomeView/index.js +0 -51
  70. package/dist/components/UserList/index.d.ts +0 -13
  71. package/dist/components/UserList/index.js +0 -136
  72. package/dist/hooks/useUsers.d.ts +0 -14
  73. package/dist/hooks/useUsers.js +0 -32
  74. package/dist/services/userService.d.ts +0 -7
  75. package/dist/services/userService.js +0 -18
@@ -0,0 +1,94 @@
1
+ import React from 'react';
2
+ import { ChatUser, WidgetConfig } from '../../types';
3
+ import { avatarColor, initials } from '../../utils/chat';
4
+
5
+ interface BlockListScreenProps {
6
+ blockedUsers: ChatUser[];
7
+ config: WidgetConfig;
8
+ onUnblock: (uid: string) => void;
9
+ onBack: () => void;
10
+ }
11
+
12
+ export const BlockListScreen: React.FC<BlockListScreenProps> = ({
13
+ blockedUsers, config, onUnblock, onBack,
14
+ }) => (
15
+ <div style={{ display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease' }}>
16
+ {/* Header */}
17
+ <div style={{
18
+ background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
19
+ padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0,
20
+ }}>
21
+ <button onClick={onBack} style={backBtnStyle}>
22
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
23
+ <path d="M19 12H5M5 12L12 19M5 12L12 5" stroke="#fff" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
24
+ </svg>
25
+ </button>
26
+ <div>
27
+ <div style={{ fontWeight: 700, fontSize: 16, color: '#fff' }}>Block List</div>
28
+ <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.8)' }}>
29
+ {blockedUsers.length} blocked user{blockedUsers.length !== 1 ? 's' : ''}
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <div style={{ flex: 1, overflowY: 'auto' }}>
35
+ {blockedUsers.length === 0 ? (
36
+ <div style={{ padding: '50px 24px', textAlign: 'center' }}>
37
+ <div style={{ fontSize: 36, marginBottom: 10 }}>✅</div>
38
+ <div style={{ fontWeight: 700, color: '#1a2332', marginBottom: 6 }}>No blocked users</div>
39
+ <div style={{ fontSize: 13, color: '#7b8fa1' }}>Users you block will appear here</div>
40
+ </div>
41
+ ) : (
42
+ blockedUsers.map((user, i) => (
43
+ <div key={user.uid} style={{
44
+ padding: '13px 16px', display: 'flex', alignItems: 'center', gap: 13,
45
+ borderBottom: '1px solid #f0f2f5',
46
+ animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s`,
47
+ }}>
48
+ <div style={{
49
+ width: 44, height: 44, borderRadius: '50%',
50
+ backgroundColor: avatarColor(user.name),
51
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
52
+ color: '#fff', fontWeight: 700, fontSize: 14, flexShrink: 0,
53
+ filter: 'grayscale(0.6)', opacity: 0.7,
54
+ }}>
55
+ {initials(user.name)}
56
+ </div>
57
+ <div style={{ flex: 1, minWidth: 0 }}>
58
+ <div style={{ fontWeight: 700, fontSize: 14, color: '#6b7280' }}>{user.name}</div>
59
+ <div style={{ fontSize: 12, color: '#9ca3af', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
60
+ {user.email}
61
+ </div>
62
+ </div>
63
+ <button
64
+ onClick={() => onUnblock(user.uid)}
65
+ style={{
66
+ padding: '6px 14px', borderRadius: 20,
67
+ border: `1.5px solid ${config.primaryColor}`,
68
+ background: 'transparent', color: config.primaryColor,
69
+ fontSize: 12, fontWeight: 700, cursor: 'pointer',
70
+ transition: 'all 0.15s', flexShrink: 0,
71
+ }}
72
+ onMouseEnter={e => {
73
+ (e.currentTarget as HTMLElement).style.background = config.primaryColor;
74
+ (e.currentTarget as HTMLElement).style.color = '#fff';
75
+ }}
76
+ onMouseLeave={e => {
77
+ (e.currentTarget as HTMLElement).style.background = 'transparent';
78
+ (e.currentTarget as HTMLElement).style.color = config.primaryColor;
79
+ }}
80
+ >
81
+ Unblock
82
+ </button>
83
+ </div>
84
+ ))
85
+ )}
86
+ </div>
87
+ </div>
88
+ );
89
+
90
+ const backBtnStyle: React.CSSProperties = {
91
+ background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
92
+ width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
93
+ cursor: 'pointer', flexShrink: 0,
94
+ };
@@ -0,0 +1,144 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { CallSession, ChatUser } from '../../types';
3
+ import { avatarColor, initials } from '../../utils/chat';
4
+
5
+ interface CallScreenProps {
6
+ session: CallSession;
7
+ localVideoRef: React.RefObject<HTMLVideoElement | null>;
8
+ remoteVideoRef: React.RefObject<HTMLVideoElement | null>;
9
+ onEnd: () => void;
10
+ onToggleMute: () => void;
11
+ onToggleCamera: () => void;
12
+ primaryColor: string;
13
+ }
14
+
15
+ export const CallScreen: React.FC<CallScreenProps> = ({
16
+ session, localVideoRef, remoteVideoRef,
17
+ onEnd, onToggleMute, onToggleCamera, primaryColor,
18
+ }) => {
19
+ const [duration, setDuration] = useState(0);
20
+ const peer = session.peer as ChatUser;
21
+
22
+ useEffect(() => {
23
+ if (session.state !== 'connected' || !session.startedAt) return;
24
+ const t = setInterval(() => {
25
+ setDuration(Math.floor((Date.now() - session.startedAt!.getTime()) / 1000));
26
+ }, 1000);
27
+ return () => clearInterval(t);
28
+ }, [session.state, session.startedAt]);
29
+
30
+ const mins = String(Math.floor(duration / 60)).padStart(2, '0');
31
+ const secs = String(duration % 60).padStart(2, '0');
32
+
33
+ return (
34
+ <div style={{
35
+ display:'flex', flexDirection:'column', height:'100%',
36
+ background: session.isCameraOn ? '#000' : `linear-gradient(145deg,${primaryColor}dd,#0f172a)`,
37
+ color:'#fff', animation:'cw-slideIn 0.22s ease',
38
+ position:'relative', overflow:'hidden',
39
+ }}>
40
+ {/* Remote video (background) */}
41
+ <video ref={remoteVideoRef} autoPlay playsInline
42
+ style={{ position:'absolute', inset:0, width:'100%', height:'100%', objectFit:'cover', opacity: session.state==='connected'?1:0 }}
43
+ />
44
+
45
+ {/* Local video (PiP) */}
46
+ <video ref={localVideoRef} autoPlay playsInline muted
47
+ style={{
48
+ position:'absolute', bottom:120, right:14,
49
+ width:90, height:120, borderRadius:10,
50
+ objectFit:'cover', border:'2px solid rgba(255,255,255,0.3)',
51
+ display: session.isCameraOn ? 'block' : 'none',
52
+ zIndex:10,
53
+ }}
54
+ />
55
+
56
+ {/* Overlay */}
57
+ <div style={{ position:'relative', zIndex:5, display:'flex', flexDirection:'column', height:'100%', background:'rgba(0,0,0,0.35)' }}>
58
+ {/* Top bar */}
59
+ <div style={{ padding:'16px 18px', display:'flex', alignItems:'center', gap:10 }}>
60
+ <div style={{ flex:1 }}>
61
+ <div style={{ fontWeight:700, fontSize:15, color:'#fff' }}>
62
+ {session.state === 'calling' && 'Calling...'}
63
+ {session.state === 'connected' && 'Connected'}
64
+ {session.state === 'ended' && 'Call Ended'}
65
+ </div>
66
+ </div>
67
+ </div>
68
+
69
+ {/* Center: avatar + name */}
70
+ <div style={{ flex:1, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:16 }}>
71
+ {peer && (
72
+ <>
73
+ <div style={{
74
+ width:90, height:90, borderRadius:'50%',
75
+ backgroundColor: avatarColor(peer.name),
76
+ display:'flex', alignItems:'center', justifyContent:'center',
77
+ fontSize:28, fontWeight:700, color:'#fff',
78
+ boxShadow:'0 0 0 4px rgba(255,255,255,0.2)',
79
+ animation: session.state==='calling' ? 'cw-pulse 1.5s ease infinite' : 'none',
80
+ }}>
81
+ {initials(peer.name)}
82
+ </div>
83
+ <div style={{ textAlign:'center' }}>
84
+ <div style={{ fontSize:20, fontWeight:800 }}>{peer.name}</div>
85
+ <div style={{ fontSize:13, opacity:0.8, marginTop:4 }}>
86
+ {session.state === 'calling' && 'Ringing...'}
87
+ {session.state === 'connected' && `${mins}:${secs}`}
88
+ {session.state === 'ended' && 'Call ended'}
89
+ </div>
90
+ </div>
91
+ </>
92
+ )}
93
+ </div>
94
+
95
+ {/* Controls */}
96
+ <div style={{ padding:'24px', display:'flex', justifyContent:'center', alignItems:'center', gap:20 }}>
97
+ {/* Mute */}
98
+ <CallBtn
99
+ active={session.isMuted}
100
+ activeColor="#374151"
101
+ onClick={onToggleMute}
102
+ title={session.isMuted ? 'Unmute' : 'Mute'}
103
+ >
104
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
105
+ {session.isMuted
106
+ ? <><path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z" stroke="#fff" strokeWidth="2"/><line x1="1" y1="1" x2="23" y2="23" stroke="#ef4444" strokeWidth="2"/></>
107
+ : <><path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z" stroke="#fff" strokeWidth="2" strokeLinecap="round"/><path d="M19 10v2a7 7 0 01-14 0v-2M12 19v4" stroke="#fff" strokeWidth="2" strokeLinecap="round"/></>
108
+ }
109
+ </svg>
110
+ </CallBtn>
111
+
112
+ {/* End call */}
113
+ <button onClick={onEnd} style={{
114
+ width:60, height:60, borderRadius:'50%', backgroundColor:'#ef4444',
115
+ border:'none', cursor:'pointer', display:'flex', alignItems:'center', justifyContent:'center',
116
+ boxShadow:'0 4px 16px rgba(239,68,68,0.5)', flexShrink:0,
117
+ }}>
118
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
119
+ <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" transform="rotate(135 12 12)"/>
120
+ </svg>
121
+ </button>
122
+
123
+ {/* Camera */}
124
+ <CallBtn active={session.isCameraOn} activeColor={primaryColor} onClick={onToggleCamera} title="Camera">
125
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
126
+ <path d="M23 7l-7 5 7 5V7zM1 5h13a2 2 0 012 2v10a2 2 0 01-2 2H1a2 2 0 01-2-2V7a2 2 0 012-2z" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
127
+ </svg>
128
+ </CallBtn>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ );
133
+ };
134
+
135
+ const CallBtn: React.FC<{ active: boolean; activeColor: string; onClick: () => void; title: string; children: React.ReactNode }> = ({
136
+ active, activeColor, onClick, title, children,
137
+ }) => (
138
+ <button onClick={onClick} title={title} style={{
139
+ width:50, height:50, borderRadius:'50%',
140
+ backgroundColor: active ? activeColor : 'rgba(255,255,255,0.2)',
141
+ border:'none', cursor:'pointer',
142
+ display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0,
143
+ }}>{children}</button>
144
+ );