ajaxter-chat 2.0.1 → 3.0.3

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 (94) hide show
  1. package/README.md +119 -128
  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 +10 -3
  7. package/dist/components/ChatScreen/index.js +142 -57
  8. package/dist/components/ChatWidget.js +192 -98
  9. package/dist/components/EmojiPicker/index.d.ts +8 -0
  10. package/dist/components/EmojiPicker/index.js +18 -0
  11. package/dist/components/HomeScreen/index.d.ts +2 -3
  12. package/dist/components/HomeScreen/index.js +25 -41
  13. package/dist/components/MaintenanceView/index.d.ts +0 -1
  14. package/dist/components/MaintenanceView/index.js +4 -6
  15. package/dist/components/RecentChatsScreen/index.d.ts +4 -3
  16. package/dist/components/RecentChatsScreen/index.js +7 -37
  17. package/dist/components/Tabs/BottomTabs.d.ts +1 -1
  18. package/dist/components/Tabs/BottomTabs.js +25 -20
  19. package/dist/components/TicketScreen/index.d.ts +3 -3
  20. package/dist/components/TicketScreen/index.js +39 -56
  21. package/dist/components/UserListScreen/index.d.ts +2 -4
  22. package/dist/components/UserListScreen/index.js +33 -62
  23. package/dist/config/index.d.ts +7 -3
  24. package/dist/config/index.js +28 -25
  25. package/dist/hooks/useChat.d.ts +8 -3
  26. package/dist/hooks/useChat.js +22 -18
  27. package/dist/hooks/useRemoteConfig.d.ts +6 -0
  28. package/dist/hooks/useRemoteConfig.js +26 -0
  29. package/dist/hooks/useWebRTC.d.ts +11 -0
  30. package/dist/hooks/useWebRTC.js +112 -0
  31. package/dist/index.d.ts +9 -5
  32. package/dist/index.js +8 -4
  33. package/dist/types/index.d.ts +62 -21
  34. package/dist/utils/chat.d.ts +13 -0
  35. package/dist/utils/chat.js +62 -0
  36. package/dist/utils/theme.d.ts +3 -1
  37. package/dist/utils/theme.js +14 -7
  38. package/package.json +4 -4
  39. package/public/chatData.json +162 -0
  40. package/src/components/BlockList/index.tsx +94 -0
  41. package/src/components/CallScreen/index.tsx +144 -0
  42. package/src/components/ChatScreen/index.tsx +403 -139
  43. package/src/components/ChatWidget.tsx +394 -250
  44. package/src/components/EmojiPicker/index.tsx +48 -0
  45. package/src/components/HomeScreen/index.tsx +58 -82
  46. package/src/components/MaintenanceView/index.tsx +6 -9
  47. package/src/components/RecentChatsScreen/index.tsx +51 -96
  48. package/src/components/Tabs/BottomTabs.tsx +45 -37
  49. package/src/components/TicketScreen/index.tsx +87 -133
  50. package/src/components/UserListScreen/index.tsx +75 -153
  51. package/src/config/index.ts +32 -26
  52. package/src/hooks/useChat.ts +31 -14
  53. package/src/hooks/useRemoteConfig.ts +26 -0
  54. package/src/hooks/useWebRTC.ts +130 -0
  55. package/src/index.ts +26 -15
  56. package/src/types/index.ts +85 -40
  57. package/src/utils/chat.ts +70 -0
  58. package/src/utils/theme.ts +18 -7
  59. package/dist/hooks/useUsers.d.ts +0 -7
  60. package/dist/hooks/useUsers.js +0 -26
  61. package/dist/services/userService.d.ts +0 -2
  62. package/dist/services/userService.js +0 -9
  63. package/dist/src/components/ChatScreen/index.d.ts +0 -12
  64. package/dist/src/components/ChatScreen/index.js +0 -83
  65. package/dist/src/components/ChatWidget.d.ts +0 -4
  66. package/dist/src/components/ChatWidget.js +0 -141
  67. package/dist/src/components/HomeScreen/index.d.ts +0 -9
  68. package/dist/src/components/HomeScreen/index.js +0 -71
  69. package/dist/src/components/MaintenanceView/index.d.ts +0 -7
  70. package/dist/src/components/MaintenanceView/index.js +0 -16
  71. package/dist/src/components/RecentChatsScreen/index.d.ts +0 -16
  72. package/dist/src/components/RecentChatsScreen/index.js +0 -38
  73. package/dist/src/components/Tabs/BottomTabs.d.ts +0 -10
  74. package/dist/src/components/Tabs/BottomTabs.js +0 -29
  75. package/dist/src/components/TicketScreen/index.d.ts +0 -9
  76. package/dist/src/components/TicketScreen/index.js +0 -71
  77. package/dist/src/components/UserListScreen/index.d.ts +0 -13
  78. package/dist/src/components/UserListScreen/index.js +0 -64
  79. package/dist/src/config/index.d.ts +0 -3
  80. package/dist/src/config/index.js +0 -38
  81. package/dist/src/hooks/useChat.d.ts +0 -8
  82. package/dist/src/hooks/useChat.js +0 -26
  83. package/dist/src/hooks/useUsers.d.ts +0 -7
  84. package/dist/src/hooks/useUsers.js +0 -26
  85. package/dist/src/index.d.ts +0 -14
  86. package/dist/src/index.js +0 -13
  87. package/dist/src/services/userService.d.ts +0 -2
  88. package/dist/src/services/userService.js +0 -9
  89. package/dist/src/types/index.d.ts +0 -59
  90. package/dist/src/types/index.js +0 -1
  91. package/dist/src/utils/theme.d.ts +0 -3
  92. package/dist/src/utils/theme.js +0 -13
  93. package/src/hooks/useUsers.ts +0 -27
  94. package/src/services/userService.ts +0 -9
