@pocketping/widget 1.5.2 → 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 +1198 -276
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +1198 -276
- package/dist/pocketping.min.global.js +517 -83
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -44,7 +44,7 @@ var import_preact2 = require("preact");
|
|
|
44
44
|
|
|
45
45
|
// src/components/ChatWidget.tsx
|
|
46
46
|
var import_preact = require("preact");
|
|
47
|
-
var
|
|
47
|
+
var import_hooks2 = require("preact/hooks");
|
|
48
48
|
|
|
49
49
|
// src/components/styles.ts
|
|
50
50
|
function styles(primaryColor, theme) {
|
|
@@ -65,6 +65,17 @@ function styles(primaryColor, theme) {
|
|
|
65
65
|
color: ${colors.text};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
#pocketping-container,
|
|
69
|
+
#pocketping-container * {
|
|
70
|
+
box-sizing: border-box;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
#pocketping-container img,
|
|
74
|
+
#pocketping-container video {
|
|
75
|
+
max-width: 100%;
|
|
76
|
+
height: auto;
|
|
77
|
+
}
|
|
78
|
+
|
|
68
79
|
.pp-toggle {
|
|
69
80
|
position: fixed;
|
|
70
81
|
width: 56px;
|
|
@@ -189,7 +200,7 @@ function styles(primaryColor, theme) {
|
|
|
189
200
|
display: flex;
|
|
190
201
|
align-items: center;
|
|
191
202
|
justify-content: space-between;
|
|
192
|
-
padding:
|
|
203
|
+
padding: 12px 14px;
|
|
193
204
|
background: ${primaryColor};
|
|
194
205
|
color: white;
|
|
195
206
|
}
|
|
@@ -197,24 +208,24 @@ function styles(primaryColor, theme) {
|
|
|
197
208
|
.pp-header-info {
|
|
198
209
|
display: flex;
|
|
199
210
|
align-items: center;
|
|
200
|
-
gap:
|
|
211
|
+
gap: 10px;
|
|
201
212
|
}
|
|
202
213
|
|
|
203
214
|
.pp-avatar {
|
|
204
|
-
width:
|
|
205
|
-
height:
|
|
215
|
+
width: 36px;
|
|
216
|
+
height: 36px;
|
|
206
217
|
border-radius: 50%;
|
|
207
218
|
object-fit: cover;
|
|
208
219
|
}
|
|
209
220
|
|
|
210
221
|
.pp-header-title {
|
|
211
222
|
font-weight: 600;
|
|
212
|
-
font-size:
|
|
223
|
+
font-size: 15px;
|
|
213
224
|
}
|
|
214
225
|
|
|
215
226
|
.pp-header-status {
|
|
216
|
-
font-size:
|
|
217
|
-
opacity: 0.
|
|
227
|
+
font-size: 11px;
|
|
228
|
+
opacity: 0.85;
|
|
218
229
|
display: flex;
|
|
219
230
|
align-items: center;
|
|
220
231
|
gap: 4px;
|
|
@@ -260,10 +271,14 @@ function styles(primaryColor, theme) {
|
|
|
260
271
|
.pp-messages {
|
|
261
272
|
flex: 1;
|
|
262
273
|
overflow-y: auto;
|
|
263
|
-
padding:
|
|
274
|
+
padding: 32px 12px 12px 12px;
|
|
264
275
|
display: flex;
|
|
265
276
|
flex-direction: column;
|
|
266
|
-
gap:
|
|
277
|
+
gap: 3px;
|
|
278
|
+
overscroll-behavior: contain;
|
|
279
|
+
-webkit-overflow-scrolling: touch;
|
|
280
|
+
/* Ensure proper stacking context for positioned elements */
|
|
281
|
+
position: relative;
|
|
267
282
|
}
|
|
268
283
|
|
|
269
284
|
.pp-welcome {
|
|
@@ -273,20 +288,110 @@ function styles(primaryColor, theme) {
|
|
|
273
288
|
font-size: 13px;
|
|
274
289
|
}
|
|
275
290
|
|
|
291
|
+
.pp-date-separator {
|
|
292
|
+
display: flex;
|
|
293
|
+
align-items: center;
|
|
294
|
+
justify-content: center;
|
|
295
|
+
margin: 16px 0 12px;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.pp-date-separator span {
|
|
299
|
+
background: ${colors.bgSecondary};
|
|
300
|
+
color: ${colors.textSecondary};
|
|
301
|
+
font-size: 11px;
|
|
302
|
+
padding: 4px 12px;
|
|
303
|
+
border-radius: 12px;
|
|
304
|
+
font-weight: 500;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Swipe container for mobile actions */
|
|
308
|
+
.pp-message-swipe-container {
|
|
309
|
+
position: relative;
|
|
310
|
+
display: flex;
|
|
311
|
+
align-items: stretch;
|
|
312
|
+
overflow: visible;
|
|
313
|
+
touch-action: pan-y;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.pp-swipe-left {
|
|
317
|
+
justify-content: flex-end;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.pp-swipe-right {
|
|
321
|
+
justify-content: flex-start;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.pp-swipe-actions {
|
|
325
|
+
position: absolute;
|
|
326
|
+
right: 0;
|
|
327
|
+
top: 0;
|
|
328
|
+
bottom: 0;
|
|
329
|
+
display: flex;
|
|
330
|
+
align-items: center;
|
|
331
|
+
gap: 4px;
|
|
332
|
+
padding-right: 8px;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.pp-swipe-left .pp-swipe-actions {
|
|
336
|
+
right: 0;
|
|
337
|
+
left: auto;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.pp-swipe-right .pp-swipe-actions {
|
|
341
|
+
left: 0;
|
|
342
|
+
right: auto;
|
|
343
|
+
padding-left: 8px;
|
|
344
|
+
padding-right: 0;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.pp-swipe-action {
|
|
348
|
+
width: 32px;
|
|
349
|
+
height: 32px;
|
|
350
|
+
border: none;
|
|
351
|
+
border-radius: 50%;
|
|
352
|
+
cursor: pointer;
|
|
353
|
+
display: flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
justify-content: center;
|
|
356
|
+
opacity: 0.9;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.pp-swipe-action svg {
|
|
360
|
+
width: 16px;
|
|
361
|
+
height: 16px;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.pp-swipe-reply {
|
|
365
|
+
background: ${primaryColor};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.pp-swipe-edit {
|
|
369
|
+
background: #3b82f6;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.pp-swipe-delete {
|
|
373
|
+
background: #ef4444;
|
|
374
|
+
}
|
|
375
|
+
|
|
276
376
|
.pp-message {
|
|
277
|
-
max-width:
|
|
278
|
-
padding: 10px
|
|
279
|
-
border-radius:
|
|
377
|
+
max-width: 85%;
|
|
378
|
+
padding: 6px 10px;
|
|
379
|
+
border-radius: 12px;
|
|
280
380
|
word-wrap: break-word;
|
|
281
381
|
position: relative;
|
|
282
382
|
user-select: text;
|
|
283
383
|
-webkit-user-select: text;
|
|
384
|
+
font-size: 14px;
|
|
385
|
+
line-height: 1.35;
|
|
386
|
+
display: flex;
|
|
387
|
+
flex-direction: column;
|
|
388
|
+
will-change: transform;
|
|
284
389
|
}
|
|
285
390
|
|
|
286
391
|
/* Hover actions container - positioned above message (Slack style) */
|
|
287
392
|
.pp-message-actions {
|
|
288
393
|
position: absolute;
|
|
289
|
-
top: -
|
|
394
|
+
top: -32px;
|
|
290
395
|
display: flex;
|
|
291
396
|
gap: 2px;
|
|
292
397
|
background: ${colors.bg};
|
|
@@ -299,6 +404,8 @@ function styles(primaryColor, theme) {
|
|
|
299
404
|
z-index: 10;
|
|
300
405
|
/* Reset color inheritance from message */
|
|
301
406
|
color: ${colors.textSecondary};
|
|
407
|
+
/* Ensure actions don't interfere with layout */
|
|
408
|
+
pointer-events: auto;
|
|
302
409
|
}
|
|
303
410
|
|
|
304
411
|
@keyframes pp-actions-fade-in {
|
|
@@ -372,7 +479,8 @@ function styles(primaryColor, theme) {
|
|
|
372
479
|
align-self: flex-end;
|
|
373
480
|
background: ${primaryColor};
|
|
374
481
|
color: white;
|
|
375
|
-
border-bottom-right-radius:
|
|
482
|
+
border-bottom-right-radius: 3px;
|
|
483
|
+
margin-left: 32px;
|
|
376
484
|
}
|
|
377
485
|
|
|
378
486
|
.pp-message-operator,
|
|
@@ -380,19 +488,32 @@ function styles(primaryColor, theme) {
|
|
|
380
488
|
align-self: flex-start;
|
|
381
489
|
background: ${colors.messageBg};
|
|
382
490
|
color: ${colors.text};
|
|
383
|
-
border-bottom-left-radius:
|
|
491
|
+
border-bottom-left-radius: 3px;
|
|
492
|
+
margin-right: 32px;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* Add spacing between different senders */
|
|
496
|
+
.pp-message-visitor + .pp-message-operator,
|
|
497
|
+
.pp-message-visitor + .pp-message-ai,
|
|
498
|
+
.pp-message-operator + .pp-message-visitor,
|
|
499
|
+
.pp-message-ai + .pp-message-visitor {
|
|
500
|
+
margin-top: 8px;
|
|
384
501
|
}
|
|
385
502
|
|
|
386
503
|
.pp-message-content {
|
|
387
|
-
|
|
504
|
+
display: block;
|
|
505
|
+
flex: 1;
|
|
388
506
|
}
|
|
389
507
|
|
|
390
508
|
.pp-message-time {
|
|
391
|
-
font-size:
|
|
392
|
-
opacity: 0.
|
|
509
|
+
font-size: 10px;
|
|
510
|
+
opacity: 0.6;
|
|
393
511
|
display: flex;
|
|
394
512
|
align-items: center;
|
|
395
|
-
gap:
|
|
513
|
+
gap: 3px;
|
|
514
|
+
justify-content: flex-end;
|
|
515
|
+
margin-top: 8px;
|
|
516
|
+
flex-shrink: 0;
|
|
396
517
|
}
|
|
397
518
|
|
|
398
519
|
.pp-ai-badge {
|
|
@@ -429,13 +550,13 @@ function styles(primaryColor, theme) {
|
|
|
429
550
|
|
|
430
551
|
.pp-typing {
|
|
431
552
|
display: flex;
|
|
432
|
-
gap:
|
|
433
|
-
padding:
|
|
553
|
+
gap: 3px;
|
|
554
|
+
padding: 8px 12px;
|
|
434
555
|
}
|
|
435
556
|
|
|
436
557
|
.pp-typing span {
|
|
437
|
-
width:
|
|
438
|
-
height:
|
|
558
|
+
width: 6px;
|
|
559
|
+
height: 6px;
|
|
439
560
|
background: ${colors.textSecondary};
|
|
440
561
|
border-radius: 50%;
|
|
441
562
|
animation: pp-bounce 1.4s infinite ease-in-out both;
|
|
@@ -451,14 +572,18 @@ function styles(primaryColor, theme) {
|
|
|
451
572
|
|
|
452
573
|
.pp-input-form {
|
|
453
574
|
display: flex;
|
|
454
|
-
padding: 12px;
|
|
575
|
+
padding: 10px 12px;
|
|
455
576
|
gap: 8px;
|
|
456
577
|
border-top: 1px solid ${colors.border};
|
|
578
|
+
align-items: center;
|
|
457
579
|
}
|
|
458
580
|
|
|
459
581
|
.pp-input {
|
|
460
582
|
flex: 1;
|
|
461
|
-
|
|
583
|
+
min-width: 0;
|
|
584
|
+
height: 40px;
|
|
585
|
+
line-height: 40px;
|
|
586
|
+
padding: 0 16px;
|
|
462
587
|
border: 1px solid ${colors.border};
|
|
463
588
|
border-radius: 20px;
|
|
464
589
|
background: ${colors.bg};
|
|
@@ -466,6 +591,8 @@ function styles(primaryColor, theme) {
|
|
|
466
591
|
font-size: 14px;
|
|
467
592
|
outline: none;
|
|
468
593
|
transition: border-color 0.2s;
|
|
594
|
+
box-sizing: border-box;
|
|
595
|
+
margin: 0;
|
|
469
596
|
}
|
|
470
597
|
|
|
471
598
|
.pp-input:focus {
|
|
@@ -479,6 +606,7 @@ function styles(primaryColor, theme) {
|
|
|
479
606
|
.pp-send-btn {
|
|
480
607
|
width: 40px;
|
|
481
608
|
height: 40px;
|
|
609
|
+
min-width: 40px;
|
|
482
610
|
border-radius: 50%;
|
|
483
611
|
background: ${primaryColor};
|
|
484
612
|
color: white;
|
|
@@ -487,7 +615,18 @@ function styles(primaryColor, theme) {
|
|
|
487
615
|
display: flex;
|
|
488
616
|
align-items: center;
|
|
489
617
|
justify-content: center;
|
|
490
|
-
transition: opacity 0.2s;
|
|
618
|
+
transition: opacity 0.2s, transform 0.1s;
|
|
619
|
+
flex-shrink: 0;
|
|
620
|
+
margin: 0;
|
|
621
|
+
padding: 0;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.pp-send-btn:not(:disabled):hover {
|
|
625
|
+
transform: scale(1.05);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.pp-send-btn:not(:disabled):active {
|
|
629
|
+
transform: scale(0.95);
|
|
491
630
|
}
|
|
492
631
|
|
|
493
632
|
.pp-send-btn:disabled {
|
|
@@ -506,6 +645,7 @@ function styles(primaryColor, theme) {
|
|
|
506
645
|
font-size: 11px;
|
|
507
646
|
color: ${colors.textSecondary};
|
|
508
647
|
border-top: 1px solid ${colors.border};
|
|
648
|
+
opacity: 0.7;
|
|
509
649
|
}
|
|
510
650
|
|
|
511
651
|
.pp-footer a {
|
|
@@ -534,6 +674,7 @@ function styles(primaryColor, theme) {
|
|
|
534
674
|
.pp-attach-btn {
|
|
535
675
|
width: 40px;
|
|
536
676
|
height: 40px;
|
|
677
|
+
min-width: 40px;
|
|
537
678
|
border-radius: 50%;
|
|
538
679
|
background: transparent;
|
|
539
680
|
color: ${colors.textSecondary};
|
|
@@ -542,6 +683,8 @@ function styles(primaryColor, theme) {
|
|
|
542
683
|
display: flex;
|
|
543
684
|
align-items: center;
|
|
544
685
|
justify-content: center;
|
|
686
|
+
margin: 0;
|
|
687
|
+
padding: 0;
|
|
545
688
|
transition: color 0.2s, border-color 0.2s;
|
|
546
689
|
flex-shrink: 0;
|
|
547
690
|
}
|
|
@@ -662,7 +805,10 @@ function styles(primaryColor, theme) {
|
|
|
662
805
|
display: flex;
|
|
663
806
|
flex-direction: column;
|
|
664
807
|
gap: 8px;
|
|
665
|
-
margin-top:
|
|
808
|
+
margin-top: 6px;
|
|
809
|
+
max-width: 100%;
|
|
810
|
+
align-items: flex-start;
|
|
811
|
+
flex-shrink: 0;
|
|
666
812
|
}
|
|
667
813
|
|
|
668
814
|
.pp-attachment {
|
|
@@ -673,11 +819,22 @@ function styles(primaryColor, theme) {
|
|
|
673
819
|
overflow: hidden;
|
|
674
820
|
}
|
|
675
821
|
|
|
822
|
+
.pp-attachment-image,
|
|
823
|
+
.pp-attachment-video,
|
|
824
|
+
.pp-attachment-audio {
|
|
825
|
+
width: 240px;
|
|
826
|
+
max-width: 100%;
|
|
827
|
+
}
|
|
828
|
+
|
|
676
829
|
.pp-attachment-image img {
|
|
677
|
-
|
|
830
|
+
width: 100% !important;
|
|
831
|
+
height: auto !important;
|
|
832
|
+
max-width: 240px;
|
|
678
833
|
max-height: 200px;
|
|
679
834
|
border-radius: 8px;
|
|
680
835
|
display: block;
|
|
836
|
+
object-fit: cover !important;
|
|
837
|
+
object-position: center;
|
|
681
838
|
}
|
|
682
839
|
|
|
683
840
|
.pp-attachment-audio {
|
|
@@ -687,7 +844,8 @@ function styles(primaryColor, theme) {
|
|
|
687
844
|
}
|
|
688
845
|
|
|
689
846
|
.pp-attachment-audio audio {
|
|
690
|
-
width:
|
|
847
|
+
width: 240px;
|
|
848
|
+
max-width: 100%;
|
|
691
849
|
height: 36px;
|
|
692
850
|
}
|
|
693
851
|
|
|
@@ -697,14 +855,18 @@ function styles(primaryColor, theme) {
|
|
|
697
855
|
white-space: nowrap;
|
|
698
856
|
overflow: hidden;
|
|
699
857
|
text-overflow: ellipsis;
|
|
700
|
-
max-width:
|
|
858
|
+
max-width: 100%;
|
|
701
859
|
}
|
|
702
860
|
|
|
703
861
|
.pp-attachment-video video {
|
|
704
|
-
|
|
705
|
-
|
|
862
|
+
width: 100% !important;
|
|
863
|
+
height: auto !important;
|
|
864
|
+
max-width: 240px;
|
|
865
|
+
max-height: none;
|
|
706
866
|
border-radius: 8px;
|
|
707
867
|
display: block;
|
|
868
|
+
object-fit: contain !important;
|
|
869
|
+
object-position: center;
|
|
708
870
|
}
|
|
709
871
|
|
|
710
872
|
.pp-attachment-file {
|
|
@@ -1055,34 +1217,665 @@ function styles(primaryColor, theme) {
|
|
|
1055
1217
|
margin-left: 4px;
|
|
1056
1218
|
font-style: italic;
|
|
1057
1219
|
}
|
|
1220
|
+
|
|
1221
|
+
/* Pre-Chat Form */
|
|
1222
|
+
.pp-prechat {
|
|
1223
|
+
flex: 1;
|
|
1224
|
+
display: flex;
|
|
1225
|
+
flex-direction: column;
|
|
1226
|
+
padding: 24px 20px;
|
|
1227
|
+
overflow-y: auto;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.pp-prechat-title {
|
|
1231
|
+
font-size: 18px;
|
|
1232
|
+
font-weight: 600;
|
|
1233
|
+
margin-bottom: 8px;
|
|
1234
|
+
color: ${colors.text};
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
.pp-prechat-subtitle {
|
|
1238
|
+
font-size: 13px;
|
|
1239
|
+
color: ${colors.textSecondary};
|
|
1240
|
+
margin-bottom: 24px;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.pp-prechat-tabs {
|
|
1244
|
+
display: flex;
|
|
1245
|
+
gap: 8px;
|
|
1246
|
+
margin-bottom: 20px;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
.pp-prechat-tab {
|
|
1250
|
+
flex: 1;
|
|
1251
|
+
padding: 10px;
|
|
1252
|
+
border: 1px solid ${colors.border};
|
|
1253
|
+
border-radius: 8px;
|
|
1254
|
+
background: transparent;
|
|
1255
|
+
color: ${colors.textSecondary};
|
|
1256
|
+
font-size: 13px;
|
|
1257
|
+
cursor: pointer;
|
|
1258
|
+
transition: all 0.2s;
|
|
1259
|
+
display: flex;
|
|
1260
|
+
align-items: center;
|
|
1261
|
+
justify-content: center;
|
|
1262
|
+
gap: 6px;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.pp-prechat-tab:hover {
|
|
1266
|
+
background: ${colors.bgSecondary};
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.pp-prechat-tab.active {
|
|
1270
|
+
background: ${primaryColor}15;
|
|
1271
|
+
border-color: ${primaryColor};
|
|
1272
|
+
color: ${primaryColor};
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
.pp-prechat-tab svg {
|
|
1276
|
+
width: 16px;
|
|
1277
|
+
height: 16px;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
.pp-prechat-field {
|
|
1281
|
+
margin-bottom: 16px;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
.pp-prechat-label {
|
|
1285
|
+
display: block;
|
|
1286
|
+
font-size: 12px;
|
|
1287
|
+
font-weight: 500;
|
|
1288
|
+
color: ${colors.textSecondary};
|
|
1289
|
+
margin-bottom: 6px;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
.pp-prechat-input {
|
|
1293
|
+
width: 100%;
|
|
1294
|
+
height: 44px;
|
|
1295
|
+
padding: 0 14px;
|
|
1296
|
+
border: 1px solid ${colors.border};
|
|
1297
|
+
border-radius: 8px;
|
|
1298
|
+
background: ${colors.bg};
|
|
1299
|
+
color: ${colors.text};
|
|
1300
|
+
font-size: 14px;
|
|
1301
|
+
outline: none;
|
|
1302
|
+
transition: border-color 0.2s;
|
|
1303
|
+
box-sizing: border-box;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
.pp-prechat-input:focus {
|
|
1307
|
+
border-color: ${primaryColor};
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
.pp-prechat-input::placeholder {
|
|
1311
|
+
color: ${colors.textSecondary};
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
.pp-prechat-input.error {
|
|
1315
|
+
border-color: #ef4444;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.pp-prechat-error {
|
|
1319
|
+
color: #ef4444;
|
|
1320
|
+
font-size: 12px;
|
|
1321
|
+
margin-top: 4px;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
.pp-phone-input-wrapper {
|
|
1325
|
+
display: flex;
|
|
1326
|
+
gap: 8px;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
.pp-country-select {
|
|
1330
|
+
position: relative;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
.pp-country-btn {
|
|
1334
|
+
display: flex;
|
|
1335
|
+
align-items: center;
|
|
1336
|
+
gap: 6px;
|
|
1337
|
+
height: 44px;
|
|
1338
|
+
padding: 0 10px;
|
|
1339
|
+
border: 1px solid ${colors.border};
|
|
1340
|
+
border-radius: 8px;
|
|
1341
|
+
background: ${colors.bg};
|
|
1342
|
+
color: ${colors.text};
|
|
1343
|
+
font-size: 14px;
|
|
1344
|
+
cursor: pointer;
|
|
1345
|
+
transition: border-color 0.2s;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
.pp-country-btn:focus {
|
|
1349
|
+
border-color: ${primaryColor};
|
|
1350
|
+
outline: none;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
.pp-country-flag {
|
|
1354
|
+
font-size: 18px;
|
|
1355
|
+
line-height: 1;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
.pp-country-code {
|
|
1359
|
+
font-size: 13px;
|
|
1360
|
+
color: ${colors.textSecondary};
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
.pp-country-chevron {
|
|
1364
|
+
width: 12px;
|
|
1365
|
+
height: 12px;
|
|
1366
|
+
color: ${colors.textSecondary};
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.pp-country-dropdown {
|
|
1370
|
+
position: absolute;
|
|
1371
|
+
top: calc(100% + 4px);
|
|
1372
|
+
left: 0;
|
|
1373
|
+
width: 280px;
|
|
1374
|
+
max-height: 280px;
|
|
1375
|
+
overflow-y: auto;
|
|
1376
|
+
background: ${colors.bg};
|
|
1377
|
+
border: 1px solid ${colors.border};
|
|
1378
|
+
border-radius: 8px;
|
|
1379
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1380
|
+
z-index: 100;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
.pp-country-search {
|
|
1384
|
+
position: sticky;
|
|
1385
|
+
top: 0;
|
|
1386
|
+
padding: 8px;
|
|
1387
|
+
background: ${colors.bg};
|
|
1388
|
+
border-bottom: 1px solid ${colors.border};
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
.pp-country-search-input {
|
|
1392
|
+
width: 100%;
|
|
1393
|
+
height: 36px;
|
|
1394
|
+
padding: 0 12px;
|
|
1395
|
+
border: 1px solid ${colors.border};
|
|
1396
|
+
border-radius: 6px;
|
|
1397
|
+
background: ${colors.bgSecondary};
|
|
1398
|
+
color: ${colors.text};
|
|
1399
|
+
font-size: 13px;
|
|
1400
|
+
outline: none;
|
|
1401
|
+
box-sizing: border-box;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
.pp-country-search-input:focus {
|
|
1405
|
+
border-color: ${primaryColor};
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
.pp-country-list {
|
|
1409
|
+
padding: 4px;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
.pp-country-option {
|
|
1413
|
+
display: flex;
|
|
1414
|
+
align-items: center;
|
|
1415
|
+
gap: 10px;
|
|
1416
|
+
padding: 10px 12px;
|
|
1417
|
+
cursor: pointer;
|
|
1418
|
+
border-radius: 6px;
|
|
1419
|
+
transition: background 0.15s;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
.pp-country-option:hover {
|
|
1423
|
+
background: ${colors.bgSecondary};
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
.pp-country-option.selected {
|
|
1427
|
+
background: ${primaryColor}15;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
.pp-country-name {
|
|
1431
|
+
flex: 1;
|
|
1432
|
+
font-size: 13px;
|
|
1433
|
+
color: ${colors.text};
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
.pp-country-dial {
|
|
1437
|
+
font-size: 12px;
|
|
1438
|
+
color: ${colors.textSecondary};
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
.pp-phone-number-input {
|
|
1442
|
+
flex: 1;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
.pp-prechat-submit {
|
|
1446
|
+
width: 100%;
|
|
1447
|
+
height: 44px;
|
|
1448
|
+
margin-top: 8px;
|
|
1449
|
+
border: none;
|
|
1450
|
+
border-radius: 8px;
|
|
1451
|
+
background: ${primaryColor};
|
|
1452
|
+
color: white;
|
|
1453
|
+
font-size: 14px;
|
|
1454
|
+
font-weight: 500;
|
|
1455
|
+
cursor: pointer;
|
|
1456
|
+
transition: opacity 0.2s, transform 0.1s;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
.pp-prechat-submit:hover:not(:disabled) {
|
|
1460
|
+
opacity: 0.9;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
.pp-prechat-submit:active:not(:disabled) {
|
|
1464
|
+
transform: scale(0.98);
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
.pp-prechat-submit:disabled {
|
|
1468
|
+
opacity: 0.5;
|
|
1469
|
+
cursor: not-allowed;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
.pp-prechat-skip {
|
|
1473
|
+
width: 100%;
|
|
1474
|
+
padding: 12px;
|
|
1475
|
+
margin-top: 8px;
|
|
1476
|
+
border: none;
|
|
1477
|
+
background: transparent;
|
|
1478
|
+
color: ${colors.textSecondary};
|
|
1479
|
+
font-size: 13px;
|
|
1480
|
+
cursor: pointer;
|
|
1481
|
+
transition: color 0.2s;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
.pp-prechat-skip:hover {
|
|
1485
|
+
color: ${colors.text};
|
|
1486
|
+
}
|
|
1058
1487
|
`;
|
|
1059
1488
|
}
|
|
1060
1489
|
|
|
1061
|
-
// src/components/
|
|
1490
|
+
// src/components/PreChatForm.tsx
|
|
1491
|
+
var import_hooks = require("preact/hooks");
|
|
1492
|
+
var import_min = require("libphonenumber-js/min");
|
|
1493
|
+
|
|
1494
|
+
// src/data/countries.ts
|
|
1495
|
+
var countries = [
|
|
1496
|
+
// Europe
|
|
1497
|
+
{ code: "FR", name: "France", dialCode: "+33", flag: "\u{1F1EB}\u{1F1F7}" },
|
|
1498
|
+
{ code: "DE", name: "Germany", dialCode: "+49", flag: "\u{1F1E9}\u{1F1EA}" },
|
|
1499
|
+
{ code: "GB", name: "United Kingdom", dialCode: "+44", flag: "\u{1F1EC}\u{1F1E7}" },
|
|
1500
|
+
{ code: "ES", name: "Spain", dialCode: "+34", flag: "\u{1F1EA}\u{1F1F8}" },
|
|
1501
|
+
{ code: "IT", name: "Italy", dialCode: "+39", flag: "\u{1F1EE}\u{1F1F9}" },
|
|
1502
|
+
{ code: "PT", name: "Portugal", dialCode: "+351", flag: "\u{1F1F5}\u{1F1F9}" },
|
|
1503
|
+
{ code: "NL", name: "Netherlands", dialCode: "+31", flag: "\u{1F1F3}\u{1F1F1}" },
|
|
1504
|
+
{ code: "BE", name: "Belgium", dialCode: "+32", flag: "\u{1F1E7}\u{1F1EA}" },
|
|
1505
|
+
{ code: "CH", name: "Switzerland", dialCode: "+41", flag: "\u{1F1E8}\u{1F1ED}" },
|
|
1506
|
+
{ code: "AT", name: "Austria", dialCode: "+43", flag: "\u{1F1E6}\u{1F1F9}" },
|
|
1507
|
+
{ code: "SE", name: "Sweden", dialCode: "+46", flag: "\u{1F1F8}\u{1F1EA}" },
|
|
1508
|
+
{ code: "NO", name: "Norway", dialCode: "+47", flag: "\u{1F1F3}\u{1F1F4}" },
|
|
1509
|
+
{ code: "DK", name: "Denmark", dialCode: "+45", flag: "\u{1F1E9}\u{1F1F0}" },
|
|
1510
|
+
{ code: "FI", name: "Finland", dialCode: "+358", flag: "\u{1F1EB}\u{1F1EE}" },
|
|
1511
|
+
{ code: "PL", name: "Poland", dialCode: "+48", flag: "\u{1F1F5}\u{1F1F1}" },
|
|
1512
|
+
{ code: "CZ", name: "Czech Republic", dialCode: "+420", flag: "\u{1F1E8}\u{1F1FF}" },
|
|
1513
|
+
{ code: "GR", name: "Greece", dialCode: "+30", flag: "\u{1F1EC}\u{1F1F7}" },
|
|
1514
|
+
{ code: "IE", name: "Ireland", dialCode: "+353", flag: "\u{1F1EE}\u{1F1EA}" },
|
|
1515
|
+
{ code: "RO", name: "Romania", dialCode: "+40", flag: "\u{1F1F7}\u{1F1F4}" },
|
|
1516
|
+
{ code: "HU", name: "Hungary", dialCode: "+36", flag: "\u{1F1ED}\u{1F1FA}" },
|
|
1517
|
+
// North America
|
|
1518
|
+
{ code: "US", name: "United States", dialCode: "+1", flag: "\u{1F1FA}\u{1F1F8}" },
|
|
1519
|
+
{ code: "CA", name: "Canada", dialCode: "+1", flag: "\u{1F1E8}\u{1F1E6}" },
|
|
1520
|
+
{ code: "MX", name: "Mexico", dialCode: "+52", flag: "\u{1F1F2}\u{1F1FD}" },
|
|
1521
|
+
// South America
|
|
1522
|
+
{ code: "BR", name: "Brazil", dialCode: "+55", flag: "\u{1F1E7}\u{1F1F7}" },
|
|
1523
|
+
{ code: "AR", name: "Argentina", dialCode: "+54", flag: "\u{1F1E6}\u{1F1F7}" },
|
|
1524
|
+
{ code: "CL", name: "Chile", dialCode: "+56", flag: "\u{1F1E8}\u{1F1F1}" },
|
|
1525
|
+
{ code: "CO", name: "Colombia", dialCode: "+57", flag: "\u{1F1E8}\u{1F1F4}" },
|
|
1526
|
+
{ code: "PE", name: "Peru", dialCode: "+51", flag: "\u{1F1F5}\u{1F1EA}" },
|
|
1527
|
+
// Asia
|
|
1528
|
+
{ code: "CN", name: "China", dialCode: "+86", flag: "\u{1F1E8}\u{1F1F3}" },
|
|
1529
|
+
{ code: "JP", name: "Japan", dialCode: "+81", flag: "\u{1F1EF}\u{1F1F5}" },
|
|
1530
|
+
{ code: "KR", name: "South Korea", dialCode: "+82", flag: "\u{1F1F0}\u{1F1F7}" },
|
|
1531
|
+
{ code: "IN", name: "India", dialCode: "+91", flag: "\u{1F1EE}\u{1F1F3}" },
|
|
1532
|
+
{ code: "ID", name: "Indonesia", dialCode: "+62", flag: "\u{1F1EE}\u{1F1E9}" },
|
|
1533
|
+
{ code: "TH", name: "Thailand", dialCode: "+66", flag: "\u{1F1F9}\u{1F1ED}" },
|
|
1534
|
+
{ code: "VN", name: "Vietnam", dialCode: "+84", flag: "\u{1F1FB}\u{1F1F3}" },
|
|
1535
|
+
{ code: "MY", name: "Malaysia", dialCode: "+60", flag: "\u{1F1F2}\u{1F1FE}" },
|
|
1536
|
+
{ code: "SG", name: "Singapore", dialCode: "+65", flag: "\u{1F1F8}\u{1F1EC}" },
|
|
1537
|
+
{ code: "PH", name: "Philippines", dialCode: "+63", flag: "\u{1F1F5}\u{1F1ED}" },
|
|
1538
|
+
{ code: "PK", name: "Pakistan", dialCode: "+92", flag: "\u{1F1F5}\u{1F1F0}" },
|
|
1539
|
+
{ code: "BD", name: "Bangladesh", dialCode: "+880", flag: "\u{1F1E7}\u{1F1E9}" },
|
|
1540
|
+
// Middle East
|
|
1541
|
+
{ code: "AE", name: "United Arab Emirates", dialCode: "+971", flag: "\u{1F1E6}\u{1F1EA}" },
|
|
1542
|
+
{ code: "SA", name: "Saudi Arabia", dialCode: "+966", flag: "\u{1F1F8}\u{1F1E6}" },
|
|
1543
|
+
{ code: "IL", name: "Israel", dialCode: "+972", flag: "\u{1F1EE}\u{1F1F1}" },
|
|
1544
|
+
{ code: "TR", name: "Turkey", dialCode: "+90", flag: "\u{1F1F9}\u{1F1F7}" },
|
|
1545
|
+
{ code: "EG", name: "Egypt", dialCode: "+20", flag: "\u{1F1EA}\u{1F1EC}" },
|
|
1546
|
+
// Africa
|
|
1547
|
+
{ code: "ZA", name: "South Africa", dialCode: "+27", flag: "\u{1F1FF}\u{1F1E6}" },
|
|
1548
|
+
{ code: "NG", name: "Nigeria", dialCode: "+234", flag: "\u{1F1F3}\u{1F1EC}" },
|
|
1549
|
+
{ code: "KE", name: "Kenya", dialCode: "+254", flag: "\u{1F1F0}\u{1F1EA}" },
|
|
1550
|
+
{ code: "MA", name: "Morocco", dialCode: "+212", flag: "\u{1F1F2}\u{1F1E6}" },
|
|
1551
|
+
{ code: "TN", name: "Tunisia", dialCode: "+216", flag: "\u{1F1F9}\u{1F1F3}" },
|
|
1552
|
+
{ code: "DZ", name: "Algeria", dialCode: "+213", flag: "\u{1F1E9}\u{1F1FF}" },
|
|
1553
|
+
// Oceania
|
|
1554
|
+
{ code: "AU", name: "Australia", dialCode: "+61", flag: "\u{1F1E6}\u{1F1FA}" },
|
|
1555
|
+
{ code: "NZ", name: "New Zealand", dialCode: "+64", flag: "\u{1F1F3}\u{1F1FF}" },
|
|
1556
|
+
// Russia & CIS
|
|
1557
|
+
{ code: "RU", name: "Russia", dialCode: "+7", flag: "\u{1F1F7}\u{1F1FA}" },
|
|
1558
|
+
{ code: "UA", name: "Ukraine", dialCode: "+380", flag: "\u{1F1FA}\u{1F1E6}" }
|
|
1559
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
1560
|
+
function findCountryByCode(code) {
|
|
1561
|
+
return countries.find((c) => c.code === code.toUpperCase());
|
|
1562
|
+
}
|
|
1563
|
+
var defaultCountry = findCountryByCode("FR");
|
|
1564
|
+
|
|
1565
|
+
// src/components/PreChatForm.tsx
|
|
1062
1566
|
var import_jsx_runtime = require("preact/jsx-runtime");
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
const
|
|
1074
|
-
const
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1077
|
-
const
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
const
|
|
1082
|
-
const
|
|
1083
|
-
const
|
|
1084
|
-
const
|
|
1567
|
+
var EmailIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1568
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
|
|
1569
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M22 7l-10 7L2 7" })
|
|
1570
|
+
] });
|
|
1571
|
+
var PhoneIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.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" }) });
|
|
1572
|
+
var ChevronIcon = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 9l6 6 6-6" }) });
|
|
1573
|
+
function isValidEmail(email) {
|
|
1574
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
1575
|
+
}
|
|
1576
|
+
function PreChatForm({ client: client2, config, onComplete, onSkip }) {
|
|
1577
|
+
const showEmailOnly = config.fields === "email-only";
|
|
1578
|
+
const showPhoneOnly = config.fields === "phone-only";
|
|
1579
|
+
const showBoth = config.fields === "email-and-phone";
|
|
1580
|
+
const showChoice = config.fields === "email-or-phone";
|
|
1581
|
+
const getDefaultTab = () => {
|
|
1582
|
+
if (showPhoneOnly) return "phone";
|
|
1583
|
+
return "email";
|
|
1584
|
+
};
|
|
1585
|
+
const [activeTab, setActiveTab] = (0, import_hooks.useState)(getDefaultTab());
|
|
1586
|
+
const [email, setEmail] = (0, import_hooks.useState)("");
|
|
1587
|
+
const [phone, setPhone] = (0, import_hooks.useState)("");
|
|
1588
|
+
const [selectedCountry, setSelectedCountry] = (0, import_hooks.useState)(defaultCountry);
|
|
1589
|
+
const [isCountryDropdownOpen, setIsCountryDropdownOpen] = (0, import_hooks.useState)(false);
|
|
1590
|
+
const [countrySearch, setCountrySearch] = (0, import_hooks.useState)("");
|
|
1591
|
+
const [emailError, setEmailError] = (0, import_hooks.useState)("");
|
|
1592
|
+
const [phoneError, setPhoneError] = (0, import_hooks.useState)("");
|
|
1593
|
+
const [isSubmitting, setIsSubmitting] = (0, import_hooks.useState)(false);
|
|
1594
|
+
const countryDropdownRef = (0, import_hooks.useRef)(null);
|
|
1595
|
+
const searchInputRef = (0, import_hooks.useRef)(null);
|
|
1596
|
+
(0, import_hooks.useEffect)(() => {
|
|
1597
|
+
const handleClickOutside = (e) => {
|
|
1598
|
+
if (countryDropdownRef.current && !countryDropdownRef.current.contains(e.target)) {
|
|
1599
|
+
setIsCountryDropdownOpen(false);
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
1603
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1604
|
+
}, []);
|
|
1085
1605
|
(0, import_hooks.useEffect)(() => {
|
|
1606
|
+
if (isCountryDropdownOpen && searchInputRef.current) {
|
|
1607
|
+
searchInputRef.current.focus();
|
|
1608
|
+
}
|
|
1609
|
+
}, [isCountryDropdownOpen]);
|
|
1610
|
+
const filteredCountries = countries.filter(
|
|
1611
|
+
(c) => c.name.toLowerCase().includes(countrySearch.toLowerCase()) || c.dialCode.includes(countrySearch) || c.code.toLowerCase().includes(countrySearch.toLowerCase())
|
|
1612
|
+
);
|
|
1613
|
+
const handleCountrySelect = (country) => {
|
|
1614
|
+
setSelectedCountry(country);
|
|
1615
|
+
setIsCountryDropdownOpen(false);
|
|
1616
|
+
setCountrySearch("");
|
|
1617
|
+
};
|
|
1618
|
+
const formatPhoneForDisplay = (value) => {
|
|
1619
|
+
const digits = value.replace(/\D/g, "");
|
|
1620
|
+
return digits;
|
|
1621
|
+
};
|
|
1622
|
+
const handlePhoneChange = (e) => {
|
|
1623
|
+
const target = e.target;
|
|
1624
|
+
const formatted = formatPhoneForDisplay(target.value);
|
|
1625
|
+
setPhone(formatted);
|
|
1626
|
+
setPhoneError("");
|
|
1627
|
+
};
|
|
1628
|
+
const getFullPhoneNumber = () => {
|
|
1629
|
+
if (!phone) return "";
|
|
1630
|
+
return `${selectedCountry.dialCode}${phone}`;
|
|
1631
|
+
};
|
|
1632
|
+
const validateForm = () => {
|
|
1633
|
+
let valid = true;
|
|
1634
|
+
if (showEmailOnly || showBoth) {
|
|
1635
|
+
if (!email.trim()) {
|
|
1636
|
+
setEmailError("Email is required");
|
|
1637
|
+
valid = false;
|
|
1638
|
+
} else if (!isValidEmail(email)) {
|
|
1639
|
+
setEmailError("Please enter a valid email");
|
|
1640
|
+
valid = false;
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
if (showPhoneOnly || showBoth) {
|
|
1644
|
+
const fullPhone = getFullPhoneNumber();
|
|
1645
|
+
if (!phone.trim()) {
|
|
1646
|
+
setPhoneError("Phone number is required");
|
|
1647
|
+
valid = false;
|
|
1648
|
+
} else if (!(0, import_min.isValidPhoneNumber)(fullPhone, selectedCountry.code)) {
|
|
1649
|
+
setPhoneError("Please enter a valid phone number");
|
|
1650
|
+
valid = false;
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
if (showChoice) {
|
|
1654
|
+
if (activeTab === "email") {
|
|
1655
|
+
if (!email.trim()) {
|
|
1656
|
+
setEmailError("Email is required");
|
|
1657
|
+
valid = false;
|
|
1658
|
+
} else if (!isValidEmail(email)) {
|
|
1659
|
+
setEmailError("Please enter a valid email");
|
|
1660
|
+
valid = false;
|
|
1661
|
+
}
|
|
1662
|
+
} else {
|
|
1663
|
+
const fullPhone = getFullPhoneNumber();
|
|
1664
|
+
if (!phone.trim()) {
|
|
1665
|
+
setPhoneError("Phone number is required");
|
|
1666
|
+
valid = false;
|
|
1667
|
+
} else if (!(0, import_min.isValidPhoneNumber)(fullPhone, selectedCountry.code)) {
|
|
1668
|
+
setPhoneError("Please enter a valid phone number");
|
|
1669
|
+
valid = false;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return valid;
|
|
1674
|
+
};
|
|
1675
|
+
const handleSubmit = async (e) => {
|
|
1676
|
+
e.preventDefault();
|
|
1677
|
+
if (!validateForm()) return;
|
|
1678
|
+
setIsSubmitting(true);
|
|
1679
|
+
try {
|
|
1680
|
+
const data = {};
|
|
1681
|
+
if (showEmailOnly || showBoth || showChoice && activeTab === "email") {
|
|
1682
|
+
data.email = email.trim();
|
|
1683
|
+
}
|
|
1684
|
+
if (showPhoneOnly || showBoth || showChoice && activeTab === "phone") {
|
|
1685
|
+
const fullPhone = getFullPhoneNumber();
|
|
1686
|
+
const parsed = (0, import_min.parsePhoneNumber)(fullPhone, selectedCountry.code);
|
|
1687
|
+
if (parsed) {
|
|
1688
|
+
data.phone = parsed.format("E.164");
|
|
1689
|
+
data.phoneCountry = selectedCountry.code;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
await client2.submitPreChat(data);
|
|
1693
|
+
onComplete();
|
|
1694
|
+
} catch (err) {
|
|
1695
|
+
console.error("[PreChatForm] Submit error:", err);
|
|
1696
|
+
if (activeTab === "email" || showEmailOnly || showBoth) {
|
|
1697
|
+
setEmailError("Something went wrong. Please try again.");
|
|
1698
|
+
} else {
|
|
1699
|
+
setPhoneError("Something went wrong. Please try again.");
|
|
1700
|
+
}
|
|
1701
|
+
} finally {
|
|
1702
|
+
setIsSubmitting(false);
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1705
|
+
const renderEmailField = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-prechat-field", children: [
|
|
1706
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { class: "pp-prechat-label", children: "Email address" }),
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1708
|
+
"input",
|
|
1709
|
+
{
|
|
1710
|
+
type: "email",
|
|
1711
|
+
class: `pp-prechat-input ${emailError ? "error" : ""}`,
|
|
1712
|
+
placeholder: "you@example.com",
|
|
1713
|
+
value: email,
|
|
1714
|
+
onInput: (e) => {
|
|
1715
|
+
setEmail(e.target.value);
|
|
1716
|
+
setEmailError("");
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
),
|
|
1720
|
+
emailError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { class: "pp-prechat-error", children: emailError })
|
|
1721
|
+
] });
|
|
1722
|
+
const renderPhoneField = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-prechat-field", children: [
|
|
1723
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { class: "pp-prechat-label", children: "Phone number" }),
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-phone-input-wrapper", children: [
|
|
1725
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-country-select", ref: countryDropdownRef, children: [
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1727
|
+
"button",
|
|
1728
|
+
{
|
|
1729
|
+
type: "button",
|
|
1730
|
+
class: "pp-country-btn",
|
|
1731
|
+
onClick: () => setIsCountryDropdownOpen(!isCountryDropdownOpen),
|
|
1732
|
+
children: [
|
|
1733
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-country-flag", children: selectedCountry.flag }),
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-country-code", children: selectedCountry.dialCode }),
|
|
1735
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronIcon, {})
|
|
1736
|
+
]
|
|
1737
|
+
}
|
|
1738
|
+
),
|
|
1739
|
+
isCountryDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-country-dropdown", children: [
|
|
1740
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { class: "pp-country-search", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1741
|
+
"input",
|
|
1742
|
+
{
|
|
1743
|
+
ref: searchInputRef,
|
|
1744
|
+
type: "text",
|
|
1745
|
+
class: "pp-country-search-input",
|
|
1746
|
+
placeholder: "Search country...",
|
|
1747
|
+
value: countrySearch,
|
|
1748
|
+
onInput: (e) => setCountrySearch(e.target.value)
|
|
1749
|
+
}
|
|
1750
|
+
) }),
|
|
1751
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { class: "pp-country-list", children: filteredCountries.map((country) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1752
|
+
"div",
|
|
1753
|
+
{
|
|
1754
|
+
class: `pp-country-option ${country.code === selectedCountry.code ? "selected" : ""}`,
|
|
1755
|
+
onClick: () => handleCountrySelect(country),
|
|
1756
|
+
children: [
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-country-flag", children: country.flag }),
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-country-name", children: country.name }),
|
|
1759
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-country-dial", children: country.dialCode })
|
|
1760
|
+
]
|
|
1761
|
+
},
|
|
1762
|
+
country.code
|
|
1763
|
+
)) })
|
|
1764
|
+
] })
|
|
1765
|
+
] }),
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1767
|
+
"input",
|
|
1768
|
+
{
|
|
1769
|
+
type: "tel",
|
|
1770
|
+
class: `pp-prechat-input pp-phone-number-input ${phoneError ? "error" : ""}`,
|
|
1771
|
+
placeholder: "612 345 678",
|
|
1772
|
+
value: phone,
|
|
1773
|
+
onInput: handlePhoneChange
|
|
1774
|
+
}
|
|
1775
|
+
)
|
|
1776
|
+
] }),
|
|
1777
|
+
phoneError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { class: "pp-prechat-error", children: phoneError })
|
|
1778
|
+
] });
|
|
1779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-prechat", children: [
|
|
1780
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { class: "pp-prechat-title", children: "How can we reach you?" }),
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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." }),
|
|
1782
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: handleSubmit, children: [
|
|
1783
|
+
showChoice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-prechat-tabs", children: [
|
|
1784
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1785
|
+
"button",
|
|
1786
|
+
{
|
|
1787
|
+
type: "button",
|
|
1788
|
+
class: `pp-prechat-tab ${activeTab === "email" ? "active" : ""}`,
|
|
1789
|
+
onClick: () => {
|
|
1790
|
+
setActiveTab("email");
|
|
1791
|
+
setPhoneError("");
|
|
1792
|
+
},
|
|
1793
|
+
children: [
|
|
1794
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmailIcon, {}),
|
|
1795
|
+
"Email"
|
|
1796
|
+
]
|
|
1797
|
+
}
|
|
1798
|
+
),
|
|
1799
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1800
|
+
"button",
|
|
1801
|
+
{
|
|
1802
|
+
type: "button",
|
|
1803
|
+
class: `pp-prechat-tab ${activeTab === "phone" ? "active" : ""}`,
|
|
1804
|
+
onClick: () => {
|
|
1805
|
+
setActiveTab("phone");
|
|
1806
|
+
setEmailError("");
|
|
1807
|
+
},
|
|
1808
|
+
children: [
|
|
1809
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhoneIcon, {}),
|
|
1810
|
+
"Phone"
|
|
1811
|
+
]
|
|
1812
|
+
}
|
|
1813
|
+
)
|
|
1814
|
+
] }),
|
|
1815
|
+
showEmailOnly && renderEmailField(),
|
|
1816
|
+
showPhoneOnly && renderPhoneField(),
|
|
1817
|
+
showBoth && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1818
|
+
renderEmailField(),
|
|
1819
|
+
renderPhoneField()
|
|
1820
|
+
] }),
|
|
1821
|
+
showChoice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1822
|
+
activeTab === "email" && renderEmailField(),
|
|
1823
|
+
activeTab === "phone" && renderPhoneField()
|
|
1824
|
+
] }),
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", class: "pp-prechat-submit", disabled: isSubmitting, children: isSubmitting ? "Submitting..." : "Start chatting" }),
|
|
1826
|
+
!config.required && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", class: "pp-prechat-skip", onClick: onSkip, children: "Skip for now" })
|
|
1827
|
+
] })
|
|
1828
|
+
] });
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
// src/components/ChatWidget.tsx
|
|
1832
|
+
var import_jsx_runtime2 = require("preact/jsx-runtime");
|
|
1833
|
+
function formatDateSeparator(date) {
|
|
1834
|
+
const now = /* @__PURE__ */ new Date();
|
|
1835
|
+
const messageDate = new Date(date);
|
|
1836
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
1837
|
+
const msgDay = new Date(messageDate.getFullYear(), messageDate.getMonth(), messageDate.getDate());
|
|
1838
|
+
const diffDays = Math.floor((today.getTime() - msgDay.getTime()) / (1e3 * 60 * 60 * 24));
|
|
1839
|
+
if (diffDays === 0) return "Today";
|
|
1840
|
+
if (diffDays === 1) return "Yesterday";
|
|
1841
|
+
return messageDate.toLocaleDateString("en-US", {
|
|
1842
|
+
month: "short",
|
|
1843
|
+
day: "numeric",
|
|
1844
|
+
year: messageDate.getFullYear() !== now.getFullYear() ? "numeric" : void 0
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
function getDateKey(date) {
|
|
1848
|
+
const d = new Date(date);
|
|
1849
|
+
return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
|
|
1850
|
+
}
|
|
1851
|
+
function ChatWidget({ client: client2, config: initialConfig }) {
|
|
1852
|
+
const [isOpen, setIsOpen] = (0, import_hooks2.useState)(false);
|
|
1853
|
+
const [messages, setMessages] = (0, import_hooks2.useState)([]);
|
|
1854
|
+
const [inputValue, setInputValue] = (0, import_hooks2.useState)("");
|
|
1855
|
+
const [isTyping, setIsTyping] = (0, import_hooks2.useState)(false);
|
|
1856
|
+
const [operatorOnline, setOperatorOnline] = (0, import_hooks2.useState)(false);
|
|
1857
|
+
const [isConnected, setIsConnected] = (0, import_hooks2.useState)(false);
|
|
1858
|
+
const [unreadCount, setUnreadCount] = (0, import_hooks2.useState)(0);
|
|
1859
|
+
const [pendingAttachments, setPendingAttachments] = (0, import_hooks2.useState)([]);
|
|
1860
|
+
const [isUploading, setIsUploading] = (0, import_hooks2.useState)(false);
|
|
1861
|
+
const [replyingTo, setReplyingTo] = (0, import_hooks2.useState)(null);
|
|
1862
|
+
const [editingMessage, setEditingMessage] = (0, import_hooks2.useState)(null);
|
|
1863
|
+
const [editContent, setEditContent] = (0, import_hooks2.useState)("");
|
|
1864
|
+
const [messageMenu, setMessageMenu] = (0, import_hooks2.useState)(null);
|
|
1865
|
+
const [isDragging, setIsDragging] = (0, import_hooks2.useState)(false);
|
|
1866
|
+
const [hoveredMessageId, setHoveredMessageId] = (0, import_hooks2.useState)(null);
|
|
1867
|
+
const [longPressTimer, setLongPressTimer] = (0, import_hooks2.useState)(null);
|
|
1868
|
+
const [swipedMessageId, setSwipedMessageId] = (0, import_hooks2.useState)(null);
|
|
1869
|
+
const [swipeOffset, setSwipeOffset] = (0, import_hooks2.useState)(0);
|
|
1870
|
+
const touchStartRef = (0, import_hooks2.useRef)(null);
|
|
1871
|
+
const [config, setConfig] = (0, import_hooks2.useState)(initialConfig);
|
|
1872
|
+
const [preChatForm, setPreChatForm] = (0, import_hooks2.useState)(void 0);
|
|
1873
|
+
const [preChatSkipped, setPreChatSkipped] = (0, import_hooks2.useState)(false);
|
|
1874
|
+
const messagesEndRef = (0, import_hooks2.useRef)(null);
|
|
1875
|
+
const inputRef = (0, import_hooks2.useRef)(null);
|
|
1876
|
+
const fileInputRef = (0, import_hooks2.useRef)(null);
|
|
1877
|
+
const messagesContainerRef = (0, import_hooks2.useRef)(null);
|
|
1878
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1086
1879
|
const unsubOpen = client2.on("openChange", setIsOpen);
|
|
1087
1880
|
const unsubMessage = client2.on("message", () => {
|
|
1088
1881
|
setMessages([...client2.getMessages()]);
|
|
@@ -1098,6 +1891,10 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1098
1891
|
setMessages(client2.getMessages());
|
|
1099
1892
|
setOperatorOnline(client2.getSession()?.operatorOnline ?? false);
|
|
1100
1893
|
setConfig(client2.getConfig());
|
|
1894
|
+
setPreChatForm(client2.getSession()?.preChatForm);
|
|
1895
|
+
});
|
|
1896
|
+
const unsubPreChat = client2.on("preChatCompleted", () => {
|
|
1897
|
+
setPreChatForm((prev) => prev ? { ...prev, completed: true } : prev);
|
|
1101
1898
|
});
|
|
1102
1899
|
const unsubConfig = client2.on("configUpdate", () => {
|
|
1103
1900
|
setConfig(client2.getConfig());
|
|
@@ -1107,6 +1904,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1107
1904
|
setMessages(client2.getMessages());
|
|
1108
1905
|
setOperatorOnline(client2.getSession()?.operatorOnline ?? false);
|
|
1109
1906
|
setConfig(client2.getConfig());
|
|
1907
|
+
setPreChatForm(client2.getSession()?.preChatForm);
|
|
1110
1908
|
}
|
|
1111
1909
|
return () => {
|
|
1112
1910
|
unsubOpen();
|
|
@@ -1114,15 +1912,16 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1114
1912
|
unsubTyping();
|
|
1115
1913
|
unsubPresence();
|
|
1116
1914
|
unsubConnect();
|
|
1915
|
+
unsubPreChat();
|
|
1117
1916
|
unsubConfig();
|
|
1118
1917
|
};
|
|
1119
1918
|
}, [client2]);
|
|
1120
|
-
(0,
|
|
1919
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1121
1920
|
if (isOpen) {
|
|
1122
1921
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1123
1922
|
}
|
|
1124
1923
|
}, [messages, isOpen]);
|
|
1125
|
-
(0,
|
|
1924
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1126
1925
|
if (isOpen) {
|
|
1127
1926
|
setTimeout(() => {
|
|
1128
1927
|
messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
|
|
@@ -1131,7 +1930,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1131
1930
|
setUnreadCount(0);
|
|
1132
1931
|
}
|
|
1133
1932
|
}, [isOpen]);
|
|
1134
|
-
(0,
|
|
1933
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1135
1934
|
if (!isOpen && messages.length > 0) {
|
|
1136
1935
|
const unread = messages.filter(
|
|
1137
1936
|
(msg) => msg.sender !== "visitor" && msg.status !== "read"
|
|
@@ -1139,7 +1938,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1139
1938
|
setUnreadCount(unread);
|
|
1140
1939
|
}
|
|
1141
1940
|
}, [messages, isOpen]);
|
|
1142
|
-
const markMessagesAsRead = (0,
|
|
1941
|
+
const markMessagesAsRead = (0, import_hooks2.useCallback)(() => {
|
|
1143
1942
|
if (!isOpen || !isConnected) return;
|
|
1144
1943
|
const unreadMessages = messages.filter(
|
|
1145
1944
|
(msg) => msg.sender !== "visitor" && msg.status !== "read"
|
|
@@ -1149,14 +1948,14 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1149
1948
|
client2.sendReadStatus(messageIds, "read");
|
|
1150
1949
|
}
|
|
1151
1950
|
}, [isOpen, isConnected, messages, client2]);
|
|
1152
|
-
(0,
|
|
1951
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1153
1952
|
if (!isOpen || !isConnected) return;
|
|
1154
1953
|
const timer = setTimeout(() => {
|
|
1155
1954
|
markMessagesAsRead();
|
|
1156
1955
|
}, 1e3);
|
|
1157
1956
|
return () => clearTimeout(timer);
|
|
1158
1957
|
}, [isOpen, isConnected, messages, markMessagesAsRead]);
|
|
1159
|
-
(0,
|
|
1958
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1160
1959
|
const handleVisibilityChange = () => {
|
|
1161
1960
|
if (document.visibilityState === "visible" && isOpen) {
|
|
1162
1961
|
markMessagesAsRead();
|
|
@@ -1165,7 +1964,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1165
1964
|
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1166
1965
|
return () => document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1167
1966
|
}, [isOpen, markMessagesAsRead]);
|
|
1168
|
-
(0,
|
|
1967
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1169
1968
|
const unsubRead = client2.on(
|
|
1170
1969
|
"read",
|
|
1171
1970
|
() => {
|
|
@@ -1304,26 +2103,43 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1304
2103
|
y: mouseEvent.clientY
|
|
1305
2104
|
});
|
|
1306
2105
|
};
|
|
1307
|
-
const handleTouchStart = (message) => {
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
y: window.innerHeight / 2 - 50
|
|
1315
|
-
// Center vertically
|
|
1316
|
-
});
|
|
1317
|
-
}, 500);
|
|
1318
|
-
setLongPressTimer(timer);
|
|
2106
|
+
const handleTouchStart = (e, message) => {
|
|
2107
|
+
const touch = e.touches[0];
|
|
2108
|
+
touchStartRef.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
|
|
2109
|
+
if (swipedMessageId && swipedMessageId !== message.id) {
|
|
2110
|
+
setSwipedMessageId(null);
|
|
2111
|
+
setSwipeOffset(0);
|
|
2112
|
+
}
|
|
1319
2113
|
};
|
|
1320
|
-
const
|
|
1321
|
-
if (
|
|
1322
|
-
|
|
1323
|
-
|
|
2114
|
+
const handleTouchMove = (e, message) => {
|
|
2115
|
+
if (!touchStartRef.current) return;
|
|
2116
|
+
const touch = e.touches[0];
|
|
2117
|
+
const deltaX = touch.clientX - touchStartRef.current.x;
|
|
2118
|
+
const deltaY = touch.clientY - touchStartRef.current.y;
|
|
2119
|
+
if (Math.abs(deltaY) > Math.abs(deltaX)) return;
|
|
2120
|
+
if (deltaX < 0) {
|
|
2121
|
+
const offset = Math.max(deltaX, -100);
|
|
2122
|
+
setSwipeOffset(offset);
|
|
2123
|
+
setSwipedMessageId(message.id);
|
|
1324
2124
|
}
|
|
1325
2125
|
};
|
|
1326
|
-
|
|
2126
|
+
const handleTouchEnd = (message) => {
|
|
2127
|
+
if (!touchStartRef.current) return;
|
|
2128
|
+
const elapsed = Date.now() - touchStartRef.current.time;
|
|
2129
|
+
if (swipeOffset < -50 || swipeOffset < -20 && elapsed < 200) {
|
|
2130
|
+
setSwipeOffset(-80);
|
|
2131
|
+
if (navigator.vibrate) navigator.vibrate(30);
|
|
2132
|
+
} else {
|
|
2133
|
+
setSwipeOffset(0);
|
|
2134
|
+
setSwipedMessageId(null);
|
|
2135
|
+
}
|
|
2136
|
+
touchStartRef.current = null;
|
|
2137
|
+
};
|
|
2138
|
+
const resetSwipe = () => {
|
|
2139
|
+
setSwipedMessageId(null);
|
|
2140
|
+
setSwipeOffset(0);
|
|
2141
|
+
};
|
|
2142
|
+
(0, import_hooks2.useEffect)(() => {
|
|
1327
2143
|
if (!messageMenu) return;
|
|
1328
2144
|
const handleClickOutside = () => setMessageMenu(null);
|
|
1329
2145
|
document.addEventListener("click", handleClickOutside);
|
|
@@ -1339,7 +2155,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1339
2155
|
}, 1500);
|
|
1340
2156
|
}
|
|
1341
2157
|
};
|
|
1342
|
-
const dragCounterRef = (0,
|
|
2158
|
+
const dragCounterRef = (0, import_hooks2.useRef)(0);
|
|
1343
2159
|
const handleDragEnter = (e) => {
|
|
1344
2160
|
e.preventDefault();
|
|
1345
2161
|
e.stopPropagation();
|
|
@@ -1415,22 +2231,24 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1415
2231
|
const theme = getTheme(config.theme ?? "auto");
|
|
1416
2232
|
const primaryColor = config.primaryColor ?? "#6366f1";
|
|
1417
2233
|
const actionIconColor = theme === "dark" ? "#9ca3af" : "#6b7280";
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
2234
|
+
const shouldShowPreChat = preChatForm && preChatForm.enabled && !preChatForm.completed && !preChatSkipped && // Before first message: show immediately
|
|
2235
|
+
(preChatForm.timing === "before-first-message" && messages.length === 0 || preChatForm.timing === "after-first-message" && messages.some((m) => m.sender === "visitor"));
|
|
2236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_preact.Fragment, { children: [
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: styles(primaryColor, theme) }),
|
|
2238
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1421
2239
|
"button",
|
|
1422
2240
|
{
|
|
1423
2241
|
class: `pp-toggle pp-${position}`,
|
|
1424
2242
|
onClick: () => client2.toggleOpen(),
|
|
1425
2243
|
"aria-label": isOpen ? "Close chat" : "Open chat",
|
|
1426
2244
|
children: [
|
|
1427
|
-
isOpen ? /* @__PURE__ */ (0,
|
|
1428
|
-
!isOpen && unreadCount > 0 && /* @__PURE__ */ (0,
|
|
1429
|
-
!isOpen && unreadCount === 0 && operatorOnline && /* @__PURE__ */ (0,
|
|
2245
|
+
isOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CloseIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChatIcon, {}),
|
|
2246
|
+
!isOpen && unreadCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-unread-badge", children: unreadCount > 9 ? "9+" : unreadCount }),
|
|
2247
|
+
!isOpen && unreadCount === 0 && operatorOnline && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-online-dot" })
|
|
1430
2248
|
]
|
|
1431
2249
|
}
|
|
1432
2250
|
),
|
|
1433
|
-
isOpen && /* @__PURE__ */ (0,
|
|
2251
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1434
2252
|
"div",
|
|
1435
2253
|
{
|
|
1436
2254
|
class: `pp-window pp-${position} pp-theme-${theme} ${isDragging ? "pp-dragging" : ""}`,
|
|
@@ -1439,39 +2257,55 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1439
2257
|
onDragLeave: handleDragLeave,
|
|
1440
2258
|
onDrop: handleDrop,
|
|
1441
2259
|
children: [
|
|
1442
|
-
isDragging && /* @__PURE__ */ (0,
|
|
1443
|
-
/* @__PURE__ */ (0,
|
|
1444
|
-
/* @__PURE__ */ (0,
|
|
2260
|
+
isDragging && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-drop-overlay", children: [
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-drop-icon", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AttachIcon, {}) }),
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-drop-text", children: "Drop files to upload" })
|
|
1445
2263
|
] }),
|
|
1446
|
-
/* @__PURE__ */ (0,
|
|
1447
|
-
/* @__PURE__ */ (0,
|
|
1448
|
-
config.operatorAvatar && /* @__PURE__ */ (0,
|
|
1449
|
-
/* @__PURE__ */ (0,
|
|
1450
|
-
/* @__PURE__ */ (0,
|
|
1451
|
-
/* @__PURE__ */ (0,
|
|
1452
|
-
/* @__PURE__ */ (0,
|
|
2264
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-header", children: [
|
|
2265
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-header-info", children: [
|
|
2266
|
+
config.operatorAvatar && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: config.operatorAvatar, alt: "", class: "pp-avatar" }),
|
|
2267
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
2268
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-header-title", children: config.operatorName ?? "Support" }),
|
|
2269
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-header-status", children: operatorOnline ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2270
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-status-dot pp-online" }),
|
|
1453
2271
|
" Online"
|
|
1454
|
-
] }) : /* @__PURE__ */ (0,
|
|
1455
|
-
/* @__PURE__ */ (0,
|
|
2272
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2273
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-status-dot" }),
|
|
1456
2274
|
" Away"
|
|
1457
2275
|
] }) })
|
|
1458
2276
|
] })
|
|
1459
2277
|
] }),
|
|
1460
|
-
/* @__PURE__ */ (0,
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1461
2279
|
"button",
|
|
1462
2280
|
{
|
|
1463
2281
|
class: "pp-close-btn",
|
|
1464
2282
|
onClick: () => client2.setOpen(false),
|
|
1465
2283
|
"aria-label": "Close chat",
|
|
1466
|
-
children: /* @__PURE__ */ (0,
|
|
2284
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CloseIcon, {})
|
|
1467
2285
|
}
|
|
1468
2286
|
)
|
|
1469
2287
|
] }),
|
|
1470
|
-
/* @__PURE__ */ (0,
|
|
1471
|
-
|
|
1472
|
-
|
|
2288
|
+
shouldShowPreChat && preChatForm && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2289
|
+
PreChatForm,
|
|
2290
|
+
{
|
|
2291
|
+
client: client2,
|
|
2292
|
+
config: preChatForm,
|
|
2293
|
+
onComplete: () => {
|
|
2294
|
+
setPreChatForm((prev) => prev ? { ...prev, completed: true } : prev);
|
|
2295
|
+
},
|
|
2296
|
+
onSkip: () => {
|
|
2297
|
+
setPreChatSkipped(true);
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
),
|
|
2301
|
+
!shouldShowPreChat && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-messages", ref: messagesContainerRef, onClick: () => swipedMessageId && resetSwipe(), children: [
|
|
2302
|
+
config.welcomeMessage && messages.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-welcome", children: config.welcomeMessage }),
|
|
2303
|
+
messages.map((msg, index) => {
|
|
1473
2304
|
const isDeleted = !!msg.deletedAt;
|
|
1474
2305
|
const isEdited = !!msg.editedAt;
|
|
2306
|
+
const msgDate = new Date(msg.timestamp);
|
|
2307
|
+
const prevMsg = index > 0 ? messages[index - 1] : null;
|
|
2308
|
+
const showDateSeparator = !prevMsg || getDateKey(new Date(prevMsg.timestamp)) !== getDateKey(msgDate);
|
|
1475
2309
|
let replyData = null;
|
|
1476
2310
|
if (msg.replyTo) {
|
|
1477
2311
|
if (typeof msg.replyTo === "object") {
|
|
@@ -1493,123 +2327,168 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1493
2327
|
}
|
|
1494
2328
|
const isHovered = hoveredMessageId === msg.id;
|
|
1495
2329
|
const showActions = isHovered && !isDeleted;
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
2330
|
+
const isSwiped = swipedMessageId === msg.id;
|
|
2331
|
+
const msgSwipeOffset = isSwiped ? swipeOffset : 0;
|
|
2332
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_preact.Fragment, { children: [
|
|
2333
|
+
showDateSeparator && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-date-separator", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: formatDateSeparator(msgDate) }) }),
|
|
2334
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: `pp-message-swipe-container ${msg.sender === "visitor" ? "pp-swipe-left" : "pp-swipe-right"}`, children: [
|
|
2335
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-swipe-actions", children: [
|
|
2336
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2337
|
+
"button",
|
|
2338
|
+
{
|
|
2339
|
+
class: "pp-swipe-action pp-swipe-reply",
|
|
2340
|
+
onClick: () => {
|
|
2341
|
+
handleReply(msg);
|
|
2342
|
+
resetSwipe();
|
|
2343
|
+
},
|
|
2344
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReplyIcon, { color: "#fff" })
|
|
2345
|
+
}
|
|
2346
|
+
),
|
|
2347
|
+
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2348
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1510
2349
|
"button",
|
|
1511
2350
|
{
|
|
1512
|
-
class: "pp-action-
|
|
1513
|
-
onClick: () =>
|
|
1514
|
-
|
|
1515
|
-
|
|
2351
|
+
class: "pp-swipe-action pp-swipe-edit",
|
|
2352
|
+
onClick: () => {
|
|
2353
|
+
handleStartEdit(msg);
|
|
2354
|
+
resetSwipe();
|
|
2355
|
+
},
|
|
2356
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditIcon, { color: "#fff" })
|
|
1516
2357
|
}
|
|
1517
2358
|
),
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
2359
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2360
|
+
"button",
|
|
2361
|
+
{
|
|
2362
|
+
class: "pp-swipe-action pp-swipe-delete",
|
|
2363
|
+
onClick: () => {
|
|
2364
|
+
handleDelete(msg);
|
|
2365
|
+
resetSwipe();
|
|
2366
|
+
},
|
|
2367
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DeleteIcon, { color: "#fff" })
|
|
2368
|
+
}
|
|
2369
|
+
)
|
|
2370
|
+
] })
|
|
2371
|
+
] }),
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2373
|
+
"div",
|
|
2374
|
+
{
|
|
2375
|
+
id: `pp-msg-${msg.id}`,
|
|
2376
|
+
class: `pp-message pp-message-${msg.sender} ${isDeleted ? "pp-message-deleted" : ""}`,
|
|
2377
|
+
style: { transform: `translateX(${msgSwipeOffset}px)`, transition: touchStartRef.current ? "none" : "transform 0.2s ease-out" },
|
|
2378
|
+
onContextMenu: (e) => handleMessageContextMenu(e, msg),
|
|
2379
|
+
onMouseEnter: () => setHoveredMessageId(msg.id),
|
|
2380
|
+
onMouseLeave: () => setHoveredMessageId(null),
|
|
2381
|
+
onTouchStart: (e) => handleTouchStart(e, msg),
|
|
2382
|
+
onTouchMove: (e) => handleTouchMove(e, msg),
|
|
2383
|
+
onTouchEnd: () => handleTouchEnd(msg),
|
|
2384
|
+
onTouchCancel: () => handleTouchEnd(msg),
|
|
2385
|
+
children: [
|
|
2386
|
+
showActions && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: `pp-message-actions ${msg.sender === "visitor" ? "pp-actions-left" : "pp-actions-right"}`, children: [
|
|
2387
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2388
|
+
"button",
|
|
2389
|
+
{
|
|
2390
|
+
class: "pp-action-btn",
|
|
2391
|
+
onClick: () => handleReply(msg),
|
|
2392
|
+
title: "Reply",
|
|
2393
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReplyIcon, { color: actionIconColor })
|
|
2394
|
+
}
|
|
2395
|
+
),
|
|
2396
|
+
msg.sender === "visitor" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2397
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2398
|
+
"button",
|
|
2399
|
+
{
|
|
2400
|
+
class: "pp-action-btn",
|
|
2401
|
+
onClick: () => handleStartEdit(msg),
|
|
2402
|
+
title: "Edit",
|
|
2403
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditIcon, { color: actionIconColor })
|
|
2404
|
+
}
|
|
2405
|
+
),
|
|
2406
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2407
|
+
"button",
|
|
2408
|
+
{
|
|
2409
|
+
class: "pp-action-btn pp-action-delete",
|
|
2410
|
+
onClick: () => handleDelete(msg),
|
|
2411
|
+
title: "Delete",
|
|
2412
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DeleteIcon, { color: actionIconColor })
|
|
2413
|
+
}
|
|
2414
|
+
)
|
|
2415
|
+
] })
|
|
2416
|
+
] }),
|
|
2417
|
+
replyData && (replyData.content || replyData.hasAttachment) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
2418
|
+
"div",
|
|
1521
2419
|
{
|
|
1522
|
-
class: "pp-
|
|
1523
|
-
onClick: () =>
|
|
1524
|
-
|
|
1525
|
-
|
|
2420
|
+
class: "pp-reply-quote pp-reply-quote-clickable",
|
|
2421
|
+
onClick: () => scrollToMessage(replyData.id),
|
|
2422
|
+
role: "button",
|
|
2423
|
+
tabIndex: 0,
|
|
2424
|
+
onKeyDown: (e) => e.key === "Enter" && scrollToMessage(replyData.id),
|
|
2425
|
+
children: [
|
|
2426
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-reply-sender", children: replyData.sender === "visitor" ? "You" : "Support" }),
|
|
2427
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-reply-content", children: replyData.deleted ? "Message deleted" : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2428
|
+
replyData.hasAttachment && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-reply-attachment-icon", children: replyData.attachmentType?.startsWith("image/") ? "\u{1F4F7} " : "\u{1F4CE} " }),
|
|
2429
|
+
replyData.content ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2430
|
+
(replyData.content || "").slice(0, 50),
|
|
2431
|
+
(replyData.content || "").length > 50 ? "..." : ""
|
|
2432
|
+
] }) : replyData.attachmentType?.startsWith("image/") ? "Photo" : "File"
|
|
2433
|
+
] }) })
|
|
2434
|
+
]
|
|
1526
2435
|
}
|
|
1527
2436
|
),
|
|
1528
|
-
/* @__PURE__ */ (0,
|
|
1529
|
-
"
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
onKeyDown: (e) => e.key === "Enter" && scrollToMessage(replyData.id),
|
|
1547
|
-
children: [
|
|
1548
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-reply-sender", children: replyData.sender === "visitor" ? "You" : "Support" }),
|
|
1549
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-reply-content", children: replyData.deleted ? "Message deleted" : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1550
|
-
replyData.hasAttachment && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-reply-attachment-icon", children: replyData.attachmentType?.startsWith("image/") ? "\u{1F4F7} " : "\u{1F4CE} " }),
|
|
1551
|
-
replyData.content ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1552
|
-
(replyData.content || "").slice(0, 50),
|
|
1553
|
-
(replyData.content || "").length > 50 ? "..." : ""
|
|
1554
|
-
] }) : replyData.attachmentType?.startsWith("image/") ? "Photo" : "File"
|
|
1555
|
-
] }) })
|
|
1556
|
-
]
|
|
1557
|
-
}
|
|
1558
|
-
),
|
|
1559
|
-
isDeleted ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-message-content pp-deleted-content", children: [
|
|
1560
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-deleted-icon", children: "\u{1F5D1}\uFE0F" }),
|
|
1561
|
-
" Message deleted"
|
|
1562
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1563
|
-
msg.content && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { class: "pp-message-content", children: msg.content }),
|
|
1564
|
-
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { class: "pp-message-attachments", children: msg.attachments.map((att) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AttachmentDisplay, { attachment: att }, att.id)) })
|
|
1565
|
-
] }),
|
|
1566
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { class: "pp-message-time", children: [
|
|
1567
|
-
formatTime(msg.timestamp),
|
|
1568
|
-
isEdited && !isDeleted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-edited-badge", children: "edited" }),
|
|
1569
|
-
msg.sender === "ai" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: "pp-ai-badge", children: "AI" }),
|
|
1570
|
-
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { class: `pp-status pp-status-${msg.status ?? "sent"}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusIcon, { status: msg.status }) })
|
|
1571
|
-
] })
|
|
1572
|
-
]
|
|
1573
|
-
},
|
|
1574
|
-
msg.id
|
|
1575
|
-
);
|
|
2437
|
+
isDeleted ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-message-content pp-deleted-content", children: [
|
|
2438
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-deleted-icon", children: "\u{1F5D1}\uFE0F" }),
|
|
2439
|
+
" Message deleted"
|
|
2440
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2441
|
+
msg.content && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-message-content", children: msg.content }),
|
|
2442
|
+
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-message-attachments", children: msg.attachments.map((att) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AttachmentDisplay, { attachment: att }, att.id)) })
|
|
2443
|
+
] }),
|
|
2444
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-message-time", children: [
|
|
2445
|
+
formatTime(msg.timestamp),
|
|
2446
|
+
isEdited && !isDeleted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-edited-badge", children: "edited" }),
|
|
2447
|
+
msg.sender === "ai" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-ai-badge", children: "AI" }),
|
|
2448
|
+
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: `pp-status pp-status-${msg.status ?? "sent"}`, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatusIcon, { status: msg.status }) })
|
|
2449
|
+
] })
|
|
2450
|
+
]
|
|
2451
|
+
}
|
|
2452
|
+
)
|
|
2453
|
+
] })
|
|
2454
|
+
] }, msg.id);
|
|
1576
2455
|
}),
|
|
1577
|
-
isTyping && /* @__PURE__ */ (0,
|
|
1578
|
-
/* @__PURE__ */ (0,
|
|
1579
|
-
/* @__PURE__ */ (0,
|
|
1580
|
-
/* @__PURE__ */ (0,
|
|
2456
|
+
isTyping && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-message pp-message-operator pp-typing", children: [
|
|
2457
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {}),
|
|
2458
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {}),
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {})
|
|
1581
2460
|
] }),
|
|
1582
|
-
/* @__PURE__ */ (0,
|
|
2461
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: messagesEndRef })
|
|
1583
2462
|
] }),
|
|
1584
|
-
messageMenu && /* @__PURE__ */ (0,
|
|
2463
|
+
messageMenu && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1585
2464
|
"div",
|
|
1586
2465
|
{
|
|
1587
2466
|
class: "pp-message-menu",
|
|
1588
2467
|
style: { top: `${messageMenu.y}px`, left: `${messageMenu.x}px` },
|
|
1589
2468
|
children: [
|
|
1590
|
-
/* @__PURE__ */ (0,
|
|
1591
|
-
/* @__PURE__ */ (0,
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { onClick: () => handleReply(messageMenu.message), children: [
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReplyIcon, { color: actionIconColor }),
|
|
1592
2471
|
" Reply"
|
|
1593
2472
|
] }),
|
|
1594
|
-
messageMenu.message.sender === "visitor" && !messageMenu.message.deletedAt && /* @__PURE__ */ (0,
|
|
1595
|
-
/* @__PURE__ */ (0,
|
|
1596
|
-
/* @__PURE__ */ (0,
|
|
2473
|
+
messageMenu.message.sender === "visitor" && !messageMenu.message.deletedAt && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2474
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { onClick: () => handleStartEdit(messageMenu.message), children: [
|
|
2475
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EditIcon, { color: actionIconColor }),
|
|
1597
2476
|
" Edit"
|
|
1598
2477
|
] }),
|
|
1599
|
-
/* @__PURE__ */ (0,
|
|
1600
|
-
/* @__PURE__ */ (0,
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { class: "pp-menu-delete", onClick: () => handleDelete(messageMenu.message), children: [
|
|
2479
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DeleteIcon, { color: "#ef4444" }),
|
|
1601
2480
|
" Delete"
|
|
1602
2481
|
] })
|
|
1603
2482
|
] })
|
|
1604
2483
|
]
|
|
1605
2484
|
}
|
|
1606
2485
|
),
|
|
1607
|
-
editingMessage && /* @__PURE__ */ (0,
|
|
1608
|
-
/* @__PURE__ */ (0,
|
|
1609
|
-
/* @__PURE__ */ (0,
|
|
1610
|
-
/* @__PURE__ */ (0,
|
|
2486
|
+
editingMessage && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-edit-modal", children: [
|
|
2487
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-edit-header", children: [
|
|
2488
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Edit message" }),
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { onClick: handleCancelEdit, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CloseIcon, {}) })
|
|
1611
2490
|
] }),
|
|
1612
|
-
/* @__PURE__ */ (0,
|
|
2491
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1613
2492
|
"textarea",
|
|
1614
2493
|
{
|
|
1615
2494
|
class: "pp-edit-input",
|
|
@@ -1618,41 +2497,41 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1618
2497
|
autoFocus: true
|
|
1619
2498
|
}
|
|
1620
2499
|
),
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
1622
|
-
/* @__PURE__ */ (0,
|
|
1623
|
-
/* @__PURE__ */ (0,
|
|
2500
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-edit-actions", children: [
|
|
2501
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { class: "pp-edit-cancel", onClick: handleCancelEdit, children: "Cancel" }),
|
|
2502
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { class: "pp-edit-save", onClick: handleSaveEdit, disabled: !editContent.trim(), children: "Save" })
|
|
1624
2503
|
] })
|
|
1625
2504
|
] }),
|
|
1626
|
-
replyingTo && /* @__PURE__ */ (0,
|
|
1627
|
-
/* @__PURE__ */ (0,
|
|
1628
|
-
/* @__PURE__ */ (0,
|
|
1629
|
-
/* @__PURE__ */ (0,
|
|
1630
|
-
replyingTo.attachments && replyingTo.attachments.length > 0 && /* @__PURE__ */ (0,
|
|
1631
|
-
replyingTo.content ? /* @__PURE__ */ (0,
|
|
2505
|
+
replyingTo && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-reply-preview", children: [
|
|
2506
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-reply-preview-content", children: [
|
|
2507
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-reply-label", children: "Replying to" }),
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { class: "pp-reply-text", children: [
|
|
2509
|
+
replyingTo.attachments && replyingTo.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-reply-attachment-icon", children: replyingTo.attachments[0].mimeType.startsWith("image/") ? "\u{1F4F7} " : "\u{1F4CE} " }),
|
|
2510
|
+
replyingTo.content ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1632
2511
|
replyingTo.content.slice(0, 50),
|
|
1633
2512
|
replyingTo.content.length > 50 ? "..." : ""
|
|
1634
2513
|
] }) : replyingTo.attachments?.[0]?.mimeType.startsWith("image/") ? "Photo" : "File"
|
|
1635
2514
|
] })
|
|
1636
2515
|
] }),
|
|
1637
|
-
/* @__PURE__ */ (0,
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { class: "pp-reply-cancel", onClick: handleCancelReply, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CloseIcon, {}) })
|
|
1638
2517
|
] }),
|
|
1639
|
-
pendingAttachments.length > 0 && /* @__PURE__ */ (0,
|
|
1640
|
-
pending.preview ? /* @__PURE__ */ (0,
|
|
1641
|
-
/* @__PURE__ */ (0,
|
|
2518
|
+
pendingAttachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-attachments-preview", children: pendingAttachments.map((pending) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: `pp-attachment-preview pp-attachment-${pending.status}`, children: [
|
|
2519
|
+
pending.preview ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: pending.preview, alt: pending.file.name, class: "pp-preview-img" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-preview-file", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FileIcon, { mimeType: pending.file.type }) }),
|
|
2520
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1642
2521
|
"button",
|
|
1643
2522
|
{
|
|
1644
2523
|
class: "pp-remove-attachment",
|
|
1645
2524
|
onClick: () => handleRemoveAttachment(pending.id),
|
|
1646
2525
|
"aria-label": "Remove attachment",
|
|
1647
2526
|
type: "button",
|
|
1648
|
-
children: /* @__PURE__ */ (0,
|
|
2527
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CloseIcon, {})
|
|
1649
2528
|
}
|
|
1650
2529
|
),
|
|
1651
|
-
pending.status === "uploading" && /* @__PURE__ */ (0,
|
|
1652
|
-
pending.status === "error" && /* @__PURE__ */ (0,
|
|
2530
|
+
pending.status === "uploading" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-upload-progress", style: { width: `${pending.progress}%` } }),
|
|
2531
|
+
pending.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-upload-error", title: pending.error, children: "!" })
|
|
1653
2532
|
] }, pending.id)) }),
|
|
1654
|
-
/* @__PURE__ */ (0,
|
|
1655
|
-
/* @__PURE__ */ (0,
|
|
2533
|
+
!shouldShowPreChat && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { class: "pp-input-form", onSubmit: handleSubmit, children: [
|
|
2534
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1656
2535
|
"input",
|
|
1657
2536
|
{
|
|
1658
2537
|
ref: (el) => {
|
|
@@ -1667,7 +2546,7 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1667
2546
|
multiple: true
|
|
1668
2547
|
}
|
|
1669
2548
|
),
|
|
1670
|
-
/* @__PURE__ */ (0,
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1671
2550
|
"button",
|
|
1672
2551
|
{
|
|
1673
2552
|
type: "button",
|
|
@@ -1675,10 +2554,10 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1675
2554
|
onClick: () => fileInputRef.current?.click(),
|
|
1676
2555
|
disabled: !isConnected || isUploading,
|
|
1677
2556
|
"aria-label": "Attach file",
|
|
1678
|
-
children: /* @__PURE__ */ (0,
|
|
2557
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AttachIcon, {})
|
|
1679
2558
|
}
|
|
1680
2559
|
),
|
|
1681
|
-
/* @__PURE__ */ (0,
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1682
2561
|
"input",
|
|
1683
2562
|
{
|
|
1684
2563
|
ref: inputRef,
|
|
@@ -1690,20 +2569,20 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
1690
2569
|
disabled: !isConnected
|
|
1691
2570
|
}
|
|
1692
2571
|
),
|
|
1693
|
-
/* @__PURE__ */ (0,
|
|
2572
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1694
2573
|
"button",
|
|
1695
2574
|
{
|
|
1696
2575
|
type: "submit",
|
|
1697
2576
|
class: "pp-send-btn",
|
|
1698
2577
|
disabled: !inputValue.trim() && pendingAttachments.filter((a) => a.status === "ready").length === 0 || !isConnected || isUploading,
|
|
1699
2578
|
"aria-label": "Send message",
|
|
1700
|
-
children: /* @__PURE__ */ (0,
|
|
2579
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SendIcon, {})
|
|
1701
2580
|
}
|
|
1702
2581
|
)
|
|
1703
2582
|
] }),
|
|
1704
|
-
/* @__PURE__ */ (0,
|
|
2583
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-footer", children: [
|
|
1705
2584
|
"Powered by ",
|
|
1706
|
-
/* @__PURE__ */ (0,
|
|
2585
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: "https://pocketping.io", target: "_blank", rel: "noopener", children: "PocketPing" })
|
|
1707
2586
|
] })
|
|
1708
2587
|
]
|
|
1709
2588
|
}
|
|
@@ -1731,90 +2610,90 @@ function formatTime(timestamp) {
|
|
|
1731
2610
|
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
1732
2611
|
}
|
|
1733
2612
|
function ChatIcon() {
|
|
1734
|
-
return /* @__PURE__ */ (0,
|
|
2613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
|
|
1735
2614
|
}
|
|
1736
2615
|
function CloseIcon() {
|
|
1737
|
-
return /* @__PURE__ */ (0,
|
|
1738
|
-
/* @__PURE__ */ (0,
|
|
1739
|
-
/* @__PURE__ */ (0,
|
|
2616
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2617
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1740
2619
|
] });
|
|
1741
2620
|
}
|
|
1742
2621
|
function SendIcon() {
|
|
1743
|
-
return /* @__PURE__ */ (0,
|
|
1744
|
-
/* @__PURE__ */ (0,
|
|
1745
|
-
/* @__PURE__ */ (0,
|
|
2622
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
2624
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
1746
2625
|
] });
|
|
1747
2626
|
}
|
|
1748
2627
|
function StatusIcon({ status }) {
|
|
1749
2628
|
if (!status || status === "sending" || status === "sent") {
|
|
1750
|
-
return /* @__PURE__ */ (0,
|
|
2629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", "stroke-width": "2", class: "pp-check", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "3 8 7 12 13 4" }) });
|
|
1751
2630
|
}
|
|
1752
2631
|
if (status === "delivered") {
|
|
1753
|
-
return /* @__PURE__ */ (0,
|
|
1754
|
-
/* @__PURE__ */ (0,
|
|
1755
|
-
/* @__PURE__ */ (0,
|
|
2632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 20 16", fill: "none", stroke: "currentColor", "stroke-width": "2", class: "pp-check-double", children: [
|
|
2633
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "1 8 5 12 11 4" }),
|
|
2634
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "7 8 11 12 17 4" })
|
|
1756
2635
|
] });
|
|
1757
2636
|
}
|
|
1758
2637
|
if (status === "read") {
|
|
1759
|
-
return /* @__PURE__ */ (0,
|
|
1760
|
-
/* @__PURE__ */ (0,
|
|
1761
|
-
/* @__PURE__ */ (0,
|
|
2638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 20 16", fill: "none", stroke: "currentColor", "stroke-width": "2", class: "pp-check-double pp-check-read", children: [
|
|
2639
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "1 8 5 12 11 4" }),
|
|
2640
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "7 8 11 12 17 4" })
|
|
1762
2641
|
] });
|
|
1763
2642
|
}
|
|
1764
2643
|
return null;
|
|
1765
2644
|
}
|
|
1766
2645
|
function AttachIcon() {
|
|
1767
|
-
return /* @__PURE__ */ (0,
|
|
2646
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }) });
|
|
1768
2647
|
}
|
|
1769
2648
|
function ReplyIcon({ color, size = 16 }) {
|
|
1770
2649
|
const strokeColor = color || "currentColor";
|
|
1771
|
-
return /* @__PURE__ */ (0,
|
|
1772
|
-
/* @__PURE__ */ (0,
|
|
1773
|
-
/* @__PURE__ */ (0,
|
|
2650
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
2651
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "9 17 4 12 9 7" }),
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M20 18v-2a4 4 0 0 0-4-4H4" })
|
|
1774
2653
|
] });
|
|
1775
2654
|
}
|
|
1776
2655
|
function EditIcon({ color, size = 16 }) {
|
|
1777
2656
|
const strokeColor = color || "currentColor";
|
|
1778
|
-
return /* @__PURE__ */ (0,
|
|
2657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" }) });
|
|
1779
2658
|
}
|
|
1780
2659
|
function DeleteIcon({ color, size = 16 }) {
|
|
1781
2660
|
const strokeColor = color || "currentColor";
|
|
1782
|
-
return /* @__PURE__ */ (0,
|
|
1783
|
-
/* @__PURE__ */ (0,
|
|
1784
|
-
/* @__PURE__ */ (0,
|
|
2661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("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: [
|
|
2662
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "3 6 5 6 21 6" }),
|
|
2663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" })
|
|
1785
2664
|
] });
|
|
1786
2665
|
}
|
|
1787
2666
|
function FileIcon({ mimeType }) {
|
|
1788
2667
|
if (mimeType === "application/pdf") {
|
|
1789
|
-
return /* @__PURE__ */ (0,
|
|
1790
|
-
/* @__PURE__ */ (0,
|
|
1791
|
-
/* @__PURE__ */ (0,
|
|
1792
|
-
/* @__PURE__ */ (0,
|
|
1793
|
-
/* @__PURE__ */ (0,
|
|
2668
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2669
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
2670
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "14 2 14 8 20 8" }),
|
|
2671
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 15h6" }),
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 11h6" })
|
|
1794
2673
|
] });
|
|
1795
2674
|
}
|
|
1796
2675
|
if (mimeType.startsWith("audio/")) {
|
|
1797
|
-
return /* @__PURE__ */ (0,
|
|
1798
|
-
/* @__PURE__ */ (0,
|
|
1799
|
-
/* @__PURE__ */ (0,
|
|
1800
|
-
/* @__PURE__ */ (0,
|
|
2676
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2677
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9 18V5l12-2v13" }),
|
|
2678
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "6", cy: "18", r: "3" }),
|
|
2679
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "18", cy: "16", r: "3" })
|
|
1801
2680
|
] });
|
|
1802
2681
|
}
|
|
1803
2682
|
if (mimeType.startsWith("video/")) {
|
|
1804
|
-
return /* @__PURE__ */ (0,
|
|
1805
|
-
/* @__PURE__ */ (0,
|
|
1806
|
-
/* @__PURE__ */ (0,
|
|
1807
|
-
/* @__PURE__ */ (0,
|
|
1808
|
-
/* @__PURE__ */ (0,
|
|
1809
|
-
/* @__PURE__ */ (0,
|
|
1810
|
-
/* @__PURE__ */ (0,
|
|
1811
|
-
/* @__PURE__ */ (0,
|
|
1812
|
-
/* @__PURE__ */ (0,
|
|
2683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2684
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "2", y: "2", width: "20", height: "20", rx: "2.18", ry: "2.18" }),
|
|
2685
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "7", y1: "2", x2: "7", y2: "22" }),
|
|
2686
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "17", y1: "2", x2: "17", y2: "22" }),
|
|
2687
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "2", y1: "7", x2: "7", y2: "7" }),
|
|
2689
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "2", y1: "17", x2: "7", y2: "17" }),
|
|
2690
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "17", y1: "17", x2: "22", y2: "17" }),
|
|
2691
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "17", y1: "7", x2: "22", y2: "7" })
|
|
1813
2692
|
] });
|
|
1814
2693
|
}
|
|
1815
|
-
return /* @__PURE__ */ (0,
|
|
1816
|
-
/* @__PURE__ */ (0,
|
|
1817
|
-
/* @__PURE__ */ (0,
|
|
2694
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
2695
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
2696
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "14 2 14 8 20 8" })
|
|
1818
2697
|
] });
|
|
1819
2698
|
}
|
|
1820
2699
|
function AttachmentDisplay({ attachment }) {
|
|
@@ -1827,28 +2706,28 @@ function AttachmentDisplay({ attachment }) {
|
|
|
1827
2706
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1828
2707
|
};
|
|
1829
2708
|
if (isImage) {
|
|
1830
|
-
return /* @__PURE__ */ (0,
|
|
2709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: attachment.url, target: "_blank", rel: "noopener", class: "pp-attachment pp-attachment-image", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: attachment.thumbnailUrl || attachment.url, alt: attachment.filename }) });
|
|
1831
2710
|
}
|
|
1832
2711
|
if (isAudio) {
|
|
1833
|
-
return /* @__PURE__ */ (0,
|
|
1834
|
-
/* @__PURE__ */ (0,
|
|
1835
|
-
/* @__PURE__ */ (0,
|
|
2712
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-attachment pp-attachment-audio", children: [
|
|
2713
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("audio", { controls: true, preload: "metadata", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("source", { src: attachment.url, type: attachment.mimeType }) }),
|
|
2714
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-attachment-name", children: attachment.filename })
|
|
1836
2715
|
] });
|
|
1837
2716
|
}
|
|
1838
2717
|
if (isVideo) {
|
|
1839
|
-
return /* @__PURE__ */ (0,
|
|
2718
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { class: "pp-attachment pp-attachment-video", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("video", { controls: true, preload: "metadata", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("source", { src: attachment.url, type: attachment.mimeType }) }) });
|
|
1840
2719
|
}
|
|
1841
|
-
return /* @__PURE__ */ (0,
|
|
1842
|
-
/* @__PURE__ */ (0,
|
|
1843
|
-
/* @__PURE__ */ (0,
|
|
1844
|
-
/* @__PURE__ */ (0,
|
|
1845
|
-
/* @__PURE__ */ (0,
|
|
2720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("a", { href: attachment.url, target: "_blank", rel: "noopener", class: "pp-attachment pp-attachment-file", children: [
|
|
2721
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FileIcon, { mimeType: attachment.mimeType }),
|
|
2722
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { class: "pp-attachment-info", children: [
|
|
2723
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-attachment-name", children: attachment.filename }),
|
|
2724
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { class: "pp-attachment-size", children: formatSize(attachment.size) })
|
|
1846
2725
|
] })
|
|
1847
2726
|
] });
|
|
1848
2727
|
}
|
|
1849
2728
|
|
|
1850
2729
|
// src/version.ts
|
|
1851
|
-
var VERSION = "0.3.
|
|
2730
|
+
var VERSION = "0.3.7";
|
|
1852
2731
|
|
|
1853
2732
|
// src/client.ts
|
|
1854
2733
|
var PocketPingClient = class {
|
|
@@ -1908,7 +2787,8 @@ var PocketPingClient = class {
|
|
|
1908
2787
|
visitorId: response.visitorId,
|
|
1909
2788
|
operatorOnline: response.operatorOnline ?? false,
|
|
1910
2789
|
messages: response.messages ?? [],
|
|
1911
|
-
identity: response.identity || storedIdentity || void 0
|
|
2790
|
+
identity: response.identity || storedIdentity || void 0,
|
|
2791
|
+
preChatForm: response.preChatForm
|
|
1912
2792
|
};
|
|
1913
2793
|
if (response.operatorName) {
|
|
1914
2794
|
this.config.operatorName = response.operatorName;
|
|
@@ -2264,6 +3144,36 @@ var PocketPingClient = class {
|
|
|
2264
3144
|
}
|
|
2265
3145
|
}
|
|
2266
3146
|
}
|
|
3147
|
+
/**
|
|
3148
|
+
* Submit pre-chat form data (email and/or phone)
|
|
3149
|
+
* @param data - Form data containing email and/or phone
|
|
3150
|
+
*/
|
|
3151
|
+
async submitPreChat(data) {
|
|
3152
|
+
if (!this.session) {
|
|
3153
|
+
throw new Error("[PocketPing] Not connected");
|
|
3154
|
+
}
|
|
3155
|
+
if (!data.email && !data.phone) {
|
|
3156
|
+
throw new Error("[PocketPing] Either email or phone is required");
|
|
3157
|
+
}
|
|
3158
|
+
try {
|
|
3159
|
+
await this.fetch("/prechat", {
|
|
3160
|
+
method: "POST",
|
|
3161
|
+
body: JSON.stringify({
|
|
3162
|
+
sessionId: this.session.sessionId,
|
|
3163
|
+
email: data.email,
|
|
3164
|
+
phone: data.phone,
|
|
3165
|
+
phoneCountry: data.phoneCountry
|
|
3166
|
+
})
|
|
3167
|
+
});
|
|
3168
|
+
if (this.session.preChatForm) {
|
|
3169
|
+
this.session.preChatForm.completed = true;
|
|
3170
|
+
}
|
|
3171
|
+
this.emit("preChatCompleted", data);
|
|
3172
|
+
} catch (err) {
|
|
3173
|
+
console.error("[PocketPing] Failed to submit pre-chat form:", err);
|
|
3174
|
+
throw err;
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
2267
3177
|
/**
|
|
2268
3178
|
* Reset the user identity and optionally start a new session
|
|
2269
3179
|
* Call on user logout to clear user data
|
|
@@ -2913,6 +3823,12 @@ var PocketPingClient = class {
|
|
|
2913
3823
|
this.session.messages.push(message);
|
|
2914
3824
|
this.emit("message", message);
|
|
2915
3825
|
this.config.onMessage?.(message);
|
|
3826
|
+
if (message.sender !== "visitor" && !this.isOpen) {
|
|
3827
|
+
const autoOpen = this.config.autoOpenOnMessage ?? true;
|
|
3828
|
+
if (autoOpen) {
|
|
3829
|
+
this.setOpen(true);
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
2916
3832
|
}
|
|
2917
3833
|
}
|
|
2918
3834
|
if (message.sender !== "visitor") {
|
|
@@ -3071,6 +3987,12 @@ var PocketPingClient = class {
|
|
|
3071
3987
|
this.session.messages.push(message);
|
|
3072
3988
|
this.emit("message", message);
|
|
3073
3989
|
this.config.onMessage?.(message);
|
|
3990
|
+
if (message.sender !== "visitor" && !this.isOpen) {
|
|
3991
|
+
const autoOpen = this.config.autoOpenOnMessage ?? true;
|
|
3992
|
+
if (autoOpen) {
|
|
3993
|
+
this.setOpen(true);
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3074
3996
|
}
|
|
3075
3997
|
}
|
|
3076
3998
|
} catch (err) {
|