@pocketping/widget 1.6.0 → 1.7.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.
- package/README.md +2 -0
- package/dist/index.cjs +1103 -257
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +1103 -257
- package/dist/pocketping.min.global.js +447 -66
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { render, h as h2 } from "preact";
|
|
3
3
|
|
|
4
4
|
// src/components/ChatWidget.tsx
|
|
5
|
-
import { Fragment } from "preact";
|
|
6
|
-
import { useState, useEffect, useRef, useCallback } from "preact/hooks";
|
|
5
|
+
import { Fragment as Fragment2 } from "preact";
|
|
6
|
+
import { useState as useState2, useEffect as useEffect2, useRef as useRef2, useCallback } from "preact/hooks";
|
|
7
7
|
|
|
8
8
|
// src/components/styles.ts
|
|
9
9
|
function styles(primaryColor, theme) {
|
|
@@ -24,6 +24,17 @@ function styles(primaryColor, theme) {
|
|
|
24
24
|
color: ${colors.text};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
#pocketping-container,
|
|
28
|
+
#pocketping-container * {
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#pocketping-container img,
|
|
33
|
+
#pocketping-container video {
|
|
34
|
+
max-width: 100%;
|
|
35
|
+
height: auto;
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
.pp-toggle {
|
|
28
39
|
position: fixed;
|
|
29
40
|
width: 56px;
|
|
@@ -219,10 +230,14 @@ function styles(primaryColor, theme) {
|
|
|
219
230
|
.pp-messages {
|
|
220
231
|
flex: 1;
|
|
221
232
|
overflow-y: auto;
|
|
222
|
-
padding: 12px;
|
|
233
|
+
padding: 32px 12px 12px 12px;
|
|
223
234
|
display: flex;
|
|
224
235
|
flex-direction: column;
|
|
225
236
|
gap: 3px;
|
|
237
|
+
overscroll-behavior: contain;
|
|
238
|
+
-webkit-overflow-scrolling: touch;
|
|
239
|
+
/* Ensure proper stacking context for positioned elements */
|
|
240
|
+
position: relative;
|
|
226
241
|
}
|
|
227
242
|
|
|
228
243
|
.pp-welcome {
|
|
@@ -248,6 +263,75 @@ function styles(primaryColor, theme) {
|
|
|
248
263
|
font-weight: 500;
|
|
249
264
|
}
|
|
250
265
|
|
|
266
|
+
/* Swipe container for mobile actions */
|
|
267
|
+
.pp-message-swipe-container {
|
|
268
|
+
position: relative;
|
|
269
|
+
display: flex;
|
|
270
|
+
align-items: stretch;
|
|
271
|
+
overflow: visible;
|
|
272
|
+
touch-action: pan-y;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.pp-swipe-left {
|
|
276
|
+
justify-content: flex-end;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.pp-swipe-right {
|
|
280
|
+
justify-content: flex-start;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.pp-swipe-actions {
|
|
284
|
+
position: absolute;
|
|
285
|
+
right: 0;
|
|
286
|
+
top: 0;
|
|
287
|
+
bottom: 0;
|
|
288
|
+
display: flex;
|
|
289
|
+
align-items: center;
|
|
290
|
+
gap: 4px;
|
|
291
|
+
padding-right: 8px;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.pp-swipe-left .pp-swipe-actions {
|
|
295
|
+
right: 0;
|
|
296
|
+
left: auto;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.pp-swipe-right .pp-swipe-actions {
|
|
300
|
+
left: 0;
|
|
301
|
+
right: auto;
|
|
302
|
+
padding-left: 8px;
|
|
303
|
+
padding-right: 0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.pp-swipe-action {
|
|
307
|
+
width: 32px;
|
|
308
|
+
height: 32px;
|
|
309
|
+
border: none;
|
|
310
|
+
border-radius: 50%;
|
|
311
|
+
cursor: pointer;
|
|
312
|
+
display: flex;
|
|
313
|
+
align-items: center;
|
|
314
|
+
justify-content: center;
|
|
315
|
+
opacity: 0.9;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.pp-swipe-action svg {
|
|
319
|
+
width: 16px;
|
|
320
|
+
height: 16px;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.pp-swipe-reply {
|
|
324
|
+
background: ${primaryColor};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.pp-swipe-edit {
|
|
328
|
+
background: #3b82f6;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.pp-swipe-delete {
|
|
332
|
+
background: #ef4444;
|
|
333
|
+
}
|
|
334
|
+
|
|
251
335
|
.pp-message {
|
|
252
336
|
max-width: 85%;
|
|
253
337
|
padding: 6px 10px;
|
|
@@ -258,12 +342,15 @@ function styles(primaryColor, theme) {
|
|
|
258
342
|
-webkit-user-select: text;
|
|
259
343
|
font-size: 14px;
|
|
260
344
|
line-height: 1.35;
|
|
345
|
+
display: flex;
|
|
346
|
+
flex-direction: column;
|
|
347
|
+
will-change: transform;
|
|
261
348
|
}
|
|
262
349
|
|
|
263
350
|
/* Hover actions container - positioned above message (Slack style) */
|
|
264
351
|
.pp-message-actions {
|
|
265
352
|
position: absolute;
|
|
266
|
-
top: -
|
|
353
|
+
top: -32px;
|
|
267
354
|
display: flex;
|
|
268
355
|
gap: 2px;
|
|
269
356
|
background: ${colors.bg};
|
|
@@ -276,6 +363,8 @@ function styles(primaryColor, theme) {
|
|
|
276
363
|
z-index: 10;
|
|
277
364
|
/* Reset color inheritance from message */
|
|
278
365
|
color: ${colors.textSecondary};
|
|
366
|
+
/* Ensure actions don't interfere with layout */
|
|
367
|
+
pointer-events: auto;
|
|
279
368
|
}
|
|
280
369
|
|
|
281
370
|
@keyframes pp-actions-fade-in {
|
|
@@ -371,18 +460,19 @@ function styles(primaryColor, theme) {
|
|
|
371
460
|
}
|
|
372
461
|
|
|
373
462
|
.pp-message-content {
|
|
374
|
-
display:
|
|
463
|
+
display: block;
|
|
464
|
+
flex: 1;
|
|
375
465
|
}
|
|
376
466
|
|
|
377
467
|
.pp-message-time {
|
|
378
468
|
font-size: 10px;
|
|
379
469
|
opacity: 0.6;
|
|
380
|
-
display:
|
|
470
|
+
display: flex;
|
|
381
471
|
align-items: center;
|
|
382
472
|
gap: 3px;
|
|
383
|
-
|
|
384
|
-
margin-
|
|
385
|
-
|
|
473
|
+
justify-content: flex-end;
|
|
474
|
+
margin-top: 8px;
|
|
475
|
+
flex-shrink: 0;
|
|
386
476
|
}
|
|
387
477
|
|
|
388
478
|
.pp-ai-badge {
|
|
@@ -674,7 +764,10 @@ function styles(primaryColor, theme) {
|
|
|
674
764
|
display: flex;
|
|
675
765
|
flex-direction: column;
|
|
676
766
|
gap: 8px;
|
|
677
|
-
margin-top:
|
|
767
|
+
margin-top: 6px;
|
|
768
|
+
max-width: 100%;
|
|
769
|
+
align-items: flex-start;
|
|
770
|
+
flex-shrink: 0;
|
|
678
771
|
}
|
|
679
772
|
|
|
680
773
|
.pp-attachment {
|
|
@@ -685,11 +778,22 @@ function styles(primaryColor, theme) {
|
|
|
685
778
|
overflow: hidden;
|
|
686
779
|
}
|
|
687
780
|
|
|
781
|
+
.pp-attachment-image,
|
|
782
|
+
.pp-attachment-video,
|
|
783
|
+
.pp-attachment-audio {
|
|
784
|
+
width: 240px;
|
|
785
|
+
max-width: 100%;
|
|
786
|
+
}
|
|
787
|
+
|
|
688
788
|
.pp-attachment-image img {
|
|
689
|
-
|
|
789
|
+
width: 100% !important;
|
|
790
|
+
height: auto !important;
|
|
791
|
+
max-width: 240px;
|
|
690
792
|
max-height: 200px;
|
|
691
793
|
border-radius: 8px;
|
|
692
794
|
display: block;
|
|
795
|
+
object-fit: cover !important;
|
|
796
|
+
object-position: center;
|
|
693
797
|
}
|
|
694
798
|
|
|
695
799
|
.pp-attachment-audio {
|
|
@@ -699,7 +803,8 @@ function styles(primaryColor, theme) {
|
|
|
699
803
|
}
|
|
700
804
|
|
|
701
805
|
.pp-attachment-audio audio {
|
|
702
|
-
width:
|
|
806
|
+
width: 240px;
|
|
807
|
+
max-width: 100%;
|
|
703
808
|
height: 36px;
|
|
704
809
|
}
|
|
705
810
|
|
|
@@ -709,14 +814,18 @@ function styles(primaryColor, theme) {
|
|
|
709
814
|
white-space: nowrap;
|
|
710
815
|
overflow: hidden;
|
|
711
816
|
text-overflow: ellipsis;
|
|
712
|
-
max-width:
|
|
817
|
+
max-width: 100%;
|
|
713
818
|
}
|
|
714
819
|
|
|
715
820
|
.pp-attachment-video video {
|
|
716
|
-
|
|
717
|
-
|
|
821
|
+
width: 100% !important;
|
|
822
|
+
height: auto !important;
|
|
823
|
+
max-width: 240px;
|
|
824
|
+
max-height: none;
|
|
718
825
|
border-radius: 8px;
|
|
719
826
|
display: block;
|
|
827
|
+
object-fit: contain !important;
|
|
828
|
+
object-position: center;
|
|
720
829
|
}
|
|
721
830
|
|
|
722
831
|
.pp-attachment-file {
|
|
@@ -1067,11 +1176,619 @@ function styles(primaryColor, theme) {
|
|
|
1067
1176
|
margin-left: 4px;
|
|
1068
1177
|
font-style: italic;
|
|
1069
1178
|
}
|
|
1179
|
+
|
|
1180
|
+
/* Pre-Chat Form */
|
|
1181
|
+
.pp-prechat {
|
|
1182
|
+
flex: 1;
|
|
1183
|
+
display: flex;
|
|
1184
|
+
flex-direction: column;
|
|
1185
|
+
padding: 24px 20px;
|
|
1186
|
+
overflow-y: auto;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.pp-prechat-title {
|
|
1190
|
+
font-size: 18px;
|
|
1191
|
+
font-weight: 600;
|
|
1192
|
+
margin-bottom: 8px;
|
|
1193
|
+
color: ${colors.text};
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
.pp-prechat-subtitle {
|
|
1197
|
+
font-size: 13px;
|
|
1198
|
+
color: ${colors.textSecondary};
|
|
1199
|
+
margin-bottom: 24px;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
.pp-prechat-tabs {
|
|
1203
|
+
display: flex;
|
|
1204
|
+
gap: 8px;
|
|
1205
|
+
margin-bottom: 20px;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.pp-prechat-tab {
|
|
1209
|
+
flex: 1;
|
|
1210
|
+
padding: 10px;
|
|
1211
|
+
border: 1px solid ${colors.border};
|
|
1212
|
+
border-radius: 8px;
|
|
1213
|
+
background: transparent;
|
|
1214
|
+
color: ${colors.textSecondary};
|
|
1215
|
+
font-size: 13px;
|
|
1216
|
+
cursor: pointer;
|
|
1217
|
+
transition: all 0.2s;
|
|
1218
|
+
display: flex;
|
|
1219
|
+
align-items: center;
|
|
1220
|
+
justify-content: center;
|
|
1221
|
+
gap: 6px;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
.pp-prechat-tab:hover {
|
|
1225
|
+
background: ${colors.bgSecondary};
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.pp-prechat-tab.active {
|
|
1229
|
+
background: ${primaryColor}15;
|
|
1230
|
+
border-color: ${primaryColor};
|
|
1231
|
+
color: ${primaryColor};
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
.pp-prechat-tab svg {
|
|
1235
|
+
width: 16px;
|
|
1236
|
+
height: 16px;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.pp-prechat-field {
|
|
1240
|
+
margin-bottom: 16px;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.pp-prechat-label {
|
|
1244
|
+
display: block;
|
|
1245
|
+
font-size: 12px;
|
|
1246
|
+
font-weight: 500;
|
|
1247
|
+
color: ${colors.textSecondary};
|
|
1248
|
+
margin-bottom: 6px;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.pp-prechat-input {
|
|
1252
|
+
width: 100%;
|
|
1253
|
+
height: 44px;
|
|
1254
|
+
padding: 0 14px;
|
|
1255
|
+
border: 1px solid ${colors.border};
|
|
1256
|
+
border-radius: 8px;
|
|
1257
|
+
background: ${colors.bg};
|
|
1258
|
+
color: ${colors.text};
|
|
1259
|
+
font-size: 14px;
|
|
1260
|
+
outline: none;
|
|
1261
|
+
transition: border-color 0.2s;
|
|
1262
|
+
box-sizing: border-box;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.pp-prechat-input:focus {
|
|
1266
|
+
border-color: ${primaryColor};
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.pp-prechat-input::placeholder {
|
|
1270
|
+
color: ${colors.textSecondary};
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
.pp-prechat-input.error {
|
|
1274
|
+
border-color: #ef4444;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
.pp-prechat-error {
|
|
1278
|
+
color: #ef4444;
|
|
1279
|
+
font-size: 12px;
|
|
1280
|
+
margin-top: 4px;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
.pp-phone-input-wrapper {
|
|
1284
|
+
display: flex;
|
|
1285
|
+
gap: 8px;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
.pp-country-select {
|
|
1289
|
+
position: relative;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
.pp-country-btn {
|
|
1293
|
+
display: flex;
|
|
1294
|
+
align-items: center;
|
|
1295
|
+
gap: 6px;
|
|
1296
|
+
height: 44px;
|
|
1297
|
+
padding: 0 10px;
|
|
1298
|
+
border: 1px solid ${colors.border};
|
|
1299
|
+
border-radius: 8px;
|
|
1300
|
+
background: ${colors.bg};
|
|
1301
|
+
color: ${colors.text};
|
|
1302
|
+
font-size: 14px;
|
|
1303
|
+
cursor: pointer;
|
|
1304
|
+
transition: border-color 0.2s;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
.pp-country-btn:focus {
|
|
1308
|
+
border-color: ${primaryColor};
|
|
1309
|
+
outline: none;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.pp-country-flag {
|
|
1313
|
+
font-size: 18px;
|
|
1314
|
+
line-height: 1;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
.pp-country-code {
|
|
1318
|
+
font-size: 13px;
|
|
1319
|
+
color: ${colors.textSecondary};
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
.pp-country-chevron {
|
|
1323
|
+
width: 12px;
|
|
1324
|
+
height: 12px;
|
|
1325
|
+
color: ${colors.textSecondary};
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
.pp-country-dropdown {
|
|
1329
|
+
position: absolute;
|
|
1330
|
+
top: calc(100% + 4px);
|
|
1331
|
+
left: 0;
|
|
1332
|
+
width: 280px;
|
|
1333
|
+
max-height: 280px;
|
|
1334
|
+
overflow-y: auto;
|
|
1335
|
+
background: ${colors.bg};
|
|
1336
|
+
border: 1px solid ${colors.border};
|
|
1337
|
+
border-radius: 8px;
|
|
1338
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1339
|
+
z-index: 100;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
.pp-country-search {
|
|
1343
|
+
position: sticky;
|
|
1344
|
+
top: 0;
|
|
1345
|
+
padding: 8px;
|
|
1346
|
+
background: ${colors.bg};
|
|
1347
|
+
border-bottom: 1px solid ${colors.border};
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
.pp-country-search-input {
|
|
1351
|
+
width: 100%;
|
|
1352
|
+
height: 36px;
|
|
1353
|
+
padding: 0 12px;
|
|
1354
|
+
border: 1px solid ${colors.border};
|
|
1355
|
+
border-radius: 6px;
|
|
1356
|
+
background: ${colors.bgSecondary};
|
|
1357
|
+
color: ${colors.text};
|
|
1358
|
+
font-size: 13px;
|
|
1359
|
+
outline: none;
|
|
1360
|
+
box-sizing: border-box;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
.pp-country-search-input:focus {
|
|
1364
|
+
border-color: ${primaryColor};
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
.pp-country-list {
|
|
1368
|
+
padding: 4px;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
.pp-country-option {
|
|
1372
|
+
display: flex;
|
|
1373
|
+
align-items: center;
|
|
1374
|
+
gap: 10px;
|
|
1375
|
+
padding: 10px 12px;
|
|
1376
|
+
cursor: pointer;
|
|
1377
|
+
border-radius: 6px;
|
|
1378
|
+
transition: background 0.15s;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
.pp-country-option:hover {
|
|
1382
|
+
background: ${colors.bgSecondary};
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
.pp-country-option.selected {
|
|
1386
|
+
background: ${primaryColor}15;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
.pp-country-name {
|
|
1390
|
+
flex: 1;
|
|
1391
|
+
font-size: 13px;
|
|
1392
|
+
color: ${colors.text};
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
.pp-country-dial {
|
|
1396
|
+
font-size: 12px;
|
|
1397
|
+
color: ${colors.textSecondary};
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
.pp-phone-number-input {
|
|
1401
|
+
flex: 1;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
.pp-prechat-submit {
|
|
1405
|
+
width: 100%;
|
|
1406
|
+
height: 44px;
|
|
1407
|
+
margin-top: 8px;
|
|
1408
|
+
border: none;
|
|
1409
|
+
border-radius: 8px;
|
|
1410
|
+
background: ${primaryColor};
|
|
1411
|
+
color: white;
|
|
1412
|
+
font-size: 14px;
|
|
1413
|
+
font-weight: 500;
|
|
1414
|
+
cursor: pointer;
|
|
1415
|
+
transition: opacity 0.2s, transform 0.1s;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
.pp-prechat-submit:hover:not(:disabled) {
|
|
1419
|
+
opacity: 0.9;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
.pp-prechat-submit:active:not(:disabled) {
|
|
1423
|
+
transform: scale(0.98);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
.pp-prechat-submit:disabled {
|
|
1427
|
+
opacity: 0.5;
|
|
1428
|
+
cursor: not-allowed;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
.pp-prechat-skip {
|
|
1432
|
+
width: 100%;
|
|
1433
|
+
padding: 12px;
|
|
1434
|
+
margin-top: 8px;
|
|
1435
|
+
border: none;
|
|
1436
|
+
background: transparent;
|
|
1437
|
+
color: ${colors.textSecondary};
|
|
1438
|
+
font-size: 13px;
|
|
1439
|
+
cursor: pointer;
|
|
1440
|
+
transition: color 0.2s;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
.pp-prechat-skip:hover {
|
|
1444
|
+
color: ${colors.text};
|
|
1445
|
+
}
|
|
1070
1446
|
`;
|
|
1071
1447
|
}
|
|
1072
1448
|
|
|
1449
|
+
// src/components/PreChatForm.tsx
|
|
1450
|
+
import { useState, useRef, useEffect } from "preact/hooks";
|
|
1451
|
+
import { parsePhoneNumber, isValidPhoneNumber } from "libphonenumber-js/min";
|
|
1452
|
+
|
|
1453
|
+
// src/data/countries.ts
|
|
1454
|
+
var countries = [
|
|
1455
|
+
// Europe
|
|
1456
|
+
{ code: "FR", name: "France", dialCode: "+33", flag: "\u{1F1EB}\u{1F1F7}" },
|
|
1457
|
+
{ code: "DE", name: "Germany", dialCode: "+49", flag: "\u{1F1E9}\u{1F1EA}" },
|
|
1458
|
+
{ code: "GB", name: "United Kingdom", dialCode: "+44", flag: "\u{1F1EC}\u{1F1E7}" },
|
|
1459
|
+
{ code: "ES", name: "Spain", dialCode: "+34", flag: "\u{1F1EA}\u{1F1F8}" },
|
|
1460
|
+
{ code: "IT", name: "Italy", dialCode: "+39", flag: "\u{1F1EE}\u{1F1F9}" },
|
|
1461
|
+
{ code: "PT", name: "Portugal", dialCode: "+351", flag: "\u{1F1F5}\u{1F1F9}" },
|
|
1462
|
+
{ code: "NL", name: "Netherlands", dialCode: "+31", flag: "\u{1F1F3}\u{1F1F1}" },
|
|
1463
|
+
{ code: "BE", name: "Belgium", dialCode: "+32", flag: "\u{1F1E7}\u{1F1EA}" },
|
|
1464
|
+
{ code: "CH", name: "Switzerland", dialCode: "+41", flag: "\u{1F1E8}\u{1F1ED}" },
|
|
1465
|
+
{ code: "AT", name: "Austria", dialCode: "+43", flag: "\u{1F1E6}\u{1F1F9}" },
|
|
1466
|
+
{ code: "SE", name: "Sweden", dialCode: "+46", flag: "\u{1F1F8}\u{1F1EA}" },
|
|
1467
|
+
{ code: "NO", name: "Norway", dialCode: "+47", flag: "\u{1F1F3}\u{1F1F4}" },
|
|
1468
|
+
{ code: "DK", name: "Denmark", dialCode: "+45", flag: "\u{1F1E9}\u{1F1F0}" },
|
|
1469
|
+
{ code: "FI", name: "Finland", dialCode: "+358", flag: "\u{1F1EB}\u{1F1EE}" },
|
|
1470
|
+
{ code: "PL", name: "Poland", dialCode: "+48", flag: "\u{1F1F5}\u{1F1F1}" },
|
|
1471
|
+
{ code: "CZ", name: "Czech Republic", dialCode: "+420", flag: "\u{1F1E8}\u{1F1FF}" },
|
|
1472
|
+
{ code: "GR", name: "Greece", dialCode: "+30", flag: "\u{1F1EC}\u{1F1F7}" },
|
|
1473
|
+
{ code: "IE", name: "Ireland", dialCode: "+353", flag: "\u{1F1EE}\u{1F1EA}" },
|
|
1474
|
+
{ code: "RO", name: "Romania", dialCode: "+40", flag: "\u{1F1F7}\u{1F1F4}" },
|
|
1475
|
+
{ code: "HU", name: "Hungary", dialCode: "+36", flag: "\u{1F1ED}\u{1F1FA}" },
|
|
1476
|
+
// North America
|
|
1477
|
+
{ code: "US", name: "United States", dialCode: "+1", flag: "\u{1F1FA}\u{1F1F8}" },
|
|
1478
|
+
{ code: "CA", name: "Canada", dialCode: "+1", flag: "\u{1F1E8}\u{1F1E6}" },
|
|
1479
|
+
{ code: "MX", name: "Mexico", dialCode: "+52", flag: "\u{1F1F2}\u{1F1FD}" },
|
|
1480
|
+
// South America
|
|
1481
|
+
{ code: "BR", name: "Brazil", dialCode: "+55", flag: "\u{1F1E7}\u{1F1F7}" },
|
|
1482
|
+
{ code: "AR", name: "Argentina", dialCode: "+54", flag: "\u{1F1E6}\u{1F1F7}" },
|
|
1483
|
+
{ code: "CL", name: "Chile", dialCode: "+56", flag: "\u{1F1E8}\u{1F1F1}" },
|
|
1484
|
+
{ code: "CO", name: "Colombia", dialCode: "+57", flag: "\u{1F1E8}\u{1F1F4}" },
|
|
1485
|
+
{ code: "PE", name: "Peru", dialCode: "+51", flag: "\u{1F1F5}\u{1F1EA}" },
|
|
1486
|
+
// Asia
|
|
1487
|
+
{ code: "CN", name: "China", dialCode: "+86", flag: "\u{1F1E8}\u{1F1F3}" },
|
|
1488
|
+
{ code: "JP", name: "Japan", dialCode: "+81", flag: "\u{1F1EF}\u{1F1F5}" },
|
|
1489
|
+
{ code: "KR", name: "South Korea", dialCode: "+82", flag: "\u{1F1F0}\u{1F1F7}" },
|
|
1490
|
+
{ code: "IN", name: "India", dialCode: "+91", flag: "\u{1F1EE}\u{1F1F3}" },
|
|
1491
|
+
{ code: "ID", name: "Indonesia", dialCode: "+62", flag: "\u{1F1EE}\u{1F1E9}" },
|
|
1492
|
+
{ code: "TH", name: "Thailand", dialCode: "+66", flag: "\u{1F1F9}\u{1F1ED}" },
|
|
1493
|
+
{ code: "VN", name: "Vietnam", dialCode: "+84", flag: "\u{1F1FB}\u{1F1F3}" },
|
|
1494
|
+
{ code: "MY", name: "Malaysia", dialCode: "+60", flag: "\u{1F1F2}\u{1F1FE}" },
|
|
1495
|
+
{ code: "SG", name: "Singapore", dialCode: "+65", flag: "\u{1F1F8}\u{1F1EC}" },
|
|
1496
|
+
{ code: "PH", name: "Philippines", dialCode: "+63", flag: "\u{1F1F5}\u{1F1ED}" },
|
|
1497
|
+
{ code: "PK", name: "Pakistan", dialCode: "+92", flag: "\u{1F1F5}\u{1F1F0}" },
|
|
1498
|
+
{ code: "BD", name: "Bangladesh", dialCode: "+880", flag: "\u{1F1E7}\u{1F1E9}" },
|
|
1499
|
+
// Middle East
|
|
1500
|
+
{ code: "AE", name: "United Arab Emirates", dialCode: "+971", flag: "\u{1F1E6}\u{1F1EA}" },
|
|
1501
|
+
{ code: "SA", name: "Saudi Arabia", dialCode: "+966", flag: "\u{1F1F8}\u{1F1E6}" },
|
|
1502
|
+
{ code: "IL", name: "Israel", dialCode: "+972", flag: "\u{1F1EE}\u{1F1F1}" },
|
|
1503
|
+
{ code: "TR", name: "Turkey", dialCode: "+90", flag: "\u{1F1F9}\u{1F1F7}" },
|
|
1504
|
+
{ code: "EG", name: "Egypt", dialCode: "+20", flag: "\u{1F1EA}\u{1F1EC}" },
|
|
1505
|
+
// Africa
|
|
1506
|
+
{ code: "ZA", name: "South Africa", dialCode: "+27", flag: "\u{1F1FF}\u{1F1E6}" },
|
|
1507
|
+
{ code: "NG", name: "Nigeria", dialCode: "+234", flag: "\u{1F1F3}\u{1F1EC}" },
|
|
1508
|
+
{ code: "KE", name: "Kenya", dialCode: "+254", flag: "\u{1F1F0}\u{1F1EA}" },
|
|
1509
|
+
{ code: "MA", name: "Morocco", dialCode: "+212", flag: "\u{1F1F2}\u{1F1E6}" },
|
|
1510
|
+
{ code: "TN", name: "Tunisia", dialCode: "+216", flag: "\u{1F1F9}\u{1F1F3}" },
|
|
1511
|
+
{ code: "DZ", name: "Algeria", dialCode: "+213", flag: "\u{1F1E9}\u{1F1FF}" },
|
|
1512
|
+
// Oceania
|
|
1513
|
+
{ code: "AU", name: "Australia", dialCode: "+61", flag: "\u{1F1E6}\u{1F1FA}" },
|
|
1514
|
+
{ code: "NZ", name: "New Zealand", dialCode: "+64", flag: "\u{1F1F3}\u{1F1FF}" },
|
|
1515
|
+
// Russia & CIS
|
|
1516
|
+
{ code: "RU", name: "Russia", dialCode: "+7", flag: "\u{1F1F7}\u{1F1FA}" },
|
|
1517
|
+
{ code: "UA", name: "Ukraine", dialCode: "+380", flag: "\u{1F1FA}\u{1F1E6}" }
|
|
1518
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
1519
|
+
function findCountryByCode(code) {
|
|
1520
|
+
return countries.find((c) => c.code === code.toUpperCase());
|
|
1521
|
+
}
|
|
1522
|
+
var defaultCountry = findCountryByCode("FR");
|
|
1523
|
+
|
|
1524
|
+
// src/components/PreChatForm.tsx
|
|
1525
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
1526
|
+
var EmailIcon = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1527
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
|
|
1528
|
+
/* @__PURE__ */ jsx("path", { d: "M22 7l-10 7L2 7" })
|
|
1529
|
+
] });
|
|
1530
|
+
var PhoneIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72 12.84 12.84 0 00.7 2.81 2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45 12.84 12.84 0 002.81.7A2 2 0 0122 16.92z" }) });
|
|
1531
|
+
var ChevronIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M6 9l6 6 6-6" }) });
|
|
1532
|
+
function isValidEmail(email) {
|
|
1533
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
1534
|
+
}
|
|
1535
|
+
function PreChatForm({ client: client2, config, onComplete, onSkip }) {
|
|
1536
|
+
const showEmailOnly = config.fields === "email-only";
|
|
1537
|
+
const showPhoneOnly = config.fields === "phone-only";
|
|
1538
|
+
const showBoth = config.fields === "email-and-phone";
|
|
1539
|
+
const showChoice = config.fields === "email-or-phone";
|
|
1540
|
+
const getDefaultTab = () => {
|
|
1541
|
+
if (showPhoneOnly) return "phone";
|
|
1542
|
+
return "email";
|
|
1543
|
+
};
|
|
1544
|
+
const [activeTab, setActiveTab] = useState(getDefaultTab());
|
|
1545
|
+
const [email, setEmail] = useState("");
|
|
1546
|
+
const [phone, setPhone] = useState("");
|
|
1547
|
+
const [selectedCountry, setSelectedCountry] = useState(defaultCountry);
|
|
1548
|
+
const [isCountryDropdownOpen, setIsCountryDropdownOpen] = useState(false);
|
|
1549
|
+
const [countrySearch, setCountrySearch] = useState("");
|
|
1550
|
+
const [emailError, setEmailError] = useState("");
|
|
1551
|
+
const [phoneError, setPhoneError] = useState("");
|
|
1552
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
1553
|
+
const countryDropdownRef = useRef(null);
|
|
1554
|
+
const searchInputRef = useRef(null);
|
|
1555
|
+
useEffect(() => {
|
|
1556
|
+
const handleClickOutside = (e) => {
|
|
1557
|
+
if (countryDropdownRef.current && !countryDropdownRef.current.contains(e.target)) {
|
|
1558
|
+
setIsCountryDropdownOpen(false);
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1562
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1563
|
+
}, []);
|
|
1564
|
+
useEffect(() => {
|
|
1565
|
+
if (isCountryDropdownOpen && searchInputRef.current) {
|
|
1566
|
+
searchInputRef.current.focus();
|
|
1567
|
+
}
|
|
1568
|
+
}, [isCountryDropdownOpen]);
|
|
1569
|
+
const filteredCountries = countries.filter(
|
|
1570
|
+
(c) => c.name.toLowerCase().includes(countrySearch.toLowerCase()) || c.dialCode.includes(countrySearch) || c.code.toLowerCase().includes(countrySearch.toLowerCase())
|
|
1571
|
+
);
|
|
1572
|
+
const handleCountrySelect = (country) => {
|
|
1573
|
+
setSelectedCountry(country);
|
|
1574
|
+
setIsCountryDropdownOpen(false);
|
|
1575
|
+
setCountrySearch("");
|
|
1576
|
+
};
|
|
1577
|
+
const formatPhoneForDisplay = (value) => {
|
|
1578
|
+
const digits = value.replace(/\D/g, "");
|
|
1579
|
+
return digits;
|
|
1580
|
+
};
|
|
1581
|
+
const handlePhoneChange = (e) => {
|
|
1582
|
+
const target = e.target;
|
|
1583
|
+
const formatted = formatPhoneForDisplay(target.value);
|
|
1584
|
+
setPhone(formatted);
|
|
1585
|
+
setPhoneError("");
|
|
1586
|
+
};
|
|
1587
|
+
const getFullPhoneNumber = () => {
|
|
1588
|
+
if (!phone) return "";
|
|
1589
|
+
return `${selectedCountry.dialCode}${phone}`;
|
|
1590
|
+
};
|
|
1591
|
+
const validateForm = () => {
|
|
1592
|
+
let valid = true;
|
|
1593
|
+
if (showEmailOnly || showBoth) {
|
|
1594
|
+
if (!email.trim()) {
|
|
1595
|
+
setEmailError("Email is required");
|
|
1596
|
+
valid = false;
|
|
1597
|
+
} else if (!isValidEmail(email)) {
|
|
1598
|
+
setEmailError("Please enter a valid email");
|
|
1599
|
+
valid = false;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
if (showPhoneOnly || showBoth) {
|
|
1603
|
+
const fullPhone = getFullPhoneNumber();
|
|
1604
|
+
if (!phone.trim()) {
|
|
1605
|
+
setPhoneError("Phone number is required");
|
|
1606
|
+
valid = false;
|
|
1607
|
+
} else if (!isValidPhoneNumber(fullPhone, selectedCountry.code)) {
|
|
1608
|
+
setPhoneError("Please enter a valid phone number");
|
|
1609
|
+
valid = false;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
if (showChoice) {
|
|
1613
|
+
if (activeTab === "email") {
|
|
1614
|
+
if (!email.trim()) {
|
|
1615
|
+
setEmailError("Email is required");
|
|
1616
|
+
valid = false;
|
|
1617
|
+
} else if (!isValidEmail(email)) {
|
|
1618
|
+
setEmailError("Please enter a valid email");
|
|
1619
|
+
valid = false;
|
|
1620
|
+
}
|
|
1621
|
+
} else {
|
|
1622
|
+
const fullPhone = getFullPhoneNumber();
|
|
1623
|
+
if (!phone.trim()) {
|
|
1624
|
+
setPhoneError("Phone number is required");
|
|
1625
|
+
valid = false;
|
|
1626
|
+
} else if (!isValidPhoneNumber(fullPhone, selectedCountry.code)) {
|
|
1627
|
+
setPhoneError("Please enter a valid phone number");
|
|
1628
|
+
valid = false;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return valid;
|
|
1633
|
+
};
|
|
1634
|
+
const handleSubmit = async (e) => {
|
|
1635
|
+
e.preventDefault();
|
|
1636
|
+
if (!validateForm()) return;
|
|
1637
|
+
setIsSubmitting(true);
|
|
1638
|
+
try {
|
|
1639
|
+
const data = {};
|
|
1640
|
+
if (showEmailOnly || showBoth || showChoice && activeTab === "email") {
|
|
1641
|
+
data.email = email.trim();
|
|
1642
|
+
}
|
|
1643
|
+
if (showPhoneOnly || showBoth || showChoice && activeTab === "phone") {
|
|
1644
|
+
const fullPhone = getFullPhoneNumber();
|
|
1645
|
+
const parsed = parsePhoneNumber(fullPhone, selectedCountry.code);
|
|
1646
|
+
if (parsed) {
|
|
1647
|
+
data.phone = parsed.format("E.164");
|
|
1648
|
+
data.phoneCountry = selectedCountry.code;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
await client2.submitPreChat(data);
|
|
1652
|
+
onComplete();
|
|
1653
|
+
} catch (err) {
|
|
1654
|
+
console.error("[PreChatForm] Submit error:", err);
|
|
1655
|
+
if (activeTab === "email" || showEmailOnly || showBoth) {
|
|
1656
|
+
setEmailError("Something went wrong. Please try again.");
|
|
1657
|
+
} else {
|
|
1658
|
+
setPhoneError("Something went wrong. Please try again.");
|
|
1659
|
+
}
|
|
1660
|
+
} finally {
|
|
1661
|
+
setIsSubmitting(false);
|
|
1662
|
+
}
|
|
1663
|
+
};
|
|
1664
|
+
const renderEmailField = () => /* @__PURE__ */ jsxs("div", { class: "pp-prechat-field", children: [
|
|
1665
|
+
/* @__PURE__ */ jsx("label", { class: "pp-prechat-label", children: "Email address" }),
|
|
1666
|
+
/* @__PURE__ */ jsx(
|
|
1667
|
+
"input",
|
|
1668
|
+
{
|
|
1669
|
+
type: "email",
|
|
1670
|
+
class: `pp-prechat-input ${emailError ? "error" : ""}`,
|
|
1671
|
+
placeholder: "you@example.com",
|
|
1672
|
+
value: email,
|
|
1673
|
+
onInput: (e) => {
|
|
1674
|
+
setEmail(e.target.value);
|
|
1675
|
+
setEmailError("");
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
),
|
|
1679
|
+
emailError && /* @__PURE__ */ jsx("div", { class: "pp-prechat-error", children: emailError })
|
|
1680
|
+
] });
|
|
1681
|
+
const renderPhoneField = () => /* @__PURE__ */ jsxs("div", { class: "pp-prechat-field", children: [
|
|
1682
|
+
/* @__PURE__ */ jsx("label", { class: "pp-prechat-label", children: "Phone number" }),
|
|
1683
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-phone-input-wrapper", children: [
|
|
1684
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-country-select", ref: countryDropdownRef, children: [
|
|
1685
|
+
/* @__PURE__ */ jsxs(
|
|
1686
|
+
"button",
|
|
1687
|
+
{
|
|
1688
|
+
type: "button",
|
|
1689
|
+
class: "pp-country-btn",
|
|
1690
|
+
onClick: () => setIsCountryDropdownOpen(!isCountryDropdownOpen),
|
|
1691
|
+
children: [
|
|
1692
|
+
/* @__PURE__ */ jsx("span", { class: "pp-country-flag", children: selectedCountry.flag }),
|
|
1693
|
+
/* @__PURE__ */ jsx("span", { class: "pp-country-code", children: selectedCountry.dialCode }),
|
|
1694
|
+
/* @__PURE__ */ jsx(ChevronIcon, {})
|
|
1695
|
+
]
|
|
1696
|
+
}
|
|
1697
|
+
),
|
|
1698
|
+
isCountryDropdownOpen && /* @__PURE__ */ jsxs("div", { class: "pp-country-dropdown", children: [
|
|
1699
|
+
/* @__PURE__ */ jsx("div", { class: "pp-country-search", children: /* @__PURE__ */ jsx(
|
|
1700
|
+
"input",
|
|
1701
|
+
{
|
|
1702
|
+
ref: searchInputRef,
|
|
1703
|
+
type: "text",
|
|
1704
|
+
class: "pp-country-search-input",
|
|
1705
|
+
placeholder: "Search country...",
|
|
1706
|
+
value: countrySearch,
|
|
1707
|
+
onInput: (e) => setCountrySearch(e.target.value)
|
|
1708
|
+
}
|
|
1709
|
+
) }),
|
|
1710
|
+
/* @__PURE__ */ jsx("div", { class: "pp-country-list", children: filteredCountries.map((country) => /* @__PURE__ */ jsxs(
|
|
1711
|
+
"div",
|
|
1712
|
+
{
|
|
1713
|
+
class: `pp-country-option ${country.code === selectedCountry.code ? "selected" : ""}`,
|
|
1714
|
+
onClick: () => handleCountrySelect(country),
|
|
1715
|
+
children: [
|
|
1716
|
+
/* @__PURE__ */ jsx("span", { class: "pp-country-flag", children: country.flag }),
|
|
1717
|
+
/* @__PURE__ */ jsx("span", { class: "pp-country-name", children: country.name }),
|
|
1718
|
+
/* @__PURE__ */ jsx("span", { class: "pp-country-dial", children: country.dialCode })
|
|
1719
|
+
]
|
|
1720
|
+
},
|
|
1721
|
+
country.code
|
|
1722
|
+
)) })
|
|
1723
|
+
] })
|
|
1724
|
+
] }),
|
|
1725
|
+
/* @__PURE__ */ jsx(
|
|
1726
|
+
"input",
|
|
1727
|
+
{
|
|
1728
|
+
type: "tel",
|
|
1729
|
+
class: `pp-prechat-input pp-phone-number-input ${phoneError ? "error" : ""}`,
|
|
1730
|
+
placeholder: "612 345 678",
|
|
1731
|
+
value: phone,
|
|
1732
|
+
onInput: handlePhoneChange
|
|
1733
|
+
}
|
|
1734
|
+
)
|
|
1735
|
+
] }),
|
|
1736
|
+
phoneError && /* @__PURE__ */ jsx("div", { class: "pp-prechat-error", children: phoneError })
|
|
1737
|
+
] });
|
|
1738
|
+
return /* @__PURE__ */ jsxs("div", { class: "pp-prechat", children: [
|
|
1739
|
+
/* @__PURE__ */ jsx("h2", { class: "pp-prechat-title", children: "How can we reach you?" }),
|
|
1740
|
+
/* @__PURE__ */ jsx("p", { class: "pp-prechat-subtitle", children: showBoth ? "Please provide your contact information so we can follow up if needed." : showChoice ? "Choose how you would like us to contact you." : showEmailOnly ? "Enter your email so we can follow up with you." : "Enter your phone number so we can call you back." }),
|
|
1741
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
|
|
1742
|
+
showChoice && /* @__PURE__ */ jsxs("div", { class: "pp-prechat-tabs", children: [
|
|
1743
|
+
/* @__PURE__ */ jsxs(
|
|
1744
|
+
"button",
|
|
1745
|
+
{
|
|
1746
|
+
type: "button",
|
|
1747
|
+
class: `pp-prechat-tab ${activeTab === "email" ? "active" : ""}`,
|
|
1748
|
+
onClick: () => {
|
|
1749
|
+
setActiveTab("email");
|
|
1750
|
+
setPhoneError("");
|
|
1751
|
+
},
|
|
1752
|
+
children: [
|
|
1753
|
+
/* @__PURE__ */ jsx(EmailIcon, {}),
|
|
1754
|
+
"Email"
|
|
1755
|
+
]
|
|
1756
|
+
}
|
|
1757
|
+
),
|
|
1758
|
+
/* @__PURE__ */ jsxs(
|
|
1759
|
+
"button",
|
|
1760
|
+
{
|
|
1761
|
+
type: "button",
|
|
1762
|
+
class: `pp-prechat-tab ${activeTab === "phone" ? "active" : ""}`,
|
|
1763
|
+
onClick: () => {
|
|
1764
|
+
setActiveTab("phone");
|
|
1765
|
+
setEmailError("");
|
|
1766
|
+
},
|
|
1767
|
+
children: [
|
|
1768
|
+
/* @__PURE__ */ jsx(PhoneIcon, {}),
|
|
1769
|
+
"Phone"
|
|
1770
|
+
]
|
|
1771
|
+
}
|
|
1772
|
+
)
|
|
1773
|
+
] }),
|
|
1774
|
+
showEmailOnly && renderEmailField(),
|
|
1775
|
+
showPhoneOnly && renderPhoneField(),
|
|
1776
|
+
showBoth && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1777
|
+
renderEmailField(),
|
|
1778
|
+
renderPhoneField()
|
|
1779
|
+
] }),
|
|
1780
|
+
showChoice && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1781
|
+
activeTab === "email" && renderEmailField(),
|
|
1782
|
+
activeTab === "phone" && renderPhoneField()
|
|
1783
|
+
] }),
|
|
1784
|
+
/* @__PURE__ */ jsx("button", { type: "submit", class: "pp-prechat-submit", disabled: isSubmitting, children: isSubmitting ? "Submitting..." : "Start chatting" }),
|
|
1785
|
+
!config.required && /* @__PURE__ */ jsx("button", { type: "button", class: "pp-prechat-skip", onClick: onSkip, children: "Skip for now" })
|
|
1786
|
+
] })
|
|
1787
|
+
] });
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1073
1790
|
// src/components/ChatWidget.tsx
|
|
1074
|
-
import { Fragment as
|
|
1791
|
+
import { Fragment as Fragment3, jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
1075
1792
|
function formatDateSeparator(date) {
|
|
1076
1793
|
const now = /* @__PURE__ */ new Date();
|
|
1077
1794
|
const messageDate = new Date(date);
|
|
@@ -1091,28 +1808,33 @@ function getDateKey(date) {
|
|
|
1091
1808
|
return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
|
|
1092
1809
|
}
|
|
1093
1810
|
function ChatWidget({ client: client2, config: initialConfig }) {
|
|
1094
|
-
const [isOpen, setIsOpen] =
|
|
1095
|
-
const [messages, setMessages] =
|
|
1096
|
-
const [inputValue, setInputValue] =
|
|
1097
|
-
const [isTyping, setIsTyping] =
|
|
1098
|
-
const [operatorOnline, setOperatorOnline] =
|
|
1099
|
-
const [isConnected, setIsConnected] =
|
|
1100
|
-
const [unreadCount, setUnreadCount] =
|
|
1101
|
-
const [pendingAttachments, setPendingAttachments] =
|
|
1102
|
-
const [isUploading, setIsUploading] =
|
|
1103
|
-
const [replyingTo, setReplyingTo] =
|
|
1104
|
-
const [editingMessage, setEditingMessage] =
|
|
1105
|
-
const [editContent, setEditContent] =
|
|
1106
|
-
const [messageMenu, setMessageMenu] =
|
|
1107
|
-
const [isDragging, setIsDragging] =
|
|
1108
|
-
const [hoveredMessageId, setHoveredMessageId] =
|
|
1109
|
-
const [longPressTimer, setLongPressTimer] =
|
|
1110
|
-
const [
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1113
|
-
const
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1811
|
+
const [isOpen, setIsOpen] = useState2(false);
|
|
1812
|
+
const [messages, setMessages] = useState2([]);
|
|
1813
|
+
const [inputValue, setInputValue] = useState2("");
|
|
1814
|
+
const [isTyping, setIsTyping] = useState2(false);
|
|
1815
|
+
const [operatorOnline, setOperatorOnline] = useState2(false);
|
|
1816
|
+
const [isConnected, setIsConnected] = useState2(false);
|
|
1817
|
+
const [unreadCount, setUnreadCount] = useState2(0);
|
|
1818
|
+
const [pendingAttachments, setPendingAttachments] = useState2([]);
|
|
1819
|
+
const [isUploading, setIsUploading] = useState2(false);
|
|
1820
|
+
const [replyingTo, setReplyingTo] = useState2(null);
|
|
1821
|
+
const [editingMessage, setEditingMessage] = useState2(null);
|
|
1822
|
+
const [editContent, setEditContent] = useState2("");
|
|
1823
|
+
const [messageMenu, setMessageMenu] = useState2(null);
|
|
1824
|
+
const [isDragging, setIsDragging] = useState2(false);
|
|
1825
|
+
const [hoveredMessageId, setHoveredMessageId] = useState2(null);
|
|
1826
|
+
const [longPressTimer, setLongPressTimer] = useState2(null);
|
|
1827
|
+
const [swipedMessageId, setSwipedMessageId] = useState2(null);
|
|
1828
|
+
const [swipeOffset, setSwipeOffset] = useState2(0);
|
|
1829
|
+
const touchStartRef = useRef2(null);
|
|
1830
|
+
const [config, setConfig] = useState2(initialConfig);
|
|
1831
|
+
const [preChatForm, setPreChatForm] = useState2(void 0);
|
|
1832
|
+
const [preChatSkipped, setPreChatSkipped] = useState2(false);
|
|
1833
|
+
const messagesEndRef = useRef2(null);
|
|
1834
|
+
const inputRef = useRef2(null);
|
|
1835
|
+
const fileInputRef = useRef2(null);
|
|
1836
|
+
const messagesContainerRef = useRef2(null);
|
|
1837
|
+
useEffect2(() => {
|
|
1116
1838
|
const unsubOpen = client2.on("openChange", setIsOpen);
|
|
1117
1839
|
const unsubMessage = client2.on("message", () => {
|
|
1118
1840
|
setMessages([...client2.getMessages()]);
|
|
@@ -1128,6 +1850,10 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1128
1850
|
setMessages(client2.getMessages());
|
|
1129
1851
|
setOperatorOnline(client2.getSession()?.operatorOnline ?? false);
|
|
1130
1852
|
setConfig(client2.getConfig());
|
|
1853
|
+
setPreChatForm(client2.getSession()?.preChatForm);
|
|
1854
|
+
});
|
|
1855
|
+
const unsubPreChat = client2.on("preChatCompleted", () => {
|
|
1856
|
+
setPreChatForm((prev) => prev ? { ...prev, completed: true } : prev);
|
|
1131
1857
|
});
|
|
1132
1858
|
const unsubConfig = client2.on("configUpdate", () => {
|
|
1133
1859
|
setConfig(client2.getConfig());
|
|
@@ -1137,6 +1863,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1137
1863
|
setMessages(client2.getMessages());
|
|
1138
1864
|
setOperatorOnline(client2.getSession()?.operatorOnline ?? false);
|
|
1139
1865
|
setConfig(client2.getConfig());
|
|
1866
|
+
setPreChatForm(client2.getSession()?.preChatForm);
|
|
1140
1867
|
}
|
|
1141
1868
|
return () => {
|
|
1142
1869
|
unsubOpen();
|
|
@@ -1144,15 +1871,16 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1144
1871
|
unsubTyping();
|
|
1145
1872
|
unsubPresence();
|
|
1146
1873
|
unsubConnect();
|
|
1874
|
+
unsubPreChat();
|
|
1147
1875
|
unsubConfig();
|
|
1148
1876
|
};
|
|
1149
1877
|
}, [client2]);
|
|
1150
|
-
|
|
1878
|
+
useEffect2(() => {
|
|
1151
1879
|
if (isOpen) {
|
|
1152
1880
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1153
1881
|
}
|
|
1154
1882
|
}, [messages, isOpen]);
|
|
1155
|
-
|
|
1883
|
+
useEffect2(() => {
|
|
1156
1884
|
if (isOpen) {
|
|
1157
1885
|
setTimeout(() => {
|
|
1158
1886
|
messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
|
|
@@ -1161,7 +1889,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1161
1889
|
setUnreadCount(0);
|
|
1162
1890
|
}
|
|
1163
1891
|
}, [isOpen]);
|
|
1164
|
-
|
|
1892
|
+
useEffect2(() => {
|
|
1165
1893
|
if (!isOpen && messages.length > 0) {
|
|
1166
1894
|
const unread = messages.filter(
|
|
1167
1895
|
(msg) => msg.sender !== "visitor" && msg.status !== "read"
|
|
@@ -1179,14 +1907,14 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1179
1907
|
client2.sendReadStatus(messageIds, "read");
|
|
1180
1908
|
}
|
|
1181
1909
|
}, [isOpen, isConnected, messages, client2]);
|
|
1182
|
-
|
|
1910
|
+
useEffect2(() => {
|
|
1183
1911
|
if (!isOpen || !isConnected) return;
|
|
1184
1912
|
const timer = setTimeout(() => {
|
|
1185
1913
|
markMessagesAsRead();
|
|
1186
1914
|
}, 1e3);
|
|
1187
1915
|
return () => clearTimeout(timer);
|
|
1188
1916
|
}, [isOpen, isConnected, messages, markMessagesAsRead]);
|
|
1189
|
-
|
|
1917
|
+
useEffect2(() => {
|
|
1190
1918
|
const handleVisibilityChange = () => {
|
|
1191
1919
|
if (document.visibilityState === "visible" && isOpen) {
|
|
1192
1920
|
markMessagesAsRead();
|
|
@@ -1195,7 +1923,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1195
1923
|
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1196
1924
|
return () => document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1197
1925
|
}, [isOpen, markMessagesAsRead]);
|
|
1198
|
-
|
|
1926
|
+
useEffect2(() => {
|
|
1199
1927
|
const unsubRead = client2.on(
|
|
1200
1928
|
"read",
|
|
1201
1929
|
() => {
|
|
@@ -1334,26 +2062,43 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1334
2062
|
y: mouseEvent.clientY
|
|
1335
2063
|
});
|
|
1336
2064
|
};
|
|
1337
|
-
const handleTouchStart = (message) => {
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
y: window.innerHeight / 2 - 50
|
|
1345
|
-
// Center vertically
|
|
1346
|
-
});
|
|
1347
|
-
}, 500);
|
|
1348
|
-
setLongPressTimer(timer);
|
|
2065
|
+
const handleTouchStart = (e, message) => {
|
|
2066
|
+
const touch = e.touches[0];
|
|
2067
|
+
touchStartRef.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
|
|
2068
|
+
if (swipedMessageId && swipedMessageId !== message.id) {
|
|
2069
|
+
setSwipedMessageId(null);
|
|
2070
|
+
setSwipeOffset(0);
|
|
2071
|
+
}
|
|
1349
2072
|
};
|
|
1350
|
-
const
|
|
1351
|
-
if (
|
|
1352
|
-
|
|
1353
|
-
|
|
2073
|
+
const handleTouchMove = (e, message) => {
|
|
2074
|
+
if (!touchStartRef.current) return;
|
|
2075
|
+
const touch = e.touches[0];
|
|
2076
|
+
const deltaX = touch.clientX - touchStartRef.current.x;
|
|
2077
|
+
const deltaY = touch.clientY - touchStartRef.current.y;
|
|
2078
|
+
if (Math.abs(deltaY) > Math.abs(deltaX)) return;
|
|
2079
|
+
if (deltaX < 0) {
|
|
2080
|
+
const offset = Math.max(deltaX, -100);
|
|
2081
|
+
setSwipeOffset(offset);
|
|
2082
|
+
setSwipedMessageId(message.id);
|
|
1354
2083
|
}
|
|
1355
2084
|
};
|
|
1356
|
-
|
|
2085
|
+
const handleTouchEnd = (message) => {
|
|
2086
|
+
if (!touchStartRef.current) return;
|
|
2087
|
+
const elapsed = Date.now() - touchStartRef.current.time;
|
|
2088
|
+
if (swipeOffset < -50 || swipeOffset < -20 && elapsed < 200) {
|
|
2089
|
+
setSwipeOffset(-80);
|
|
2090
|
+
if (navigator.vibrate) navigator.vibrate(30);
|
|
2091
|
+
} else {
|
|
2092
|
+
setSwipeOffset(0);
|
|
2093
|
+
setSwipedMessageId(null);
|
|
2094
|
+
}
|
|
2095
|
+
touchStartRef.current = null;
|
|
2096
|
+
};
|
|
2097
|
+
const resetSwipe = () => {
|
|
2098
|
+
setSwipedMessageId(null);
|
|
2099
|
+
setSwipeOffset(0);
|
|
2100
|
+
};
|
|
2101
|
+
useEffect2(() => {
|
|
1357
2102
|
if (!messageMenu) return;
|
|
1358
2103
|
const handleClickOutside = () => setMessageMenu(null);
|
|
1359
2104
|
document.addEventListener("click", handleClickOutside);
|
|
@@ -1369,7 +2114,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1369
2114
|
}, 1500);
|
|
1370
2115
|
}
|
|
1371
2116
|
};
|
|
1372
|
-
const dragCounterRef =
|
|
2117
|
+
const dragCounterRef = useRef2(0);
|
|
1373
2118
|
const handleDragEnter = (e) => {
|
|
1374
2119
|
e.preventDefault();
|
|
1375
2120
|
e.stopPropagation();
|
|
@@ -1445,22 +2190,24 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1445
2190
|
const theme = getTheme(config.theme ?? "auto");
|
|
1446
2191
|
const primaryColor = config.primaryColor ?? "#6366f1";
|
|
1447
2192
|
const actionIconColor = theme === "dark" ? "#9ca3af" : "#6b7280";
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
2193
|
+
const shouldShowPreChat = preChatForm && preChatForm.enabled && !preChatForm.completed && !preChatSkipped && // Before first message: show immediately
|
|
2194
|
+
(preChatForm.timing === "before-first-message" && messages.length === 0 || preChatForm.timing === "after-first-message" && messages.some((m) => m.sender === "visitor"));
|
|
2195
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2196
|
+
/* @__PURE__ */ jsx2("style", { children: styles(primaryColor, theme) }),
|
|
2197
|
+
/* @__PURE__ */ jsxs2(
|
|
1451
2198
|
"button",
|
|
1452
2199
|
{
|
|
1453
2200
|
class: `pp-toggle pp-${position}`,
|
|
1454
2201
|
onClick: () => client2.toggleOpen(),
|
|
1455
2202
|
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
1456
2203
|
children: [
|
|
1457
|
-
isOpen ? /* @__PURE__ */
|
|
1458
|
-
!isOpen && unreadCount > 0 && /* @__PURE__ */
|
|
1459
|
-
!isOpen && unreadCount === 0 && operatorOnline && /* @__PURE__ */
|
|
2204
|
+
isOpen ? /* @__PURE__ */ jsx2(CloseIcon, {}) : /* @__PURE__ */ jsx2(ChatIcon, {}),
|
|
2205
|
+
!isOpen && unreadCount > 0 && /* @__PURE__ */ jsx2("span", { class: "pp-unread-badge", children: unreadCount > 9 ? "9+" : unreadCount }),
|
|
2206
|
+
!isOpen && unreadCount === 0 && operatorOnline && /* @__PURE__ */ jsx2("span", { class: "pp-online-dot" })
|
|
1460
2207
|
]
|
|
1461
2208
|
}
|
|
1462
2209
|
),
|
|
1463
|
-
isOpen && /* @__PURE__ */
|
|
2210
|
+
isOpen && /* @__PURE__ */ jsxs2(
|
|
1464
2211
|
"div",
|
|
1465
2212
|
{
|
|
1466
2213
|
class: `pp-window pp-${position} pp-theme-${theme} ${isDragging ? "pp-dragging" : ""}`,
|
|
@@ -1469,36 +2216,49 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1469
2216
|
onDragLeave: handleDragLeave,
|
|
1470
2217
|
onDrop: handleDrop,
|
|
1471
2218
|
children: [
|
|
1472
|
-
isDragging && /* @__PURE__ */
|
|
1473
|
-
/* @__PURE__ */
|
|
1474
|
-
/* @__PURE__ */
|
|
2219
|
+
isDragging && /* @__PURE__ */ jsxs2("div", { class: "pp-drop-overlay", children: [
|
|
2220
|
+
/* @__PURE__ */ jsx2("div", { class: "pp-drop-icon", children: /* @__PURE__ */ jsx2(AttachIcon, {}) }),
|
|
2221
|
+
/* @__PURE__ */ jsx2("div", { class: "pp-drop-text", children: "Drop files to upload" })
|
|
1475
2222
|
] }),
|
|
1476
|
-
/* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1478
|
-
config.operatorAvatar && /* @__PURE__ */
|
|
1479
|
-
/* @__PURE__ */
|
|
1480
|
-
/* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
/* @__PURE__ */
|
|
2223
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-header", children: [
|
|
2224
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-header-info", children: [
|
|
2225
|
+
config.operatorAvatar && /* @__PURE__ */ jsx2("img", { src: config.operatorAvatar, alt: "", class: "pp-avatar" }),
|
|
2226
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
2227
|
+
/* @__PURE__ */ jsx2("div", { class: "pp-header-title", children: config.operatorName ?? "Support" }),
|
|
2228
|
+
/* @__PURE__ */ jsx2("div", { class: "pp-header-status", children: operatorOnline ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2229
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-status-dot pp-online" }),
|
|
1483
2230
|
" Online"
|
|
1484
|
-
] }) : /* @__PURE__ */
|
|
1485
|
-
/* @__PURE__ */
|
|
2231
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2232
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-status-dot" }),
|
|
1486
2233
|
" Away"
|
|
1487
2234
|
] }) })
|
|
1488
2235
|
] })
|
|
1489
2236
|
] }),
|
|
1490
|
-
/* @__PURE__ */
|
|
2237
|
+
/* @__PURE__ */ jsx2(
|
|
1491
2238
|
"button",
|
|
1492
2239
|
{
|
|
1493
2240
|
class: "pp-close-btn",
|
|
1494
2241
|
onClick: () => client2.setOpen(false),
|
|
1495
2242
|
"aria-label": "Close chat",
|
|
1496
|
-
children: /* @__PURE__ */
|
|
2243
|
+
children: /* @__PURE__ */ jsx2(CloseIcon, {})
|
|
1497
2244
|
}
|
|
1498
2245
|
)
|
|
1499
2246
|
] }),
|
|
1500
|
-
/* @__PURE__ */
|
|
1501
|
-
|
|
2247
|
+
shouldShowPreChat && preChatForm && /* @__PURE__ */ jsx2(
|
|
2248
|
+
PreChatForm,
|
|
2249
|
+
{
|
|
2250
|
+
client: client2,
|
|
2251
|
+
config: preChatForm,
|
|
2252
|
+
onComplete: () => {
|
|
2253
|
+
setPreChatForm((prev) => prev ? { ...prev, completed: true } : prev);
|
|
2254
|
+
},
|
|
2255
|
+
onSkip: () => {
|
|
2256
|
+
setPreChatSkipped(true);
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
),
|
|
2260
|
+
!shouldShowPreChat && /* @__PURE__ */ jsxs2("div", { class: "pp-messages", ref: messagesContainerRef, onClick: () => swipedMessageId && resetSwipe(), children: [
|
|
2261
|
+
config.welcomeMessage && messages.length === 0 && /* @__PURE__ */ jsx2("div", { class: "pp-welcome", children: config.welcomeMessage }),
|
|
1502
2262
|
messages.map((msg, index) => {
|
|
1503
2263
|
const isDeleted = !!msg.deletedAt;
|
|
1504
2264
|
const isEdited = !!msg.editedAt;
|
|
@@ -1526,125 +2286,168 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1526
2286
|
}
|
|
1527
2287
|
const isHovered = hoveredMessageId === msg.id;
|
|
1528
2288
|
const showActions = isHovered && !isDeleted;
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
2289
|
+
const isSwiped = swipedMessageId === msg.id;
|
|
2290
|
+
const msgSwipeOffset = isSwiped ? swipeOffset : 0;
|
|
2291
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2292
|
+
showDateSeparator && /* @__PURE__ */ jsx2("div", { class: "pp-date-separator", children: /* @__PURE__ */ jsx2("span", { children: formatDateSeparator(msgDate) }) }),
|
|
2293
|
+
/* @__PURE__ */ jsxs2("div", { class: `pp-message-swipe-container ${msg.sender === "visitor" ? "pp-swipe-left" : "pp-swipe-right"}`, children: [
|
|
2294
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-swipe-actions", children: [
|
|
2295
|
+
/* @__PURE__ */ jsx2(
|
|
2296
|
+
"button",
|
|
2297
|
+
{
|
|
2298
|
+
class: "pp-swipe-action pp-swipe-reply",
|
|
2299
|
+
onClick: () => {
|
|
2300
|
+
handleReply(msg);
|
|
2301
|
+
resetSwipe();
|
|
2302
|
+
},
|
|
2303
|
+
children: /* @__PURE__ */ jsx2(ReplyIcon, { color: "#fff" })
|
|
2304
|
+
}
|
|
2305
|
+
),
|
|
2306
|
+
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2307
|
+
/* @__PURE__ */ jsx2(
|
|
2308
|
+
"button",
|
|
2309
|
+
{
|
|
2310
|
+
class: "pp-swipe-action pp-swipe-edit",
|
|
2311
|
+
onClick: () => {
|
|
2312
|
+
handleStartEdit(msg);
|
|
2313
|
+
resetSwipe();
|
|
2314
|
+
},
|
|
2315
|
+
children: /* @__PURE__ */ jsx2(EditIcon, { color: "#fff" })
|
|
2316
|
+
}
|
|
2317
|
+
),
|
|
2318
|
+
/* @__PURE__ */ jsx2(
|
|
2319
|
+
"button",
|
|
2320
|
+
{
|
|
2321
|
+
class: "pp-swipe-action pp-swipe-delete",
|
|
2322
|
+
onClick: () => {
|
|
2323
|
+
handleDelete(msg);
|
|
2324
|
+
resetSwipe();
|
|
2325
|
+
},
|
|
2326
|
+
children: /* @__PURE__ */ jsx2(DeleteIcon, { color: "#fff" })
|
|
2327
|
+
}
|
|
2328
|
+
)
|
|
2329
|
+
] })
|
|
2330
|
+
] }),
|
|
2331
|
+
/* @__PURE__ */ jsxs2(
|
|
2332
|
+
"div",
|
|
2333
|
+
{
|
|
2334
|
+
id: `pp-msg-${msg.id}`,
|
|
2335
|
+
class: `pp-message pp-message-${msg.sender} ${isDeleted ? "pp-message-deleted" : ""}`,
|
|
2336
|
+
style: { transform: `translateX(${msgSwipeOffset}px)`, transition: touchStartRef.current ? "none" : "transform 0.2s ease-out" },
|
|
2337
|
+
onContextMenu: (e) => handleMessageContextMenu(e, msg),
|
|
2338
|
+
onMouseEnter: () => setHoveredMessageId(msg.id),
|
|
2339
|
+
onMouseLeave: () => setHoveredMessageId(null),
|
|
2340
|
+
onTouchStart: (e) => handleTouchStart(e, msg),
|
|
2341
|
+
onTouchMove: (e) => handleTouchMove(e, msg),
|
|
2342
|
+
onTouchEnd: () => handleTouchEnd(msg),
|
|
2343
|
+
onTouchCancel: () => handleTouchEnd(msg),
|
|
2344
|
+
children: [
|
|
2345
|
+
showActions && /* @__PURE__ */ jsxs2("div", { class: `pp-message-actions ${msg.sender === "visitor" ? "pp-actions-left" : "pp-actions-right"}`, children: [
|
|
2346
|
+
/* @__PURE__ */ jsx2(
|
|
1555
2347
|
"button",
|
|
1556
2348
|
{
|
|
1557
2349
|
class: "pp-action-btn",
|
|
1558
|
-
onClick: () =>
|
|
1559
|
-
title: "
|
|
1560
|
-
children: /* @__PURE__ */
|
|
2350
|
+
onClick: () => handleReply(msg),
|
|
2351
|
+
title: "Reply",
|
|
2352
|
+
children: /* @__PURE__ */ jsx2(ReplyIcon, { color: actionIconColor })
|
|
1561
2353
|
}
|
|
1562
2354
|
),
|
|
1563
|
-
/* @__PURE__ */
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
2355
|
+
msg.sender === "visitor" && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2356
|
+
/* @__PURE__ */ jsx2(
|
|
2357
|
+
"button",
|
|
2358
|
+
{
|
|
2359
|
+
class: "pp-action-btn",
|
|
2360
|
+
onClick: () => handleStartEdit(msg),
|
|
2361
|
+
title: "Edit",
|
|
2362
|
+
children: /* @__PURE__ */ jsx2(EditIcon, { color: actionIconColor })
|
|
2363
|
+
}
|
|
2364
|
+
),
|
|
2365
|
+
/* @__PURE__ */ jsx2(
|
|
2366
|
+
"button",
|
|
2367
|
+
{
|
|
2368
|
+
class: "pp-action-btn pp-action-delete",
|
|
2369
|
+
onClick: () => handleDelete(msg),
|
|
2370
|
+
title: "Delete",
|
|
2371
|
+
children: /* @__PURE__ */ jsx2(DeleteIcon, { color: actionIconColor })
|
|
2372
|
+
}
|
|
2373
|
+
)
|
|
2374
|
+
] })
|
|
2375
|
+
] }),
|
|
2376
|
+
replyData && (replyData.content || replyData.hasAttachment) && /* @__PURE__ */ jsxs2(
|
|
2377
|
+
"div",
|
|
2378
|
+
{
|
|
2379
|
+
class: "pp-reply-quote pp-reply-quote-clickable",
|
|
2380
|
+
onClick: () => scrollToMessage(replyData.id),
|
|
2381
|
+
role: "button",
|
|
2382
|
+
tabIndex: 0,
|
|
2383
|
+
onKeyDown: (e) => e.key === "Enter" && scrollToMessage(replyData.id),
|
|
2384
|
+
children: [
|
|
2385
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-reply-sender", children: replyData.sender === "visitor" ? "You" : "Support" }),
|
|
2386
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-reply-content", children: replyData.deleted ? "Message deleted" : /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2387
|
+
replyData.hasAttachment && /* @__PURE__ */ jsx2("span", { class: "pp-reply-attachment-icon", children: replyData.attachmentType?.startsWith("image/") ? "\u{1F4F7} " : "\u{1F4CE} " }),
|
|
2388
|
+
replyData.content ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2389
|
+
(replyData.content || "").slice(0, 50),
|
|
2390
|
+
(replyData.content || "").length > 50 ? "..." : ""
|
|
2391
|
+
] }) : replyData.attachmentType?.startsWith("image/") ? "Photo" : "File"
|
|
2392
|
+
] }) })
|
|
2393
|
+
]
|
|
2394
|
+
}
|
|
2395
|
+
),
|
|
2396
|
+
isDeleted ? /* @__PURE__ */ jsxs2("div", { class: "pp-message-content pp-deleted-content", children: [
|
|
2397
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-deleted-icon", children: "\u{1F5D1}\uFE0F" }),
|
|
2398
|
+
" Message deleted"
|
|
2399
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2400
|
+
msg.content && /* @__PURE__ */ jsx2("div", { class: "pp-message-content", children: msg.content }),
|
|
2401
|
+
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ jsx2("div", { class: "pp-message-attachments", children: msg.attachments.map((att) => /* @__PURE__ */ jsx2(AttachmentDisplay, { attachment: att }, att.id)) })
|
|
2402
|
+
] }),
|
|
2403
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-message-time", children: [
|
|
2404
|
+
formatTime(msg.timestamp),
|
|
2405
|
+
isEdited && !isDeleted && /* @__PURE__ */ jsx2("span", { class: "pp-edited-badge", children: "edited" }),
|
|
2406
|
+
msg.sender === "ai" && /* @__PURE__ */ jsx2("span", { class: "pp-ai-badge", children: "AI" }),
|
|
2407
|
+
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ jsx2("span", { class: `pp-status pp-status-${msg.status ?? "sent"}`, children: /* @__PURE__ */ jsx2(StatusIcon, { status: msg.status }) })
|
|
1572
2408
|
] })
|
|
1573
|
-
]
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
class: "pp-reply-quote pp-reply-quote-clickable",
|
|
1578
|
-
onClick: () => scrollToMessage(replyData.id),
|
|
1579
|
-
role: "button",
|
|
1580
|
-
tabIndex: 0,
|
|
1581
|
-
onKeyDown: (e) => e.key === "Enter" && scrollToMessage(replyData.id),
|
|
1582
|
-
children: [
|
|
1583
|
-
/* @__PURE__ */ jsx("span", { class: "pp-reply-sender", children: replyData.sender === "visitor" ? "You" : "Support" }),
|
|
1584
|
-
/* @__PURE__ */ jsx("span", { class: "pp-reply-content", children: replyData.deleted ? "Message deleted" : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1585
|
-
replyData.hasAttachment && /* @__PURE__ */ jsx("span", { class: "pp-reply-attachment-icon", children: replyData.attachmentType?.startsWith("image/") ? "\u{1F4F7} " : "\u{1F4CE} " }),
|
|
1586
|
-
replyData.content ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1587
|
-
(replyData.content || "").slice(0, 50),
|
|
1588
|
-
(replyData.content || "").length > 50 ? "..." : ""
|
|
1589
|
-
] }) : replyData.attachmentType?.startsWith("image/") ? "Photo" : "File"
|
|
1590
|
-
] }) })
|
|
1591
|
-
]
|
|
1592
|
-
}
|
|
1593
|
-
),
|
|
1594
|
-
isDeleted ? /* @__PURE__ */ jsxs("div", { class: "pp-message-content pp-deleted-content", children: [
|
|
1595
|
-
/* @__PURE__ */ jsx("span", { class: "pp-deleted-icon", children: "\u{1F5D1}\uFE0F" }),
|
|
1596
|
-
" Message deleted"
|
|
1597
|
-
] }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1598
|
-
msg.content && /* @__PURE__ */ jsx("div", { class: "pp-message-content", children: msg.content }),
|
|
1599
|
-
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ jsx("div", { class: "pp-message-attachments", children: msg.attachments.map((att) => /* @__PURE__ */ jsx(AttachmentDisplay, { attachment: att }, att.id)) })
|
|
1600
|
-
] }),
|
|
1601
|
-
/* @__PURE__ */ jsxs("div", { class: "pp-message-time", children: [
|
|
1602
|
-
formatTime(msg.timestamp),
|
|
1603
|
-
isEdited && !isDeleted && /* @__PURE__ */ jsx("span", { class: "pp-edited-badge", children: "edited" }),
|
|
1604
|
-
msg.sender === "ai" && /* @__PURE__ */ jsx("span", { class: "pp-ai-badge", children: "AI" }),
|
|
1605
|
-
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ jsx("span", { class: `pp-status pp-status-${msg.status ?? "sent"}`, children: /* @__PURE__ */ jsx(StatusIcon, { status: msg.status }) })
|
|
1606
|
-
] })
|
|
1607
|
-
]
|
|
1608
|
-
}
|
|
1609
|
-
)
|
|
2409
|
+
]
|
|
2410
|
+
}
|
|
2411
|
+
)
|
|
2412
|
+
] })
|
|
1610
2413
|
] }, msg.id);
|
|
1611
2414
|
}),
|
|
1612
|
-
isTyping && /* @__PURE__ */
|
|
1613
|
-
/* @__PURE__ */
|
|
1614
|
-
/* @__PURE__ */
|
|
1615
|
-
/* @__PURE__ */
|
|
2415
|
+
isTyping && /* @__PURE__ */ jsxs2("div", { class: "pp-message pp-message-operator pp-typing", children: [
|
|
2416
|
+
/* @__PURE__ */ jsx2("span", {}),
|
|
2417
|
+
/* @__PURE__ */ jsx2("span", {}),
|
|
2418
|
+
/* @__PURE__ */ jsx2("span", {})
|
|
1616
2419
|
] }),
|
|
1617
|
-
/* @__PURE__ */
|
|
2420
|
+
/* @__PURE__ */ jsx2("div", { ref: messagesEndRef })
|
|
1618
2421
|
] }),
|
|
1619
|
-
messageMenu && /* @__PURE__ */
|
|
2422
|
+
messageMenu && /* @__PURE__ */ jsxs2(
|
|
1620
2423
|
"div",
|
|
1621
2424
|
{
|
|
1622
2425
|
class: "pp-message-menu",
|
|
1623
2426
|
style: { top: `${messageMenu.y}px`, left: `${messageMenu.x}px` },
|
|
1624
2427
|
children: [
|
|
1625
|
-
/* @__PURE__ */
|
|
1626
|
-
/* @__PURE__ */
|
|
2428
|
+
/* @__PURE__ */ jsxs2("button", { onClick: () => handleReply(messageMenu.message), children: [
|
|
2429
|
+
/* @__PURE__ */ jsx2(ReplyIcon, { color: actionIconColor }),
|
|
1627
2430
|
" Reply"
|
|
1628
2431
|
] }),
|
|
1629
|
-
messageMenu.message.sender === "visitor" && !messageMenu.message.deletedAt && /* @__PURE__ */
|
|
1630
|
-
/* @__PURE__ */
|
|
1631
|
-
/* @__PURE__ */
|
|
2432
|
+
messageMenu.message.sender === "visitor" && !messageMenu.message.deletedAt && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2433
|
+
/* @__PURE__ */ jsxs2("button", { onClick: () => handleStartEdit(messageMenu.message), children: [
|
|
2434
|
+
/* @__PURE__ */ jsx2(EditIcon, { color: actionIconColor }),
|
|
1632
2435
|
" Edit"
|
|
1633
2436
|
] }),
|
|
1634
|
-
/* @__PURE__ */
|
|
1635
|
-
/* @__PURE__ */
|
|
2437
|
+
/* @__PURE__ */ jsxs2("button", { class: "pp-menu-delete", onClick: () => handleDelete(messageMenu.message), children: [
|
|
2438
|
+
/* @__PURE__ */ jsx2(DeleteIcon, { color: "#ef4444" }),
|
|
1636
2439
|
" Delete"
|
|
1637
2440
|
] })
|
|
1638
2441
|
] })
|
|
1639
2442
|
]
|
|
1640
2443
|
}
|
|
1641
2444
|
),
|
|
1642
|
-
editingMessage && /* @__PURE__ */
|
|
1643
|
-
/* @__PURE__ */
|
|
1644
|
-
/* @__PURE__ */
|
|
1645
|
-
/* @__PURE__ */
|
|
2445
|
+
editingMessage && /* @__PURE__ */ jsxs2("div", { class: "pp-edit-modal", children: [
|
|
2446
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-edit-header", children: [
|
|
2447
|
+
/* @__PURE__ */ jsx2("span", { children: "Edit message" }),
|
|
2448
|
+
/* @__PURE__ */ jsx2("button", { onClick: handleCancelEdit, children: /* @__PURE__ */ jsx2(CloseIcon, {}) })
|
|
1646
2449
|
] }),
|
|
1647
|
-
/* @__PURE__ */
|
|
2450
|
+
/* @__PURE__ */ jsx2(
|
|
1648
2451
|
"textarea",
|
|
1649
2452
|
{
|
|
1650
2453
|
class: "pp-edit-input",
|
|
@@ -1653,41 +2456,41 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1653
2456
|
autoFocus: true
|
|
1654
2457
|
}
|
|
1655
2458
|
),
|
|
1656
|
-
/* @__PURE__ */
|
|
1657
|
-
/* @__PURE__ */
|
|
1658
|
-
/* @__PURE__ */
|
|
2459
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-edit-actions", children: [
|
|
2460
|
+
/* @__PURE__ */ jsx2("button", { class: "pp-edit-cancel", onClick: handleCancelEdit, children: "Cancel" }),
|
|
2461
|
+
/* @__PURE__ */ jsx2("button", { class: "pp-edit-save", onClick: handleSaveEdit, disabled: !editContent.trim(), children: "Save" })
|
|
1659
2462
|
] })
|
|
1660
2463
|
] }),
|
|
1661
|
-
replyingTo && /* @__PURE__ */
|
|
1662
|
-
/* @__PURE__ */
|
|
1663
|
-
/* @__PURE__ */
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
replyingTo.attachments && replyingTo.attachments.length > 0 && /* @__PURE__ */
|
|
1666
|
-
replyingTo.content ? /* @__PURE__ */
|
|
2464
|
+
replyingTo && /* @__PURE__ */ jsxs2("div", { class: "pp-reply-preview", children: [
|
|
2465
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-reply-preview-content", children: [
|
|
2466
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-reply-label", children: "Replying to" }),
|
|
2467
|
+
/* @__PURE__ */ jsxs2("span", { class: "pp-reply-text", children: [
|
|
2468
|
+
replyingTo.attachments && replyingTo.attachments.length > 0 && /* @__PURE__ */ jsx2("span", { class: "pp-reply-attachment-icon", children: replyingTo.attachments[0].mimeType.startsWith("image/") ? "\u{1F4F7} " : "\u{1F4CE} " }),
|
|
2469
|
+
replyingTo.content ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
1667
2470
|
replyingTo.content.slice(0, 50),
|
|
1668
2471
|
replyingTo.content.length > 50 ? "..." : ""
|
|
1669
2472
|
] }) : replyingTo.attachments?.[0]?.mimeType.startsWith("image/") ? "Photo" : "File"
|
|
1670
2473
|
] })
|
|
1671
2474
|
] }),
|
|
1672
|
-
/* @__PURE__ */
|
|
2475
|
+
/* @__PURE__ */ jsx2("button", { class: "pp-reply-cancel", onClick: handleCancelReply, children: /* @__PURE__ */ jsx2(CloseIcon, {}) })
|
|
1673
2476
|
] }),
|
|
1674
|
-
pendingAttachments.length > 0 && /* @__PURE__ */
|
|
1675
|
-
pending.preview ? /* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
2477
|
+
pendingAttachments.length > 0 && /* @__PURE__ */ jsx2("div", { class: "pp-attachments-preview", children: pendingAttachments.map((pending) => /* @__PURE__ */ jsxs2("div", { class: `pp-attachment-preview pp-attachment-${pending.status}`, children: [
|
|
2478
|
+
pending.preview ? /* @__PURE__ */ jsx2("img", { src: pending.preview, alt: pending.file.name, class: "pp-preview-img" }) : /* @__PURE__ */ jsx2("div", { class: "pp-preview-file", children: /* @__PURE__ */ jsx2(FileIcon, { mimeType: pending.file.type }) }),
|
|
2479
|
+
/* @__PURE__ */ jsx2(
|
|
1677
2480
|
"button",
|
|
1678
2481
|
{
|
|
1679
2482
|
class: "pp-remove-attachment",
|
|
1680
2483
|
onClick: () => handleRemoveAttachment(pending.id),
|
|
1681
2484
|
"aria-label": "Remove attachment",
|
|
1682
2485
|
type: "button",
|
|
1683
|
-
children: /* @__PURE__ */
|
|
2486
|
+
children: /* @__PURE__ */ jsx2(CloseIcon, {})
|
|
1684
2487
|
}
|
|
1685
2488
|
),
|
|
1686
|
-
pending.status === "uploading" && /* @__PURE__ */
|
|
1687
|
-
pending.status === "error" && /* @__PURE__ */
|
|
2489
|
+
pending.status === "uploading" && /* @__PURE__ */ jsx2("div", { class: "pp-upload-progress", style: { width: `${pending.progress}%` } }),
|
|
2490
|
+
pending.status === "error" && /* @__PURE__ */ jsx2("div", { class: "pp-upload-error", title: pending.error, children: "!" })
|
|
1688
2491
|
] }, pending.id)) }),
|
|
1689
|
-
/* @__PURE__ */
|
|
1690
|
-
/* @__PURE__ */
|
|
2492
|
+
!shouldShowPreChat && /* @__PURE__ */ jsxs2("form", { class: "pp-input-form", onSubmit: handleSubmit, children: [
|
|
2493
|
+
/* @__PURE__ */ jsx2(
|
|
1691
2494
|
"input",
|
|
1692
2495
|
{
|
|
1693
2496
|
ref: (el) => {
|
|
@@ -1702,7 +2505,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1702
2505
|
multiple: true
|
|
1703
2506
|
}
|
|
1704
2507
|
),
|
|
1705
|
-
/* @__PURE__ */
|
|
2508
|
+
/* @__PURE__ */ jsx2(
|
|
1706
2509
|
"button",
|
|
1707
2510
|
{
|
|
1708
2511
|
type: "button",
|
|
@@ -1710,10 +2513,10 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1710
2513
|
onClick: () => fileInputRef.current?.click(),
|
|
1711
2514
|
disabled: !isConnected || isUploading,
|
|
1712
2515
|
"aria-label": "Attach file",
|
|
1713
|
-
children: /* @__PURE__ */
|
|
2516
|
+
children: /* @__PURE__ */ jsx2(AttachIcon, {})
|
|
1714
2517
|
}
|
|
1715
2518
|
),
|
|
1716
|
-
/* @__PURE__ */
|
|
2519
|
+
/* @__PURE__ */ jsx2(
|
|
1717
2520
|
"input",
|
|
1718
2521
|
{
|
|
1719
2522
|
ref: inputRef,
|
|
@@ -1725,20 +2528,20 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1725
2528
|
disabled: !isConnected
|
|
1726
2529
|
}
|
|
1727
2530
|
),
|
|
1728
|
-
/* @__PURE__ */
|
|
2531
|
+
/* @__PURE__ */ jsx2(
|
|
1729
2532
|
"button",
|
|
1730
2533
|
{
|
|
1731
2534
|
type: "submit",
|
|
1732
2535
|
class: "pp-send-btn",
|
|
1733
2536
|
disabled: !inputValue.trim() && pendingAttachments.filter((a) => a.status === "ready").length === 0 || !isConnected || isUploading,
|
|
1734
2537
|
"aria-label": "Send message",
|
|
1735
|
-
children: /* @__PURE__ */
|
|
2538
|
+
children: /* @__PURE__ */ jsx2(SendIcon, {})
|
|
1736
2539
|
}
|
|
1737
2540
|
)
|
|
1738
2541
|
] }),
|
|
1739
|
-
/* @__PURE__ */
|
|
2542
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-footer", children: [
|
|
1740
2543
|
"Powered by ",
|
|
1741
|
-
/* @__PURE__ */
|
|
2544
|
+
/* @__PURE__ */ jsx2("a", { href: "https://pocketping.io", target: "_blank", rel: "noopener", children: "PocketPing" })
|
|
1742
2545
|
] })
|
|
1743
2546
|
]
|
|
1744
2547
|
}
|
|
@@ -1766,90 +2569,90 @@ function formatTime(timestamp) {
|
|
|
1766
2569
|
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
1767
2570
|
}
|
|
1768
2571
|
function ChatIcon() {
|
|
1769
|
-
return /* @__PURE__ */
|
|
2572
|
+
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: /* @__PURE__ */ jsx2("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
|
|
1770
2573
|
}
|
|
1771
2574
|
function CloseIcon() {
|
|
1772
|
-
return /* @__PURE__ */
|
|
1773
|
-
/* @__PURE__ */
|
|
1774
|
-
/* @__PURE__ */
|
|
2575
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2576
|
+
/* @__PURE__ */ jsx2("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2577
|
+
/* @__PURE__ */ jsx2("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1775
2578
|
] });
|
|
1776
2579
|
}
|
|
1777
2580
|
function SendIcon() {
|
|
1778
|
-
return /* @__PURE__ */
|
|
1779
|
-
/* @__PURE__ */
|
|
1780
|
-
/* @__PURE__ */
|
|
2581
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2582
|
+
/* @__PURE__ */ jsx2("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
2583
|
+
/* @__PURE__ */ jsx2("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
1781
2584
|
] });
|
|
1782
2585
|
}
|
|
1783
2586
|
function StatusIcon({ status }) {
|
|
1784
2587
|
if (!status || status === "sending" || status === "sent") {
|
|
1785
|
-
return /* @__PURE__ */
|
|
2588
|
+
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", "stroke-width": "2", class: "pp-check", children: /* @__PURE__ */ jsx2("polyline", { points: "3 8 7 12 13 4" }) });
|
|
1786
2589
|
}
|
|
1787
2590
|
if (status === "delivered") {
|
|
1788
|
-
return /* @__PURE__ */
|
|
1789
|
-
/* @__PURE__ */
|
|
1790
|
-
/* @__PURE__ */
|
|
2591
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 20 16", fill: "none", stroke: "currentColor", "stroke-width": "2", class: "pp-check-double", children: [
|
|
2592
|
+
/* @__PURE__ */ jsx2("polyline", { points: "1 8 5 12 11 4" }),
|
|
2593
|
+
/* @__PURE__ */ jsx2("polyline", { points: "7 8 11 12 17 4" })
|
|
1791
2594
|
] });
|
|
1792
2595
|
}
|
|
1793
2596
|
if (status === "read") {
|
|
1794
|
-
return /* @__PURE__ */
|
|
1795
|
-
/* @__PURE__ */
|
|
1796
|
-
/* @__PURE__ */
|
|
2597
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 20 16", fill: "none", stroke: "currentColor", "stroke-width": "2", class: "pp-check-double pp-check-read", children: [
|
|
2598
|
+
/* @__PURE__ */ jsx2("polyline", { points: "1 8 5 12 11 4" }),
|
|
2599
|
+
/* @__PURE__ */ jsx2("polyline", { points: "7 8 11 12 17 4" })
|
|
1797
2600
|
] });
|
|
1798
2601
|
}
|
|
1799
2602
|
return null;
|
|
1800
2603
|
}
|
|
1801
2604
|
function AttachIcon() {
|
|
1802
|
-
return /* @__PURE__ */
|
|
2605
|
+
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: /* @__PURE__ */ jsx2("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) });
|
|
1803
2606
|
}
|
|
1804
2607
|
function ReplyIcon({ color, size = 16 }) {
|
|
1805
2608
|
const strokeColor = color || "currentColor";
|
|
1806
|
-
return /* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
1808
|
-
/* @__PURE__ */
|
|
2609
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", "stroke-width": "2", style: { stroke: strokeColor, width: `${size}px`, minWidth: `${size}px`, height: `${size}px`, display: "block", flexShrink: 0 }, children: [
|
|
2610
|
+
/* @__PURE__ */ jsx2("polyline", { points: "9 17 4 12 9 7" }),
|
|
2611
|
+
/* @__PURE__ */ jsx2("path", { d: "M20 18v-2a4 4 0 0 0-4-4H4" })
|
|
1809
2612
|
] });
|
|
1810
2613
|
}
|
|
1811
2614
|
function EditIcon({ color, size = 16 }) {
|
|
1812
2615
|
const strokeColor = color || "currentColor";
|
|
1813
|
-
return /* @__PURE__ */
|
|
2616
|
+
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", fill: "none", "stroke-width": "2", style: { stroke: strokeColor, width: `${size}px`, minWidth: `${size}px`, height: `${size}px`, display: "block", flexShrink: 0 }, children: /* @__PURE__ */ jsx2("path", { d: "M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" }) });
|
|
1814
2617
|
}
|
|
1815
2618
|
function DeleteIcon({ color, size = 16 }) {
|
|
1816
2619
|
const strokeColor = color || "currentColor";
|
|
1817
|
-
return /* @__PURE__ */
|
|
1818
|
-
/* @__PURE__ */
|
|
1819
|
-
/* @__PURE__ */
|
|
2620
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", "stroke-width": "2", style: { stroke: strokeColor, width: `${size}px`, minWidth: `${size}px`, height: `${size}px`, display: "block", flexShrink: 0 }, children: [
|
|
2621
|
+
/* @__PURE__ */ jsx2("polyline", { points: "3 6 5 6 21 6" }),
|
|
2622
|
+
/* @__PURE__ */ jsx2("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
1820
2623
|
] });
|
|
1821
2624
|
}
|
|
1822
2625
|
function FileIcon({ mimeType }) {
|
|
1823
2626
|
if (mimeType === "application/pdf") {
|
|
1824
|
-
return /* @__PURE__ */
|
|
1825
|
-
/* @__PURE__ */
|
|
1826
|
-
/* @__PURE__ */
|
|
1827
|
-
/* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2628
|
+
/* @__PURE__ */ jsx2("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
2629
|
+
/* @__PURE__ */ jsx2("polyline", { points: "14 2 14 8 20 8" }),
|
|
2630
|
+
/* @__PURE__ */ jsx2("path", { d: "M9 15h6" }),
|
|
2631
|
+
/* @__PURE__ */ jsx2("path", { d: "M9 11h6" })
|
|
1829
2632
|
] });
|
|
1830
2633
|
}
|
|
1831
2634
|
if (mimeType.startsWith("audio/")) {
|
|
1832
|
-
return /* @__PURE__ */
|
|
1833
|
-
/* @__PURE__ */
|
|
1834
|
-
/* @__PURE__ */
|
|
1835
|
-
/* @__PURE__ */
|
|
2635
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2636
|
+
/* @__PURE__ */ jsx2("path", { d: "M9 18V5l12-2v13" }),
|
|
2637
|
+
/* @__PURE__ */ jsx2("circle", { cx: "6", cy: "18", r: "3" }),
|
|
2638
|
+
/* @__PURE__ */ jsx2("circle", { cx: "18", cy: "16", r: "3" })
|
|
1836
2639
|
] });
|
|
1837
2640
|
}
|
|
1838
2641
|
if (mimeType.startsWith("video/")) {
|
|
1839
|
-
return /* @__PURE__ */
|
|
1840
|
-
/* @__PURE__ */
|
|
1841
|
-
/* @__PURE__ */
|
|
1842
|
-
/* @__PURE__ */
|
|
1843
|
-
/* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1845
|
-
/* @__PURE__ */
|
|
1846
|
-
/* @__PURE__ */
|
|
1847
|
-
/* @__PURE__ */
|
|
2642
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2643
|
+
/* @__PURE__ */ jsx2("rect", { x: "2", y: "2", width: "20", height: "20", rx: "2.18", ry: "2.18" }),
|
|
2644
|
+
/* @__PURE__ */ jsx2("line", { x1: "7", y1: "2", x2: "7", y2: "22" }),
|
|
2645
|
+
/* @__PURE__ */ jsx2("line", { x1: "17", y1: "2", x2: "17", y2: "22" }),
|
|
2646
|
+
/* @__PURE__ */ jsx2("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
|
|
2647
|
+
/* @__PURE__ */ jsx2("line", { x1: "2", y1: "7", x2: "7", y2: "7" }),
|
|
2648
|
+
/* @__PURE__ */ jsx2("line", { x1: "2", y1: "17", x2: "7", y2: "17" }),
|
|
2649
|
+
/* @__PURE__ */ jsx2("line", { x1: "17", y1: "17", x2: "22", y2: "17" }),
|
|
2650
|
+
/* @__PURE__ */ jsx2("line", { x1: "17", y1: "7", x2: "22", y2: "7" })
|
|
1848
2651
|
] });
|
|
1849
2652
|
}
|
|
1850
|
-
return /* @__PURE__ */
|
|
1851
|
-
/* @__PURE__ */
|
|
1852
|
-
/* @__PURE__ */
|
|
2653
|
+
return /* @__PURE__ */ jsxs2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2654
|
+
/* @__PURE__ */ jsx2("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
2655
|
+
/* @__PURE__ */ jsx2("polyline", { points: "14 2 14 8 20 8" })
|
|
1853
2656
|
] });
|
|
1854
2657
|
}
|
|
1855
2658
|
function AttachmentDisplay({ attachment }) {
|
|
@@ -1862,22 +2665,22 @@ function AttachmentDisplay({ attachment }) {
|
|
|
1862
2665
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1863
2666
|
};
|
|
1864
2667
|
if (isImage) {
|
|
1865
|
-
return /* @__PURE__ */
|
|
2668
|
+
return /* @__PURE__ */ jsx2("a", { href: attachment.url, target: "_blank", rel: "noopener", class: "pp-attachment pp-attachment-image", children: /* @__PURE__ */ jsx2("img", { src: attachment.thumbnailUrl || attachment.url, alt: attachment.filename }) });
|
|
1866
2669
|
}
|
|
1867
2670
|
if (isAudio) {
|
|
1868
|
-
return /* @__PURE__ */
|
|
1869
|
-
/* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */
|
|
2671
|
+
return /* @__PURE__ */ jsxs2("div", { class: "pp-attachment pp-attachment-audio", children: [
|
|
2672
|
+
/* @__PURE__ */ jsx2("audio", { controls: true, preload: "metadata", children: /* @__PURE__ */ jsx2("source", { src: attachment.url, type: attachment.mimeType }) }),
|
|
2673
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-attachment-name", children: attachment.filename })
|
|
1871
2674
|
] });
|
|
1872
2675
|
}
|
|
1873
2676
|
if (isVideo) {
|
|
1874
|
-
return /* @__PURE__ */
|
|
2677
|
+
return /* @__PURE__ */ jsx2("div", { class: "pp-attachment pp-attachment-video", children: /* @__PURE__ */ jsx2("video", { controls: true, preload: "metadata", children: /* @__PURE__ */ jsx2("source", { src: attachment.url, type: attachment.mimeType }) }) });
|
|
1875
2678
|
}
|
|
1876
|
-
return /* @__PURE__ */
|
|
1877
|
-
/* @__PURE__ */
|
|
1878
|
-
/* @__PURE__ */
|
|
1879
|
-
/* @__PURE__ */
|
|
1880
|
-
/* @__PURE__ */
|
|
2679
|
+
return /* @__PURE__ */ jsxs2("a", { href: attachment.url, target: "_blank", rel: "noopener", class: "pp-attachment pp-attachment-file", children: [
|
|
2680
|
+
/* @__PURE__ */ jsx2(FileIcon, { mimeType: attachment.mimeType }),
|
|
2681
|
+
/* @__PURE__ */ jsxs2("div", { class: "pp-attachment-info", children: [
|
|
2682
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-attachment-name", children: attachment.filename }),
|
|
2683
|
+
/* @__PURE__ */ jsx2("span", { class: "pp-attachment-size", children: formatSize(attachment.size) })
|
|
1881
2684
|
] })
|
|
1882
2685
|
] });
|
|
1883
2686
|
}
|
|
@@ -1943,7 +2746,8 @@ var PocketPingClient = class {
|
|
|
1943
2746
|
visitorId: response.visitorId,
|
|
1944
2747
|
operatorOnline: response.operatorOnline ?? false,
|
|
1945
2748
|
messages: response.messages ?? [],
|
|
1946
|
-
identity: response.identity || storedIdentity || void 0
|
|
2749
|
+
identity: response.identity || storedIdentity || void 0,
|
|
2750
|
+
preChatForm: response.preChatForm
|
|
1947
2751
|
};
|
|
1948
2752
|
if (response.operatorName) {
|
|
1949
2753
|
this.config.operatorName = response.operatorName;
|
|
@@ -2299,6 +3103,36 @@ var PocketPingClient = class {
|
|
|
2299
3103
|
}
|
|
2300
3104
|
}
|
|
2301
3105
|
}
|
|
3106
|
+
/**
|
|
3107
|
+
* Submit pre-chat form data (email and/or phone)
|
|
3108
|
+
* @param data - Form data containing email and/or phone
|
|
3109
|
+
*/
|
|
3110
|
+
async submitPreChat(data) {
|
|
3111
|
+
if (!this.session) {
|
|
3112
|
+
throw new Error("[PocketPing] Not connected");
|
|
3113
|
+
}
|
|
3114
|
+
if (!data.email && !data.phone) {
|
|
3115
|
+
throw new Error("[PocketPing] Either email or phone is required");
|
|
3116
|
+
}
|
|
3117
|
+
try {
|
|
3118
|
+
await this.fetch("/prechat", {
|
|
3119
|
+
method: "POST",
|
|
3120
|
+
body: JSON.stringify({
|
|
3121
|
+
sessionId: this.session.sessionId,
|
|
3122
|
+
email: data.email,
|
|
3123
|
+
phone: data.phone,
|
|
3124
|
+
phoneCountry: data.phoneCountry
|
|
3125
|
+
})
|
|
3126
|
+
});
|
|
3127
|
+
if (this.session.preChatForm) {
|
|
3128
|
+
this.session.preChatForm.completed = true;
|
|
3129
|
+
}
|
|
3130
|
+
this.emit("preChatCompleted", data);
|
|
3131
|
+
} catch (err) {
|
|
3132
|
+
console.error("[PocketPing] Failed to submit pre-chat form:", err);
|
|
3133
|
+
throw err;
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
2302
3136
|
/**
|
|
2303
3137
|
* Reset the user identity and optionally start a new session
|
|
2304
3138
|
* Call on user logout to clear user data
|
|
@@ -2948,6 +3782,12 @@ var PocketPingClient = class {
|
|
|
2948
3782
|
this.session.messages.push(message);
|
|
2949
3783
|
this.emit("message", message);
|
|
2950
3784
|
this.config.onMessage?.(message);
|
|
3785
|
+
if (message.sender !== "visitor" && !this.isOpen) {
|
|
3786
|
+
const autoOpen = this.config.autoOpenOnMessage ?? true;
|
|
3787
|
+
if (autoOpen) {
|
|
3788
|
+
this.setOpen(true);
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
2951
3791
|
}
|
|
2952
3792
|
}
|
|
2953
3793
|
if (message.sender !== "visitor") {
|
|
@@ -3106,6 +3946,12 @@ var PocketPingClient = class {
|
|
|
3106
3946
|
this.session.messages.push(message);
|
|
3107
3947
|
this.emit("message", message);
|
|
3108
3948
|
this.config.onMessage?.(message);
|
|
3949
|
+
if (message.sender !== "visitor" && !this.isOpen) {
|
|
3950
|
+
const autoOpen = this.config.autoOpenOnMessage ?? true;
|
|
3951
|
+
if (autoOpen) {
|
|
3952
|
+
this.setOpen(true);
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3109
3955
|
}
|
|
3110
3956
|
}
|
|
3111
3957
|
} catch (err) {
|