package/README.md CHANGED
@@ -1,82 +1,71 @@
1
- # react-chat-widget-extension v2
1
+ # react-chat-widget-extension v3
2
2
 
3
- A drop-in floating chat widget for **React.js** and **Next.js** with a multi-screen UI, ticket system, and full theme control.
3
+ A production-ready **drawer/slider-based** chat widget for React.js and Next.js.
4
+ All configuration is loaded remotely from your hosted `chatData.json`.
4
5
 
5
6
  ---
6
7
 
7
- ## Screens & Navigation Flow
8
-
9
- ```
10
- Floating Button
11
- └── Opens Widget Window
12
- ├── [Home Screen] ← default on open
13
- │ ├── Need Support → [User List Screen: developers] → [Chat Screen]
14
- │ ├── New Convo → [User List Screen: users] → [Chat Screen]
15
- │ └── Raise Ticket → [Ticket Screen] (always shown)
16
-
17
- ├── [Bottom Tab: Home] ← Home screen
18
- ├── [Bottom Tab: Chats] ← Recent conversations list
19
- └── [Bottom Tab: Tickets] ← All raised tickets + new ticket form
20
- ```
21
-
22
- ---
23
-
24
- ## Environment Variables
8
+ ## Setup (2 env vars only)
25
9
 
26
10
  ### React (.env)
27
11
  ```env
28
- REACT_APP_CHAT_HOST_URL=http://your-api.com
29
- REACT_APP_CHAT_HOST_PORT=4000 # Optional — omit to use URL default port
30
- REACT_APP_CHAT_USER_LIST=api/v1/users
31
- REACT_APP_CHAT_STATUS=ACTIVE # ACTIVE | DISABLE | MAINTENANCE
32
- REACT_APP_CHAT_TYPE=BOTH # SUPPORT | CHAT | BOTH
12
+ REACT_APP_CHAT_API_KEY=demo1234
13
+ REACT_APP_CHAT_WIDGET_ID=demo
33
14
  ```
34
15
 
35
16
  ### Next.js (.env.local)
36
17
  ```env
37
- NEXT_PUBLIC_CHAT_HOST_URL=http://your-api.com
38
- NEXT_PUBLIC_CHAT_HOST_PORT=4000 # Optional
39
- NEXT_PUBLIC_CHAT_USER_LIST=api/v1/users
40
- NEXT_PUBLIC_CHAT_STATUS=ACTIVE
41
- NEXT_PUBLIC_CHAT_TYPE=BOTH
18
+ NEXT_PUBLIC_CHAT_API_KEY=demo1234
19
+ NEXT_PUBLIC_CHAT_WIDGET_ID=demo
42
20
  ```
43
21
 
44
22
  ---
45
23
 
46
- ## CHAT_STATUS Behaviour
47
-
48
- | Value | Behaviour |
49
- |---------------|--------------------------------------------------------|
50
- | `ACTIVE` | Widget fully enabled |
51
- | `DISABLE` | Widget **not rendered at all** — zero DOM footprint |
52
- | `MAINTENANCE` | Widget opens but shows a maintenance message |
53
-
54
- ---
55
-
56
- ## CHAT_TYPE Behaviour
57
-
58
- | Value | Home Cards Shown | User List Filter |
59
- |-----------|-------------------------------------|-------------------|
60
- | `SUPPORT` | Need Support only | `type=developer` |
61
- | `CHAT` | New Conversation only | `type=user` |
62
- | `BOTH` | Both cards | Per card clicked |
24
+ ## Remote Config URL
63
25
 
64
- > **Raise Ticket is always shown regardless of CHAT_TYPE.**
26
+ The widget fetches all config from:
27
+ ```
28
+ GET https://window.mscorpres.com/TEST/chatData.json
29
+ ```
30
+ With headers:
31
+ ```
32
+ X-Chat-Api-Key: demo1234
33
+ X-Chat-Widget-Id: demo
34
+ ```
65
35
 
66
36
  ---
67
37
 
68
- ## User List API
38
+ ## chatData.json Schema
69
39
 
70
- ```
71
- GET {CHAT_HOST_URL}[:{CHAT_HOST_PORT}]/{CHAT_USER_LIST}
72
- ```
40
+ Host this file at the URL above:
73
41
 
74
- Expected response:
75
42
  ```json
76
- [
77
- { "name": "Alice", "uid": "u1", "email": "alice@co.com", "mobile": "", "project": "Platform", "type": "developer" },
78
- { "name": "Bob", "uid": "u2", "email": "bob@co.com", "mobile": "", "project": "Portal", "type": "user" }
79
- ]
43
+ {
44
+ "widget": {
45
+ "id": "demo",
46
+ "apiKey": "demo1234",
47
+ "status": "ACTIVE",
48
+ "chatType": "BOTH",
49
+ "primaryColor": "#2563EB",
50
+ "buttonLabel": "Support",
51
+ "buttonPosition": "bottom-right",
52
+ "welcomeTitle": "Hi there 👋",
53
+ "welcomeSubtitle": "Need help? Start a conversation:",
54
+ "allowVoiceMessage": true,
55
+ "allowAttachment": true,
56
+ "allowEmoji": true,
57
+ "allowWebCall": true,
58
+ "maxEmojiCount": 20,
59
+ "allowTranscriptDownload": true,
60
+ "allowReport": true,
61
+ "allowBlock": true
62
+ },
63
+ "developers": [ { "uid":"dev_001","name":"...","type":"developer","status":"online", ... } ],
64
+ "users": [ { "uid":"usr_001","name":"...","type":"user","status":"online", ... } ],
65
+ "sampleChats": { "dev_001": [ { "id":"msg_001","senderId":"me","text":"Hi!","type":"text", ... } ] },
66
+ "sampleTickets": [ { "id":"TKT-0001","title":"...","status":"open","priority":"high", ... } ],
67
+ "blockedUsers": []
68
+ }
80
69
  ```
81
70
 
82
71
  ---
@@ -85,111 +74,113 @@ Expected response:
85
74
 
86
75
  ### React
87
76
  ```tsx
88
- // App.tsx
89
77
  import { ChatWidget } from 'react-chat-widget-extension';
90
-
91
78
  export default function App() {
92
- return (
93
- <>
94
- <main>Your app</main>
95
- <ChatWidget
96
- theme={{
97
- primaryColor: '#1aaa96',
98
- buttonLabel: 'Chat with us',
99
- buttonPosition: 'bottom-right',
100
- }}
101
- />
102
- </>
103
- );
79
+ return <><main>App</main><ChatWidget /></>;
104
80
  }
105
81
  ```
106
82
 
107
- ### Next.js App Router
83
+ ### Next.js App Router
108
84
  ```tsx
109
85
  // app/ChatWidgetWrapper.tsx
110
86
  'use client';
111
87
  import { ChatWidget } from 'react-chat-widget-extension';
112
- export function ChatWidgetWrapper() {
113
- return <ChatWidget theme={{ primaryColor: '#1aaa96' }} />;
114
- }
88
+ export function ChatWidgetWrapper() { return <ChatWidget />; }
115
89
 
116
90
  // app/layout.tsx
117
91
  import { ChatWidgetWrapper } from './ChatWidgetWrapper';
118
- export default function RootLayout({ children }) {
92
+ export default function Layout({ children }) {
119
93
  return <html><body>{children}<ChatWidgetWrapper /></body></html>;
120
94
  }
121
95
  ```
122
96
 
123
- ### Next.js Pages Router
97
+ ### Next.js Pages Router
124
98
  ```tsx
125
99
  // pages/_app.tsx
126
100
  import { ChatWidget } from 'react-chat-widget-extension';
127
101
  export default function MyApp({ Component, pageProps }) {
128
- return <><Component {...pageProps} /><ChatWidget theme={{ primaryColor: '#1aaa96' }} /></>;
102
+ return <><Component {...pageProps}/><ChatWidget /></>;
129
103
  }
130
104
  ```
131
105
 
132
106
  ---
133
107
 
134
- ## Theme Props (all optional)
135
-
136
- | Prop | Type | Default | Description |
137
- |-------------------|------------------------------------|----------------------------------|--------------------------------------|
138
- | `primaryColor` | `string` | `'#1aaa96'` | Header, active states, send button |
139
- | `buttonColor` | `string` | `'#1aaa96'` | Floating button background |
140
- | `buttonTextColor` | `string` | `'#ffffff'` | Floating button text/icon |
141
- | `buttonLabel` | `string` | `'Chat with us'` | Floating button label |
142
- | `buttonPosition` | `'bottom-right' \| 'bottom-left'` | `'bottom-right'` | Floating button corner |
143
- | `fontFamily` | `string` | `"'DM Sans', 'Segoe UI', ..."` | Font used across the widget |
144
- | `borderRadius` | `string` | `'16px'` | Widget panel corner radius |
145
- | `backgroundColor` | `string` | `'#ffffff'` | Widget panel background |
146
-
147
- ---
148
-
149
- ## Folder Structure
150
-
151
- ```
152
- src/
153
- ├── index.ts ← Public API exports
154
- ├── types/index.ts ← All TypeScript types
155
- ├── config/index.ts ← Env loader (NEXT_PUBLIC_ + REACT_APP_)
156
- ├── services/userService.ts ← fetch() user list API
157
- ├── hooks/
158
- │ ├── useUsers.ts ← Fetch & filter users
159
- │ └── useChat.ts ← Message state, WebSocket-ready
160
- ├── utils/theme.ts ← defaultTheme + mergeTheme
161
- └── components/
162
- ├── ChatWidget.tsx ← 🏠 Root — mount this in your app
163
- ├── HomeScreen/ ← Hi there + option cards
164
- ├── UserListScreen/ ← Slide-in user picker
165
- ├── ChatScreen/ ← Conversation + input bar
166
- ├── RecentChatsScreen/ ← Bottom tab: Chats
167
- ├── TicketScreen/ ← Bottom tab: Tickets + raise form
168
- ├── MaintenanceView/ ← Shown when MAINTENANCE
169
- └── Tabs/BottomTabs.tsx ← Home / Chats / Tickets tabs
170
- ```
108
+ ## Features
109
+
110
+ | Feature | Details |
111
+ |---|---|
112
+ | **Drawer/Slider UI** | Slides in from right (or left) with smooth animation. Backdrop closes it. |
113
+ | **Home Screen** | "Hi there 👋" hero, cards for Support / New Conversation / Raise Ticket |
114
+ | **User List** | Slide-in panel with online status dot, designation, project |
115
+ | **Chat Screen** | Matches the UI image hamburger back, title "Support", phone + fullscreen icons |
116
+ | **Enter Your Details** | Blue card at top of chat (ticket chat body placeholder) |
117
+ | **Voice Messages** | Record via MediaRecorder API, shows duration |
118
+ | **Attachments** | File picker, shows filename + size as message |
119
+ | **Emoji Picker** | 20 curated emojis, limited count via `maxEmojiCount` |
120
+ | **Pause Chat** | Developer can pause — user cannot send messages |
121
+ | **Resume Chat** | One-click resume from banner or menu |
122
+ | **Report Chat** | Flags chat, shows warning banner |
123
+ | **Block User** | Blocks users only (not developers), with confirm dialog |
124
+ | **Block List Tab** | View all blocked users, one-click unblock |
125
+ | **Download Transcript** | Saves plain-text .txt file of full conversation |
126
+ | **WebRTC Calls** | Secure P2P voice/video call with mute + camera toggle |
127
+ | **Ticket Screen** | Raise tickets with title, description, priority selector |
128
+ | **Ticket History** | Shows all tickets with status badge and priority color |
129
+ | **Recent Chats Tab** | Shows past conversations with unread badges |
130
+ | **Maximize/Minimize** | Toggle drawer width 380px ↔ 480px |
131
+ | **Slide Close** | Smooth slide-out animation on close |
132
+ | **SSR Safe** | isMounted guard, works in Next.js App Router and Pages Router |
133
+ | **CHAT_STATUS** | ACTIVE / DISABLE / MAINTENANCE handled |
171
134
 
172
135
  ---
173
136
 
174
137
  ## WebSocket Integration Points
175
138
 
176
- Look for `// TODO:` comments in `src/hooks/useChat.ts`:
177
-
139
+ In `src/hooks/useChat.ts` — find the `// TODO:` comments:
178
140
  ```ts
179
- // In selectUser — connect and listen:
180
- // socket.emit('join', user.uid);
181
- // socket.on('message', (msg) => setMessages(prev => [...prev, msg]));
141
+ // In selectUser:
142
+ // socket.emit('join', { roomId: user.uid });
143
+ // socket.on('message', msg => setMessages(prev => [...prev, msg]));
182
144
 
183
- // In sendMessage — emit outgoing:
184
- // socket.emit('message', newMsg);
145
+ // In sendMessage:
146
+ // socket.emit('message', msg);
185
147
  ```
186
148
 
187
- ---
149
+ In `src/hooks/useWebRTC.ts` — find the `// TODO:` comments:
150
+ ```ts
151
+ // ICE candidate: socket.emit('ice-candidate', { candidate, to: peer.uid });
152
+ // Offer: socket.emit('call-offer', { offer, to: peer.uid });
153
+ // Answer: socket.emit('call-answer', { answer, to: peer.uid });
154
+ ```
188
155
 
189
- ## Resize (Maximize / Minimize)
156
+ ---
190
157
 
191
- The widget has a maximize/minimize toggle button in the top-right of the panel header.
192
- - **Normal size**: 380×560px
193
- - **Maximized**: 480×720px
194
- - Both sizes respect `max-width: calc(100vw - 32px)` and `max-height: calc(100vh - 110px)` for mobile safety.
158
+ ## Folder Structure
195
159
 
160
+ ```
161
+ src/
162
+ ├── index.ts
163
+ ├── types/index.ts
164
+ ├── config/index.ts ← reads CHAT_API_KEY + CHAT_WIDGET_ID, fetches chatData.json
165
+ ├── utils/theme.ts
166
+ ├── utils/chat.ts ← transcript, avatarColor, formatTime, downloadText
167
+ ├── hooks/
168
+ │ ├── useRemoteConfig.ts ← fetches chatData.json
169
+ │ ├── useChat.ts ← messages, pause, report
170
+ │ └── useWebRTC.ts ← P2P WebRTC calling
171
+ └── components/
172
+ ├── ChatWidget.tsx ← 🏠 Root drawer orchestrator
173
+ ├── HomeScreen/
174
+ ├── UserListScreen/
175
+ ├── ChatScreen/ ← voice, attach, emoji, pause, report, block, transcript, call
176
+ ├── CallScreen/ ← WebRTC video/audio UI
177
+ ├── EmojiPicker/
178
+ ├── TicketScreen/
179
+ ├── RecentChatsScreen/
180
+ ├── BlockList/
181
+ ├── MaintenanceView/
182
+ └── Tabs/BottomTabs.tsx ← Home / Chats / Tickets / Blocked
183
+
184
+ public/
185
+ └── chatData.json ← Sample JSON — host at window.mscorpres.com/TEST/chatData.json
186
+ ```
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { ChatUser, WidgetConfig } from '../../types';
3
+ interface BlockListScreenProps {
4
+ blockedUsers: ChatUser[];
5
+ config: WidgetConfig;
6
+ onUnblock: (uid: string) => void;
7
+ onBack: () => void;
8
+ }
9
+ export declare const BlockListScreen: React.FC<BlockListScreenProps>;
10
+ export {};
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { avatarColor, initials } from '../../utils/chat';
3
+ export const BlockListScreen = ({ blockedUsers, config, onUnblock, onBack, }) => (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', animation: 'cw-slideIn 0.22s ease' }, children: [_jsxs("div", { style: {
4
+ background: `linear-gradient(135deg,${config.primaryColor},${config.primaryColor}cc)`,
5
+ padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0,
6
+ }, children: [_jsx("button", { onClick: onBack, style: backBtnStyle, 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", { children: [_jsx("div", { style: { fontWeight: 700, fontSize: 16, color: '#fff' }, children: "Block List" }), _jsxs("div", { style: { fontSize: 12, color: 'rgba(255,255,255,0.8)' }, children: [blockedUsers.length, " blocked user", blockedUsers.length !== 1 ? 's' : ''] })] })] }), _jsx("div", { style: { flex: 1, overflowY: 'auto' }, children: blockedUsers.length === 0 ? (_jsxs("div", { style: { padding: '50px 24px', textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 36, marginBottom: 10 }, children: "\u2705" }), _jsx("div", { style: { fontWeight: 700, color: '#1a2332', marginBottom: 6 }, children: "No blocked users" }), _jsx("div", { style: { fontSize: 13, color: '#7b8fa1' }, children: "Users you block will appear here" })] })) : (blockedUsers.map((user, i) => (_jsxs("div", { style: {
7
+ padding: '13px 16px', display: 'flex', alignItems: 'center', gap: 13,
8
+ borderBottom: '1px solid #f0f2f5',
9
+ animation: `cw-fadeUp 0.28s ease both`, animationDelay: `${i * 0.05}s`,
10
+ }, children: [_jsx("div", { style: {
11
+ width: 44, height: 44, borderRadius: '50%',
12
+ backgroundColor: avatarColor(user.name),
13
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
14
+ color: '#fff', fontWeight: 700, fontSize: 14, flexShrink: 0,
15
+ filter: 'grayscale(0.6)', opacity: 0.7,
16
+ }, children: initials(user.name) }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [_jsx("div", { style: { fontWeight: 700, fontSize: 14, color: '#6b7280' }, children: user.name }), _jsx("div", { style: { fontSize: 12, color: '#9ca3af', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: user.email })] }), _jsx("button", { onClick: () => onUnblock(user.uid), style: {
17
+ padding: '6px 14px', borderRadius: 20,
18
+ border: `1.5px solid ${config.primaryColor}`,
19
+ background: 'transparent', color: config.primaryColor,
20
+ fontSize: 12, fontWeight: 700, cursor: 'pointer',
21
+ transition: 'all 0.15s', flexShrink: 0,
22
+ }, onMouseEnter: e => {
23
+ e.currentTarget.style.background = config.primaryColor;
24
+ e.currentTarget.style.color = '#fff';
25
+ }, onMouseLeave: e => {
26
+ e.currentTarget.style.background = 'transparent';
27
+ e.currentTarget.style.color = config.primaryColor;
28
+ }, children: "Unblock" })] }, user.uid)))) })] }));
29
+ const backBtnStyle = {
30
+ background: 'rgba(255,255,255,0.22)', border: 'none', borderRadius: '50%',
31
+ width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
32
+ cursor: 'pointer', flexShrink: 0,
33
+ };
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { CallSession } from '../../types';
3
+ interface CallScreenProps {
4
+ session: CallSession;
5
+ localVideoRef: React.RefObject<HTMLVideoElement | null>;
6
+ remoteVideoRef: React.RefObject<HTMLVideoElement | null>;
7
+ onEnd: () => void;
8
+ onToggleMute: () => void;
9
+ onToggleCamera: () => void;
10
+ primaryColor: string;
11
+ }
12
+ export declare const CallScreen: React.FC<CallScreenProps>;
13
+ export {};
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { avatarColor, initials } from '../../utils/chat';
4
+ export const CallScreen = ({ session, localVideoRef, remoteVideoRef, onEnd, onToggleMute, onToggleCamera, primaryColor, }) => {
5
+ const [duration, setDuration] = useState(0);
6
+ const peer = session.peer;
7
+ useEffect(() => {
8
+ if (session.state !== 'connected' || !session.startedAt)
9
+ return;
10
+ const t = setInterval(() => {
11
+ setDuration(Math.floor((Date.now() - session.startedAt.getTime()) / 1000));
12
+ }, 1000);
13
+ return () => clearInterval(t);
14
+ }, [session.state, session.startedAt]);
15
+ const mins = String(Math.floor(duration / 60)).padStart(2, '0');
16
+ const secs = String(duration % 60).padStart(2, '0');
17
+ return (_jsxs("div", { style: {
18
+ display: 'flex', flexDirection: 'column', height: '100%',
19
+ background: session.isCameraOn ? '#000' : `linear-gradient(145deg,${primaryColor}dd,#0f172a)`,
20
+ color: '#fff', animation: 'cw-slideIn 0.22s ease',
21
+ position: 'relative', overflow: 'hidden',
22
+ }, children: [_jsx("video", { ref: remoteVideoRef, autoPlay: true, playsInline: true, style: { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', opacity: session.state === 'connected' ? 1 : 0 } }), _jsx("video", { ref: localVideoRef, autoPlay: true, playsInline: true, muted: true, style: {
23
+ position: 'absolute', bottom: 120, right: 14,
24
+ width: 90, height: 120, borderRadius: 10,
25
+ objectFit: 'cover', border: '2px solid rgba(255,255,255,0.3)',
26
+ display: session.isCameraOn ? 'block' : 'none',
27
+ zIndex: 10,
28
+ } }), _jsxs("div", { style: { position: 'relative', zIndex: 5, display: 'flex', flexDirection: 'column', height: '100%', background: 'rgba(0,0,0,0.35)' }, children: [_jsx("div", { style: { padding: '16px 18px', display: 'flex', alignItems: 'center', gap: 10 }, children: _jsx("div", { style: { flex: 1 }, children: _jsxs("div", { style: { fontWeight: 700, fontSize: 15, color: '#fff' }, children: [session.state === 'calling' && 'Calling...', session.state === 'connected' && 'Connected', session.state === 'ended' && 'Call Ended'] }) }) }), _jsx("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 16 }, children: peer && (_jsxs(_Fragment, { children: [_jsx("div", { style: {
29
+ width: 90, height: 90, borderRadius: '50%',
30
+ backgroundColor: avatarColor(peer.name),
31
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
32
+ fontSize: 28, fontWeight: 700, color: '#fff',
33
+ boxShadow: '0 0 0 4px rgba(255,255,255,0.2)',
34
+ animation: session.state === 'calling' ? 'cw-pulse 1.5s ease infinite' : 'none',
35
+ }, children: initials(peer.name) }), _jsxs("div", { style: { textAlign: 'center' }, children: [_jsx("div", { style: { fontSize: 20, fontWeight: 800 }, children: peer.name }), _jsxs("div", { style: { fontSize: 13, opacity: 0.8, marginTop: 4 }, children: [session.state === 'calling' && 'Ringing...', session.state === 'connected' && `${mins}:${secs}`, session.state === 'ended' && 'Call ended'] })] })] })) }), _jsxs("div", { style: { padding: '24px', display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 20 }, children: [_jsx(CallBtn, { active: session.isMuted, activeColor: "#374151", onClick: onToggleMute, title: session.isMuted ? 'Unmute' : 'Mute', children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: session.isMuted
36
+ ? _jsxs(_Fragment, { children: [_jsx("path", { d: "M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z", stroke: "#fff", strokeWidth: "2" }), _jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23", stroke: "#ef4444", strokeWidth: "2" })] })
37
+ : _jsxs(_Fragment, { children: [_jsx("path", { d: "M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round" }), _jsx("path", { d: "M19 10v2a7 7 0 01-14 0v-2M12 19v4", stroke: "#fff", strokeWidth: "2", strokeLinecap: "round" })] }) }) }), _jsx("button", { onClick: onEnd, style: {
38
+ width: 60, height: 60, borderRadius: '50%', backgroundColor: '#ef4444',
39
+ border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
40
+ boxShadow: '0 4px 16px rgba(239,68,68,0.5)', flexShrink: 0,
41
+ }, children: _jsx("svg", { width: "24", height: "24", 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", transform: "rotate(135 12 12)" }) }) }), _jsx(CallBtn, { active: session.isCameraOn, activeColor: primaryColor, onClick: onToggleCamera, title: "Camera", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: _jsx("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" }) }) })] })] })] }));
42
+ };
43
+ const CallBtn = ({ active, activeColor, onClick, title, children, }) => (_jsx("button", { onClick: onClick, title: title, style: {
44
+ width: 50, height: 50, borderRadius: '50%',
45
+ backgroundColor: active ? activeColor : 'rgba(255,255,255,0.2)',
46
+ border: 'none', cursor: 'pointer',
47
+ display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
48
+ }, children: children }));
@@ -1,12 +1,19 @@
1
1
  import React from 'react';
2
- import { ChatMessage, ChatUser, ChatWidgetTheme } from '../../types';
2
+ import { ChatMessage, ChatUser, WidgetConfig } from '../../types';
3
3
  interface ChatScreenProps {
4
4
  activeUser: ChatUser;
5
5
  messages: ChatMessage[];
6
- onSend: (text: string) => void;
6
+ config: WidgetConfig;
7
+ isPaused: boolean;
8
+ isReported: boolean;
9
+ isBlocked: boolean;
10
+ onSend: (text: string, type?: ChatMessage['type'], extra?: Partial<ChatMessage>) => void;
7
11
  onBack: () => void;
8
12
  onClose: () => void;
9
- theme?: ChatWidgetTheme;
13
+ onTogglePause: () => void;
14
+ onReport: () => void;
15
+ onBlock: () => void;
16
+ onStartCall: (withVideo: boolean) => void;
10
17
  }
11
18
  export declare const ChatScreen: React.FC<ChatScreenProps>;
12
19
  export {};