@pocketping/widget 1.1.0 → 1.3.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/dist/index.cjs +1493 -142
- package/dist/index.d.cts +85 -4
- package/dist/index.d.ts +85 -4
- package/dist/index.js +1490 -141
- package/dist/pocketping.min.global.js +593 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -190,6 +190,12 @@ function styles(primaryColor, theme) {
|
|
|
190
190
|
border-radius: 4px;
|
|
191
191
|
opacity: 0.8;
|
|
192
192
|
transition: opacity 0.2s;
|
|
193
|
+
flex-shrink: 0;
|
|
194
|
+
width: 28px;
|
|
195
|
+
height: 28px;
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: center;
|
|
193
199
|
}
|
|
194
200
|
|
|
195
201
|
.pp-close-btn:hover {
|
|
@@ -197,8 +203,8 @@ function styles(primaryColor, theme) {
|
|
|
197
203
|
}
|
|
198
204
|
|
|
199
205
|
.pp-close-btn svg {
|
|
200
|
-
width:
|
|
201
|
-
height:
|
|
206
|
+
width: 16px;
|
|
207
|
+
height: 16px;
|
|
202
208
|
}
|
|
203
209
|
|
|
204
210
|
.pp-messages {
|
|
@@ -222,6 +228,94 @@ function styles(primaryColor, theme) {
|
|
|
222
228
|
padding: 10px 14px;
|
|
223
229
|
border-radius: 16px;
|
|
224
230
|
word-wrap: break-word;
|
|
231
|
+
position: relative;
|
|
232
|
+
user-select: text;
|
|
233
|
+
-webkit-user-select: text;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Hover actions container - positioned above message (Slack style) */
|
|
237
|
+
.pp-message-actions {
|
|
238
|
+
position: absolute;
|
|
239
|
+
top: -28px;
|
|
240
|
+
display: flex;
|
|
241
|
+
gap: 2px;
|
|
242
|
+
background: ${colors.bg};
|
|
243
|
+
border: 1px solid ${colors.border};
|
|
244
|
+
border-radius: 6px;
|
|
245
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
246
|
+
padding: 2px;
|
|
247
|
+
opacity: 0;
|
|
248
|
+
animation: pp-actions-fade-in 0.12s ease forwards;
|
|
249
|
+
z-index: 10;
|
|
250
|
+
/* Reset color inheritance from message */
|
|
251
|
+
color: ${colors.textSecondary};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@keyframes pp-actions-fade-in {
|
|
255
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
256
|
+
to { opacity: 1; transform: translateY(0); }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* Visitor messages: actions aligned right */
|
|
260
|
+
.pp-actions-left {
|
|
261
|
+
right: 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* Operator messages: actions aligned left */
|
|
265
|
+
.pp-actions-right {
|
|
266
|
+
left: 0;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.pp-message-actions .pp-action-btn {
|
|
270
|
+
width: 24px;
|
|
271
|
+
height: 24px;
|
|
272
|
+
border: none;
|
|
273
|
+
background: transparent;
|
|
274
|
+
border-radius: 4px;
|
|
275
|
+
cursor: pointer;
|
|
276
|
+
display: flex;
|
|
277
|
+
align-items: center;
|
|
278
|
+
justify-content: center;
|
|
279
|
+
color: ${colors.textSecondary} !important;
|
|
280
|
+
transition: background 0.1s, color 0.1s;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.pp-message-actions .pp-action-btn:hover {
|
|
284
|
+
background: ${colors.bgSecondary};
|
|
285
|
+
color: ${colors.text} !important;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.pp-message-actions .pp-action-btn svg {
|
|
289
|
+
width: 14px;
|
|
290
|
+
height: 14px;
|
|
291
|
+
stroke: ${colors.textSecondary};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.pp-message-actions .pp-action-btn:hover svg {
|
|
295
|
+
stroke: ${colors.text};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.pp-message-actions .pp-action-delete:hover {
|
|
299
|
+
background: #fef2f2;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.pp-message-actions .pp-action-delete:hover svg {
|
|
303
|
+
stroke: #ef4444;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.pp-theme-dark .pp-message-actions .pp-action-delete:hover {
|
|
307
|
+
background: #7f1d1d;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.pp-theme-dark .pp-message-actions .pp-action-delete:hover svg {
|
|
311
|
+
stroke: #fca5a5;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* Hide hover actions on mobile */
|
|
315
|
+
@media (hover: none) and (pointer: coarse) {
|
|
316
|
+
.pp-message-actions {
|
|
317
|
+
display: none;
|
|
318
|
+
}
|
|
225
319
|
}
|
|
226
320
|
|
|
227
321
|
.pp-message-visitor {
|
|
@@ -305,72 +399,565 @@ function styles(primaryColor, theme) {
|
|
|
305
399
|
40% { transform: scale(1); }
|
|
306
400
|
}
|
|
307
401
|
|
|
308
|
-
.pp-input-form {
|
|
309
|
-
display: flex;
|
|
310
|
-
padding: 12px;
|
|
311
|
-
gap: 8px;
|
|
312
|
-
border-top: 1px solid ${colors.border};
|
|
402
|
+
.pp-input-form {
|
|
403
|
+
display: flex;
|
|
404
|
+
padding: 12px;
|
|
405
|
+
gap: 8px;
|
|
406
|
+
border-top: 1px solid ${colors.border};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.pp-input {
|
|
410
|
+
flex: 1;
|
|
411
|
+
padding: 10px 14px;
|
|
412
|
+
border: 1px solid ${colors.border};
|
|
413
|
+
border-radius: 20px;
|
|
414
|
+
background: ${colors.bg};
|
|
415
|
+
color: ${colors.text};
|
|
416
|
+
font-size: 14px;
|
|
417
|
+
outline: none;
|
|
418
|
+
transition: border-color 0.2s;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.pp-input:focus {
|
|
422
|
+
border-color: ${primaryColor};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.pp-input::placeholder {
|
|
426
|
+
color: ${colors.textSecondary};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.pp-send-btn {
|
|
430
|
+
width: 40px;
|
|
431
|
+
height: 40px;
|
|
432
|
+
border-radius: 50%;
|
|
433
|
+
background: ${primaryColor};
|
|
434
|
+
color: white;
|
|
435
|
+
border: none;
|
|
436
|
+
cursor: pointer;
|
|
437
|
+
display: flex;
|
|
438
|
+
align-items: center;
|
|
439
|
+
justify-content: center;
|
|
440
|
+
transition: opacity 0.2s;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.pp-send-btn:disabled {
|
|
444
|
+
opacity: 0.5;
|
|
445
|
+
cursor: not-allowed;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.pp-send-btn svg {
|
|
449
|
+
width: 18px;
|
|
450
|
+
height: 18px;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.pp-footer {
|
|
454
|
+
text-align: center;
|
|
455
|
+
padding: 8px;
|
|
456
|
+
font-size: 11px;
|
|
457
|
+
color: ${colors.textSecondary};
|
|
458
|
+
border-top: 1px solid ${colors.border};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.pp-footer a {
|
|
462
|
+
color: ${primaryColor};
|
|
463
|
+
text-decoration: none;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.pp-footer a:hover {
|
|
467
|
+
text-decoration: underline;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* Attachment Styles */
|
|
471
|
+
.pp-file-input {
|
|
472
|
+
/* Use offscreen positioning instead of display:none for better browser compatibility */
|
|
473
|
+
position: absolute;
|
|
474
|
+
width: 1px;
|
|
475
|
+
height: 1px;
|
|
476
|
+
padding: 0;
|
|
477
|
+
margin: -1px;
|
|
478
|
+
overflow: hidden;
|
|
479
|
+
clip: rect(0, 0, 0, 0);
|
|
480
|
+
white-space: nowrap;
|
|
481
|
+
border: 0;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.pp-attach-btn {
|
|
485
|
+
width: 40px;
|
|
486
|
+
height: 40px;
|
|
487
|
+
border-radius: 50%;
|
|
488
|
+
background: transparent;
|
|
489
|
+
color: ${colors.textSecondary};
|
|
490
|
+
border: 1px solid ${colors.border};
|
|
491
|
+
cursor: pointer;
|
|
492
|
+
display: flex;
|
|
493
|
+
align-items: center;
|
|
494
|
+
justify-content: center;
|
|
495
|
+
transition: color 0.2s, border-color 0.2s;
|
|
496
|
+
flex-shrink: 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.pp-attach-btn:hover:not(:disabled) {
|
|
500
|
+
color: ${primaryColor};
|
|
501
|
+
border-color: ${primaryColor};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.pp-attach-btn:disabled {
|
|
505
|
+
opacity: 0.5;
|
|
506
|
+
cursor: not-allowed;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.pp-attach-btn svg {
|
|
510
|
+
width: 18px;
|
|
511
|
+
height: 18px;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.pp-attachments-preview {
|
|
515
|
+
display: flex;
|
|
516
|
+
gap: 8px;
|
|
517
|
+
padding: 8px 12px;
|
|
518
|
+
border-top: 1px solid ${colors.border};
|
|
519
|
+
overflow-x: auto;
|
|
520
|
+
background: ${colors.bgSecondary};
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.pp-attachment-preview {
|
|
524
|
+
position: relative;
|
|
525
|
+
width: 60px;
|
|
526
|
+
height: 60px;
|
|
527
|
+
border-radius: 8px;
|
|
528
|
+
overflow: hidden;
|
|
529
|
+
flex-shrink: 0;
|
|
530
|
+
background: ${colors.bg};
|
|
531
|
+
border: 1px solid ${colors.border};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.pp-preview-img {
|
|
535
|
+
width: 100%;
|
|
536
|
+
height: 100%;
|
|
537
|
+
object-fit: cover;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.pp-preview-file {
|
|
541
|
+
width: 100%;
|
|
542
|
+
height: 100%;
|
|
543
|
+
display: flex;
|
|
544
|
+
align-items: center;
|
|
545
|
+
justify-content: center;
|
|
546
|
+
color: ${colors.textSecondary};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.pp-preview-file svg {
|
|
550
|
+
width: 24px;
|
|
551
|
+
height: 24px;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.pp-remove-attachment {
|
|
555
|
+
position: absolute;
|
|
556
|
+
top: 2px;
|
|
557
|
+
right: 2px;
|
|
558
|
+
width: 18px;
|
|
559
|
+
height: 18px;
|
|
560
|
+
border-radius: 50%;
|
|
561
|
+
background: rgba(0, 0, 0, 0.6);
|
|
562
|
+
color: white;
|
|
563
|
+
border: none;
|
|
564
|
+
cursor: pointer;
|
|
565
|
+
display: flex;
|
|
566
|
+
align-items: center;
|
|
567
|
+
justify-content: center;
|
|
568
|
+
padding: 0;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.pp-remove-attachment svg {
|
|
572
|
+
width: 10px;
|
|
573
|
+
height: 10px;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.pp-upload-progress {
|
|
577
|
+
position: absolute;
|
|
578
|
+
bottom: 0;
|
|
579
|
+
left: 0;
|
|
580
|
+
height: 3px;
|
|
581
|
+
background: ${primaryColor};
|
|
582
|
+
transition: width 0.1s;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.pp-upload-error {
|
|
586
|
+
position: absolute;
|
|
587
|
+
top: 50%;
|
|
588
|
+
left: 50%;
|
|
589
|
+
transform: translate(-50%, -50%);
|
|
590
|
+
width: 24px;
|
|
591
|
+
height: 24px;
|
|
592
|
+
border-radius: 50%;
|
|
593
|
+
background: #ef4444;
|
|
594
|
+
color: white;
|
|
595
|
+
font-weight: bold;
|
|
596
|
+
display: flex;
|
|
597
|
+
align-items: center;
|
|
598
|
+
justify-content: center;
|
|
599
|
+
font-size: 14px;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.pp-attachment-uploading {
|
|
603
|
+
opacity: 0.7;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.pp-attachment-error {
|
|
607
|
+
border-color: #ef4444;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/* Message Attachments */
|
|
611
|
+
.pp-message-attachments {
|
|
612
|
+
display: flex;
|
|
613
|
+
flex-direction: column;
|
|
614
|
+
gap: 8px;
|
|
615
|
+
margin-top: 4px;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.pp-attachment {
|
|
619
|
+
display: block;
|
|
620
|
+
text-decoration: none;
|
|
621
|
+
color: inherit;
|
|
622
|
+
border-radius: 8px;
|
|
623
|
+
overflow: hidden;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.pp-attachment-image img {
|
|
627
|
+
max-width: 200px;
|
|
628
|
+
max-height: 200px;
|
|
629
|
+
border-radius: 8px;
|
|
630
|
+
display: block;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.pp-attachment-audio {
|
|
634
|
+
display: flex;
|
|
635
|
+
flex-direction: column;
|
|
636
|
+
gap: 4px;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.pp-attachment-audio audio {
|
|
640
|
+
width: 200px;
|
|
641
|
+
height: 36px;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.pp-attachment-audio .pp-attachment-name {
|
|
645
|
+
font-size: 11px;
|
|
646
|
+
opacity: 0.7;
|
|
647
|
+
white-space: nowrap;
|
|
648
|
+
overflow: hidden;
|
|
649
|
+
text-overflow: ellipsis;
|
|
650
|
+
max-width: 200px;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
.pp-attachment-video video {
|
|
654
|
+
max-width: 200px;
|
|
655
|
+
max-height: 200px;
|
|
656
|
+
border-radius: 8px;
|
|
657
|
+
display: block;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.pp-attachment-file {
|
|
661
|
+
display: flex;
|
|
662
|
+
align-items: center;
|
|
663
|
+
gap: 8px;
|
|
664
|
+
padding: 8px 12px;
|
|
665
|
+
background: ${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.05)"};
|
|
666
|
+
border-radius: 8px;
|
|
667
|
+
transition: background 0.2s;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.pp-attachment-file:hover {
|
|
671
|
+
background: ${isDark ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.08)"};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.pp-attachment-file svg {
|
|
675
|
+
width: 24px;
|
|
676
|
+
height: 24px;
|
|
677
|
+
flex-shrink: 0;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.pp-attachment-info {
|
|
681
|
+
display: flex;
|
|
682
|
+
flex-direction: column;
|
|
683
|
+
min-width: 0;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.pp-attachment-name {
|
|
687
|
+
font-size: 13px;
|
|
688
|
+
font-weight: 500;
|
|
689
|
+
white-space: nowrap;
|
|
690
|
+
overflow: hidden;
|
|
691
|
+
text-overflow: ellipsis;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.pp-attachment-size {
|
|
695
|
+
font-size: 11px;
|
|
696
|
+
opacity: 0.7;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/* Drag & Drop */
|
|
700
|
+
.pp-dragging {
|
|
701
|
+
position: relative;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.pp-drop-overlay {
|
|
705
|
+
position: absolute;
|
|
706
|
+
inset: 0;
|
|
707
|
+
background: ${isDark ? "rgba(0,0,0,0.9)" : "rgba(255,255,255,0.95)"};
|
|
708
|
+
display: flex;
|
|
709
|
+
flex-direction: column;
|
|
710
|
+
align-items: center;
|
|
711
|
+
justify-content: center;
|
|
712
|
+
gap: 12px;
|
|
713
|
+
z-index: 100;
|
|
714
|
+
border: 3px dashed ${primaryColor};
|
|
715
|
+
border-radius: 16px;
|
|
716
|
+
margin: 4px;
|
|
717
|
+
pointer-events: none;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.pp-drop-icon svg {
|
|
721
|
+
width: 48px;
|
|
722
|
+
height: 48px;
|
|
723
|
+
color: ${primaryColor};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.pp-drop-text {
|
|
727
|
+
font-size: 16px;
|
|
728
|
+
font-weight: 500;
|
|
729
|
+
color: ${colors.text};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/* Message Context Menu */
|
|
733
|
+
.pp-message-menu {
|
|
734
|
+
position: fixed;
|
|
735
|
+
background: ${colors.bg};
|
|
736
|
+
border: 1px solid ${colors.border};
|
|
737
|
+
border-radius: 8px;
|
|
738
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
739
|
+
padding: 4px;
|
|
740
|
+
z-index: 200;
|
|
741
|
+
min-width: 120px;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.pp-message-menu button {
|
|
745
|
+
display: flex;
|
|
746
|
+
align-items: center;
|
|
747
|
+
gap: 8px;
|
|
748
|
+
width: 100%;
|
|
749
|
+
padding: 8px 12px;
|
|
750
|
+
border: none;
|
|
751
|
+
background: transparent;
|
|
752
|
+
color: ${colors.text};
|
|
753
|
+
font-size: 13px;
|
|
754
|
+
cursor: pointer;
|
|
755
|
+
border-radius: 4px;
|
|
756
|
+
text-align: left;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.pp-message-menu button:hover {
|
|
760
|
+
background: ${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.05)"};
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.pp-message-menu button svg {
|
|
764
|
+
width: 16px;
|
|
765
|
+
height: 16px;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.pp-menu-delete {
|
|
769
|
+
color: #ef4444 !important;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/* Edit Modal */
|
|
773
|
+
.pp-edit-modal {
|
|
774
|
+
position: absolute;
|
|
775
|
+
bottom: 80px;
|
|
776
|
+
left: 12px;
|
|
777
|
+
right: 12px;
|
|
778
|
+
background: ${colors.bg};
|
|
779
|
+
border: 1px solid ${colors.border};
|
|
780
|
+
border-radius: 12px;
|
|
781
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
|
782
|
+
z-index: 150;
|
|
783
|
+
overflow: hidden;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.pp-edit-header {
|
|
787
|
+
display: flex;
|
|
788
|
+
justify-content: space-between;
|
|
789
|
+
align-items: center;
|
|
790
|
+
padding: 12px 16px;
|
|
791
|
+
border-bottom: 1px solid ${colors.border};
|
|
792
|
+
font-weight: 500;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.pp-edit-header button {
|
|
796
|
+
background: transparent;
|
|
797
|
+
border: none;
|
|
798
|
+
color: ${colors.textSecondary};
|
|
799
|
+
cursor: pointer;
|
|
800
|
+
padding: 4px;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.pp-edit-header button svg {
|
|
804
|
+
width: 18px;
|
|
805
|
+
height: 18px;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
.pp-edit-input {
|
|
809
|
+
width: 100%;
|
|
810
|
+
padding: 12px 16px;
|
|
811
|
+
border: none;
|
|
812
|
+
background: transparent;
|
|
813
|
+
color: ${colors.text};
|
|
814
|
+
font-size: 14px;
|
|
815
|
+
resize: none;
|
|
816
|
+
min-height: 80px;
|
|
817
|
+
outline: none;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
.pp-edit-actions {
|
|
821
|
+
display: flex;
|
|
822
|
+
justify-content: flex-end;
|
|
823
|
+
gap: 8px;
|
|
824
|
+
padding: 12px 16px;
|
|
825
|
+
border-top: 1px solid ${colors.border};
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.pp-edit-cancel {
|
|
829
|
+
padding: 8px 16px;
|
|
830
|
+
border: 1px solid ${colors.border};
|
|
831
|
+
border-radius: 6px;
|
|
832
|
+
background: transparent;
|
|
833
|
+
color: ${colors.text};
|
|
834
|
+
font-size: 13px;
|
|
835
|
+
cursor: pointer;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
.pp-edit-save {
|
|
839
|
+
padding: 8px 16px;
|
|
840
|
+
border: none;
|
|
841
|
+
border-radius: 6px;
|
|
842
|
+
background: ${primaryColor};
|
|
843
|
+
color: white;
|
|
844
|
+
font-size: 13px;
|
|
845
|
+
cursor: pointer;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.pp-edit-save:disabled {
|
|
849
|
+
opacity: 0.5;
|
|
850
|
+
cursor: not-allowed;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/* Reply Preview */
|
|
854
|
+
.pp-reply-preview {
|
|
855
|
+
display: flex;
|
|
856
|
+
align-items: center;
|
|
857
|
+
gap: 8px;
|
|
858
|
+
padding: 8px 12px;
|
|
859
|
+
background: ${isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.03)"};
|
|
860
|
+
border-top: 1px solid ${colors.border};
|
|
861
|
+
border-left: 3px solid ${primaryColor};
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.pp-reply-preview-content {
|
|
865
|
+
flex: 1;
|
|
866
|
+
min-width: 0;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
.pp-reply-label {
|
|
870
|
+
display: block;
|
|
871
|
+
font-size: 11px;
|
|
872
|
+
color: ${primaryColor};
|
|
873
|
+
font-weight: 500;
|
|
874
|
+
margin-bottom: 2px;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
.pp-reply-text {
|
|
878
|
+
display: block;
|
|
879
|
+
font-size: 12px;
|
|
880
|
+
color: ${colors.textSecondary};
|
|
881
|
+
white-space: nowrap;
|
|
882
|
+
overflow: hidden;
|
|
883
|
+
text-overflow: ellipsis;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
.pp-reply-cancel {
|
|
887
|
+
background: transparent;
|
|
888
|
+
border: none;
|
|
889
|
+
color: ${colors.textSecondary};
|
|
890
|
+
cursor: pointer;
|
|
891
|
+
padding: 4px;
|
|
892
|
+
flex-shrink: 0;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.pp-reply-cancel svg {
|
|
896
|
+
width: 16px;
|
|
897
|
+
height: 16px;
|
|
313
898
|
}
|
|
314
899
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
border:
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
font-size:
|
|
323
|
-
|
|
324
|
-
|
|
900
|
+
/* Reply Quote in Message */
|
|
901
|
+
.pp-reply-quote {
|
|
902
|
+
background: ${isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.05)"};
|
|
903
|
+
border-left: 2px solid ${primaryColor};
|
|
904
|
+
padding: 4px 8px;
|
|
905
|
+
margin-bottom: 6px;
|
|
906
|
+
border-radius: 0 4px 4px 0;
|
|
907
|
+
font-size: 12px;
|
|
908
|
+
position: relative;
|
|
909
|
+
z-index: 1;
|
|
325
910
|
}
|
|
326
911
|
|
|
327
|
-
.pp-
|
|
328
|
-
|
|
912
|
+
.pp-reply-sender {
|
|
913
|
+
display: block;
|
|
914
|
+
font-weight: 500;
|
|
915
|
+
color: ${primaryColor};
|
|
916
|
+
margin-bottom: 2px;
|
|
329
917
|
}
|
|
330
918
|
|
|
331
|
-
.pp-
|
|
919
|
+
.pp-reply-content {
|
|
920
|
+
display: block;
|
|
332
921
|
color: ${colors.textSecondary};
|
|
922
|
+
white-space: nowrap;
|
|
923
|
+
overflow: hidden;
|
|
924
|
+
text-overflow: ellipsis;
|
|
333
925
|
}
|
|
334
926
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
border-
|
|
339
|
-
background: ${primaryColor};
|
|
340
|
-
color: white;
|
|
341
|
-
border: none;
|
|
342
|
-
cursor: pointer;
|
|
343
|
-
display: flex;
|
|
344
|
-
align-items: center;
|
|
345
|
-
justify-content: center;
|
|
346
|
-
transition: opacity 0.2s;
|
|
927
|
+
/* Reply quote in visitor message bubble needs higher contrast */
|
|
928
|
+
.pp-message-visitor .pp-reply-quote {
|
|
929
|
+
background: rgba(255, 255, 255, 0.18);
|
|
930
|
+
border-left-color: rgba(255, 255, 255, 0.7);
|
|
347
931
|
}
|
|
348
932
|
|
|
349
|
-
.pp-
|
|
350
|
-
|
|
351
|
-
|
|
933
|
+
.pp-message-visitor .pp-reply-sender,
|
|
934
|
+
.pp-message-visitor .pp-reply-content {
|
|
935
|
+
color: rgba(255, 255, 255, 0.9);
|
|
352
936
|
}
|
|
353
937
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
938
|
+
/* Deleted Message */
|
|
939
|
+
.pp-message-deleted {
|
|
940
|
+
opacity: 0.6;
|
|
357
941
|
}
|
|
358
942
|
|
|
359
|
-
.pp-
|
|
360
|
-
|
|
361
|
-
padding: 8px;
|
|
362
|
-
font-size: 11px;
|
|
943
|
+
.pp-deleted-content {
|
|
944
|
+
font-style: italic;
|
|
363
945
|
color: ${colors.textSecondary};
|
|
364
|
-
|
|
946
|
+
display: flex;
|
|
947
|
+
align-items: center;
|
|
948
|
+
gap: 4px;
|
|
365
949
|
}
|
|
366
950
|
|
|
367
|
-
.pp-
|
|
368
|
-
|
|
369
|
-
text-decoration: none;
|
|
951
|
+
.pp-deleted-icon {
|
|
952
|
+
font-size: 12px;
|
|
370
953
|
}
|
|
371
954
|
|
|
372
|
-
|
|
373
|
-
|
|
955
|
+
/* Edited Badge */
|
|
956
|
+
.pp-edited-badge {
|
|
957
|
+
font-size: 10px;
|
|
958
|
+
color: ${colors.textSecondary};
|
|
959
|
+
margin-left: 4px;
|
|
960
|
+
font-style: italic;
|
|
374
961
|
}
|
|
375
962
|
`;
|
|
376
963
|
}
|
|
@@ -385,9 +972,20 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
385
972
|
const [operatorOnline, setOperatorOnline] = useState(false);
|
|
386
973
|
const [isConnected, setIsConnected] = useState(false);
|
|
387
974
|
const [unreadCount, setUnreadCount] = useState(0);
|
|
975
|
+
const [pendingAttachments, setPendingAttachments] = useState([]);
|
|
976
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
977
|
+
const [replyingTo, setReplyingTo] = useState(null);
|
|
978
|
+
const [editingMessage, setEditingMessage] = useState(null);
|
|
979
|
+
const [editContent, setEditContent] = useState("");
|
|
980
|
+
const [messageMenu, setMessageMenu] = useState(null);
|
|
981
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
982
|
+
const [hoveredMessageId, setHoveredMessageId] = useState(null);
|
|
983
|
+
const [longPressTimer, setLongPressTimer] = useState(null);
|
|
388
984
|
const [config, setConfig] = useState(initialConfig);
|
|
389
985
|
const messagesEndRef = useRef(null);
|
|
390
986
|
const inputRef = useRef(null);
|
|
987
|
+
const fileInputRef = useRef(null);
|
|
988
|
+
const messagesContainerRef = useRef(null);
|
|
391
989
|
useEffect(() => {
|
|
392
990
|
const unsubOpen = client2.on("openChange", setIsOpen);
|
|
393
991
|
const unsubMessage = client2.on("message", () => {
|
|
@@ -484,11 +1082,17 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
484
1082
|
if (!shouldShow) return null;
|
|
485
1083
|
const handleSubmit = async (e) => {
|
|
486
1084
|
e.preventDefault();
|
|
487
|
-
|
|
1085
|
+
const hasContent = inputValue.trim().length > 0;
|
|
1086
|
+
const readyAttachments = pendingAttachments.filter((a) => a.status === "ready" && a.attachment);
|
|
1087
|
+
if (!hasContent && readyAttachments.length === 0) return;
|
|
488
1088
|
const content = inputValue;
|
|
1089
|
+
const attachmentIds = readyAttachments.map((a) => a.attachment.id);
|
|
1090
|
+
const replyToId = replyingTo?.id;
|
|
489
1091
|
setInputValue("");
|
|
1092
|
+
setPendingAttachments([]);
|
|
1093
|
+
setReplyingTo(null);
|
|
490
1094
|
try {
|
|
491
|
-
await client2.sendMessage(content);
|
|
1095
|
+
await client2.sendMessage(content, attachmentIds, replyToId);
|
|
492
1096
|
} catch (err) {
|
|
493
1097
|
console.error("[PocketPing] Failed to send message:", err);
|
|
494
1098
|
}
|
|
@@ -498,9 +1102,213 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
498
1102
|
setInputValue(target.value);
|
|
499
1103
|
client2.sendTyping(true);
|
|
500
1104
|
};
|
|
1105
|
+
const handleFileSelect = async (e) => {
|
|
1106
|
+
const target = e.target;
|
|
1107
|
+
const files = target.files;
|
|
1108
|
+
if (!files || files.length === 0) return;
|
|
1109
|
+
const newPending = [];
|
|
1110
|
+
for (let i = 0; i < files.length; i++) {
|
|
1111
|
+
const file = files[i];
|
|
1112
|
+
const id = `pending-${Date.now()}-${i}`;
|
|
1113
|
+
let preview;
|
|
1114
|
+
if (file.type.startsWith("image/")) {
|
|
1115
|
+
preview = URL.createObjectURL(file);
|
|
1116
|
+
}
|
|
1117
|
+
newPending.push({
|
|
1118
|
+
id,
|
|
1119
|
+
file,
|
|
1120
|
+
preview,
|
|
1121
|
+
progress: 0,
|
|
1122
|
+
status: "pending"
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
setPendingAttachments((prev) => [...prev, ...newPending]);
|
|
1126
|
+
target.value = "";
|
|
1127
|
+
setIsUploading(true);
|
|
1128
|
+
for (const pending of newPending) {
|
|
1129
|
+
try {
|
|
1130
|
+
setPendingAttachments(
|
|
1131
|
+
(prev) => prev.map((a) => a.id === pending.id ? { ...a, status: "uploading" } : a)
|
|
1132
|
+
);
|
|
1133
|
+
const attachment = await client2.uploadFile(pending.file, (progress) => {
|
|
1134
|
+
setPendingAttachments(
|
|
1135
|
+
(prev) => prev.map((a) => a.id === pending.id ? { ...a, progress } : a)
|
|
1136
|
+
);
|
|
1137
|
+
});
|
|
1138
|
+
setPendingAttachments(
|
|
1139
|
+
(prev) => prev.map(
|
|
1140
|
+
(a) => a.id === pending.id ? { ...a, status: "ready", progress: 100, attachment } : a
|
|
1141
|
+
)
|
|
1142
|
+
);
|
|
1143
|
+
} catch (err) {
|
|
1144
|
+
console.error("[PocketPing] Failed to upload file:", err);
|
|
1145
|
+
setPendingAttachments(
|
|
1146
|
+
(prev) => prev.map(
|
|
1147
|
+
(a) => a.id === pending.id ? { ...a, status: "error", error: "Upload failed" } : a
|
|
1148
|
+
)
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
setIsUploading(false);
|
|
1153
|
+
};
|
|
1154
|
+
const handleRemoveAttachment = (id) => {
|
|
1155
|
+
setPendingAttachments((prev) => {
|
|
1156
|
+
const removed = prev.find((a) => a.id === id);
|
|
1157
|
+
if (removed?.preview) {
|
|
1158
|
+
URL.revokeObjectURL(removed.preview);
|
|
1159
|
+
}
|
|
1160
|
+
return prev.filter((a) => a.id !== id);
|
|
1161
|
+
});
|
|
1162
|
+
};
|
|
1163
|
+
const handleReply = (message) => {
|
|
1164
|
+
setReplyingTo(message);
|
|
1165
|
+
setMessageMenu(null);
|
|
1166
|
+
inputRef.current?.focus();
|
|
1167
|
+
};
|
|
1168
|
+
const handleCancelReply = () => {
|
|
1169
|
+
setReplyingTo(null);
|
|
1170
|
+
};
|
|
1171
|
+
const handleStartEdit = (message) => {
|
|
1172
|
+
if (message.sender !== "visitor") return;
|
|
1173
|
+
setEditingMessage(message);
|
|
1174
|
+
setEditContent(message.content);
|
|
1175
|
+
setMessageMenu(null);
|
|
1176
|
+
};
|
|
1177
|
+
const handleCancelEdit = () => {
|
|
1178
|
+
setEditingMessage(null);
|
|
1179
|
+
setEditContent("");
|
|
1180
|
+
};
|
|
1181
|
+
const handleSaveEdit = async () => {
|
|
1182
|
+
if (!editingMessage || !editContent.trim()) return;
|
|
1183
|
+
try {
|
|
1184
|
+
await client2.editMessage(editingMessage.id, editContent.trim());
|
|
1185
|
+
setEditingMessage(null);
|
|
1186
|
+
setEditContent("");
|
|
1187
|
+
} catch (err) {
|
|
1188
|
+
console.error("[PocketPing] Failed to edit message:", err);
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
const handleDelete = async (message) => {
|
|
1192
|
+
if (message.sender !== "visitor") return;
|
|
1193
|
+
setMessageMenu(null);
|
|
1194
|
+
if (confirm("Delete this message?")) {
|
|
1195
|
+
try {
|
|
1196
|
+
await client2.deleteMessage(message.id);
|
|
1197
|
+
} catch (err) {
|
|
1198
|
+
console.error("[PocketPing] Failed to delete message:", err);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
const handleMessageContextMenu = (e, message) => {
|
|
1203
|
+
e.preventDefault();
|
|
1204
|
+
const mouseEvent = e;
|
|
1205
|
+
setMessageMenu({
|
|
1206
|
+
message,
|
|
1207
|
+
x: mouseEvent.clientX,
|
|
1208
|
+
y: mouseEvent.clientY
|
|
1209
|
+
});
|
|
1210
|
+
};
|
|
1211
|
+
const handleTouchStart = (message) => {
|
|
1212
|
+
const timer = setTimeout(() => {
|
|
1213
|
+
if (navigator.vibrate) navigator.vibrate(50);
|
|
1214
|
+
setMessageMenu({
|
|
1215
|
+
message,
|
|
1216
|
+
x: window.innerWidth / 2 - 60,
|
|
1217
|
+
// Center horizontally
|
|
1218
|
+
y: window.innerHeight / 2 - 50
|
|
1219
|
+
// Center vertically
|
|
1220
|
+
});
|
|
1221
|
+
}, 500);
|
|
1222
|
+
setLongPressTimer(timer);
|
|
1223
|
+
};
|
|
1224
|
+
const handleTouchEnd = () => {
|
|
1225
|
+
if (longPressTimer) {
|
|
1226
|
+
clearTimeout(longPressTimer);
|
|
1227
|
+
setLongPressTimer(null);
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
useEffect(() => {
|
|
1231
|
+
if (!messageMenu) return;
|
|
1232
|
+
const handleClickOutside = () => setMessageMenu(null);
|
|
1233
|
+
document.addEventListener("click", handleClickOutside);
|
|
1234
|
+
return () => document.removeEventListener("click", handleClickOutside);
|
|
1235
|
+
}, [messageMenu]);
|
|
1236
|
+
const dragCounterRef = useRef(0);
|
|
1237
|
+
const handleDragEnter = (e) => {
|
|
1238
|
+
e.preventDefault();
|
|
1239
|
+
e.stopPropagation();
|
|
1240
|
+
dragCounterRef.current++;
|
|
1241
|
+
if (dragCounterRef.current === 1) {
|
|
1242
|
+
setIsDragging(true);
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
const handleDragOver = (e) => {
|
|
1246
|
+
e.preventDefault();
|
|
1247
|
+
e.stopPropagation();
|
|
1248
|
+
};
|
|
1249
|
+
const handleDragLeave = (e) => {
|
|
1250
|
+
e.preventDefault();
|
|
1251
|
+
e.stopPropagation();
|
|
1252
|
+
dragCounterRef.current--;
|
|
1253
|
+
if (dragCounterRef.current === 0) {
|
|
1254
|
+
setIsDragging(false);
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
const handleDrop = async (e) => {
|
|
1258
|
+
e.preventDefault();
|
|
1259
|
+
e.stopPropagation();
|
|
1260
|
+
dragCounterRef.current = 0;
|
|
1261
|
+
setIsDragging(false);
|
|
1262
|
+
const files = e.dataTransfer?.files;
|
|
1263
|
+
if (!files || files.length === 0) return;
|
|
1264
|
+
const newPending = [];
|
|
1265
|
+
for (let i = 0; i < files.length; i++) {
|
|
1266
|
+
const file = files[i];
|
|
1267
|
+
const id = `pending-${Date.now()}-${i}`;
|
|
1268
|
+
let preview;
|
|
1269
|
+
if (file.type.startsWith("image/")) {
|
|
1270
|
+
preview = URL.createObjectURL(file);
|
|
1271
|
+
}
|
|
1272
|
+
newPending.push({
|
|
1273
|
+
id,
|
|
1274
|
+
file,
|
|
1275
|
+
preview,
|
|
1276
|
+
progress: 0,
|
|
1277
|
+
status: "pending"
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
setPendingAttachments((prev) => [...prev, ...newPending]);
|
|
1281
|
+
setIsUploading(true);
|
|
1282
|
+
for (const pending of newPending) {
|
|
1283
|
+
try {
|
|
1284
|
+
setPendingAttachments(
|
|
1285
|
+
(prev) => prev.map((a) => a.id === pending.id ? { ...a, status: "uploading" } : a)
|
|
1286
|
+
);
|
|
1287
|
+
const attachment = await client2.uploadFile(pending.file, (progress) => {
|
|
1288
|
+
setPendingAttachments(
|
|
1289
|
+
(prev) => prev.map((a) => a.id === pending.id ? { ...a, progress } : a)
|
|
1290
|
+
);
|
|
1291
|
+
});
|
|
1292
|
+
setPendingAttachments(
|
|
1293
|
+
(prev) => prev.map(
|
|
1294
|
+
(a) => a.id === pending.id ? { ...a, status: "ready", progress: 100, attachment } : a
|
|
1295
|
+
)
|
|
1296
|
+
);
|
|
1297
|
+
} catch (err) {
|
|
1298
|
+
console.error("[PocketPing] Failed to upload dropped file:", err);
|
|
1299
|
+
setPendingAttachments(
|
|
1300
|
+
(prev) => prev.map(
|
|
1301
|
+
(a) => a.id === pending.id ? { ...a, status: "error", error: "Upload failed" } : a
|
|
1302
|
+
)
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
setIsUploading(false);
|
|
1307
|
+
};
|
|
501
1308
|
const position = config.position ?? "bottom-right";
|
|
502
1309
|
const theme = getTheme(config.theme ?? "auto");
|
|
503
1310
|
const primaryColor = config.primaryColor ?? "#6366f1";
|
|
1311
|
+
const actionIconColor = theme === "dark" ? "#9ca3af" : "#6b7280";
|
|
504
1312
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
505
1313
|
/* @__PURE__ */ jsx("style", { children: styles(primaryColor, theme) }),
|
|
506
1314
|
/* @__PURE__ */ jsxs(
|
|
@@ -516,84 +1324,263 @@ function ChatWidget({ client: client2, config: initialConfig }) {
|
|
|
516
1324
|
]
|
|
517
1325
|
}
|
|
518
1326
|
),
|
|
519
|
-
isOpen && /* @__PURE__ */ jsxs(
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
/* @__PURE__ */ jsxs("div", { class: "pp-messages", children: [
|
|
545
|
-
config.welcomeMessage && messages.length === 0 && /* @__PURE__ */ jsx("div", { class: "pp-welcome", children: config.welcomeMessage }),
|
|
546
|
-
messages.map((msg) => /* @__PURE__ */ jsxs(
|
|
547
|
-
"div",
|
|
548
|
-
{
|
|
549
|
-
class: `pp-message pp-message-${msg.sender}`,
|
|
550
|
-
children: [
|
|
551
|
-
/* @__PURE__ */ jsx("div", { class: "pp-message-content", children: msg.content }),
|
|
552
|
-
/* @__PURE__ */ jsxs("div", { class: "pp-message-time", children: [
|
|
553
|
-
formatTime(msg.timestamp),
|
|
554
|
-
msg.sender === "ai" && /* @__PURE__ */ jsx("span", { class: "pp-ai-badge", children: "AI" }),
|
|
555
|
-
msg.sender === "visitor" && /* @__PURE__ */ jsx("span", { class: `pp-status pp-status-${msg.status ?? "sent"}`, children: /* @__PURE__ */ jsx(StatusIcon, { status: msg.status }) })
|
|
1327
|
+
isOpen && /* @__PURE__ */ jsxs(
|
|
1328
|
+
"div",
|
|
1329
|
+
{
|
|
1330
|
+
class: `pp-window pp-${position} pp-theme-${theme} ${isDragging ? "pp-dragging" : ""}`,
|
|
1331
|
+
onDragEnter: handleDragEnter,
|
|
1332
|
+
onDragOver: handleDragOver,
|
|
1333
|
+
onDragLeave: handleDragLeave,
|
|
1334
|
+
onDrop: handleDrop,
|
|
1335
|
+
children: [
|
|
1336
|
+
isDragging && /* @__PURE__ */ jsxs("div", { class: "pp-drop-overlay", children: [
|
|
1337
|
+
/* @__PURE__ */ jsx("div", { class: "pp-drop-icon", children: /* @__PURE__ */ jsx(AttachIcon, {}) }),
|
|
1338
|
+
/* @__PURE__ */ jsx("div", { class: "pp-drop-text", children: "Drop files to upload" })
|
|
1339
|
+
] }),
|
|
1340
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-header", children: [
|
|
1341
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-header-info", children: [
|
|
1342
|
+
config.operatorAvatar && /* @__PURE__ */ jsx("img", { src: config.operatorAvatar, alt: "", class: "pp-avatar" }),
|
|
1343
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1344
|
+
/* @__PURE__ */ jsx("div", { class: "pp-header-title", children: config.operatorName ?? "Support" }),
|
|
1345
|
+
/* @__PURE__ */ jsx("div", { class: "pp-header-status", children: operatorOnline ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1346
|
+
/* @__PURE__ */ jsx("span", { class: "pp-status-dot pp-online" }),
|
|
1347
|
+
" Online"
|
|
1348
|
+
] }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1349
|
+
/* @__PURE__ */ jsx("span", { class: "pp-status-dot" }),
|
|
1350
|
+
" Away"
|
|
1351
|
+
] }) })
|
|
556
1352
|
] })
|
|
557
|
-
]
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
1353
|
+
] }),
|
|
1354
|
+
/* @__PURE__ */ jsx(
|
|
1355
|
+
"button",
|
|
1356
|
+
{
|
|
1357
|
+
class: "pp-close-btn",
|
|
1358
|
+
onClick: () => client2.setOpen(false),
|
|
1359
|
+
"aria-label": "Close chat",
|
|
1360
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
1361
|
+
}
|
|
1362
|
+
)
|
|
1363
|
+
] }),
|
|
1364
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-messages", ref: messagesContainerRef, children: [
|
|
1365
|
+
config.welcomeMessage && messages.length === 0 && /* @__PURE__ */ jsx("div", { class: "pp-welcome", children: config.welcomeMessage }),
|
|
1366
|
+
messages.map((msg) => {
|
|
1367
|
+
const isDeleted = !!msg.deletedAt;
|
|
1368
|
+
const isEdited = !!msg.editedAt;
|
|
1369
|
+
let replyData = null;
|
|
1370
|
+
if (msg.replyTo) {
|
|
1371
|
+
if (typeof msg.replyTo === "object") {
|
|
1372
|
+
replyData = msg.replyTo;
|
|
1373
|
+
} else {
|
|
1374
|
+
const replyToMsg = messages.find((m) => m.id === msg.replyTo);
|
|
1375
|
+
if (replyToMsg) {
|
|
1376
|
+
replyData = {
|
|
1377
|
+
sender: replyToMsg.sender,
|
|
1378
|
+
content: replyToMsg.content,
|
|
1379
|
+
deleted: !!replyToMsg.deletedAt
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
const isHovered = hoveredMessageId === msg.id;
|
|
1385
|
+
const showActions = isHovered && !isDeleted;
|
|
1386
|
+
return /* @__PURE__ */ jsxs(
|
|
1387
|
+
"div",
|
|
1388
|
+
{
|
|
1389
|
+
class: `pp-message pp-message-${msg.sender} ${isDeleted ? "pp-message-deleted" : ""}`,
|
|
1390
|
+
onContextMenu: (e) => handleMessageContextMenu(e, msg),
|
|
1391
|
+
onMouseEnter: () => setHoveredMessageId(msg.id),
|
|
1392
|
+
onMouseLeave: () => setHoveredMessageId(null),
|
|
1393
|
+
onTouchStart: () => handleTouchStart(msg),
|
|
1394
|
+
onTouchEnd: handleTouchEnd,
|
|
1395
|
+
onTouchCancel: handleTouchEnd,
|
|
1396
|
+
children: [
|
|
1397
|
+
showActions && /* @__PURE__ */ jsxs("div", { class: `pp-message-actions ${msg.sender === "visitor" ? "pp-actions-left" : "pp-actions-right"}`, children: [
|
|
1398
|
+
/* @__PURE__ */ jsx(
|
|
1399
|
+
"button",
|
|
1400
|
+
{
|
|
1401
|
+
class: "pp-action-btn",
|
|
1402
|
+
onClick: () => handleReply(msg),
|
|
1403
|
+
title: "Reply",
|
|
1404
|
+
children: /* @__PURE__ */ jsx(ReplyIcon, { color: actionIconColor })
|
|
1405
|
+
}
|
|
1406
|
+
),
|
|
1407
|
+
msg.sender === "visitor" && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1408
|
+
/* @__PURE__ */ jsx(
|
|
1409
|
+
"button",
|
|
1410
|
+
{
|
|
1411
|
+
class: "pp-action-btn",
|
|
1412
|
+
onClick: () => handleStartEdit(msg),
|
|
1413
|
+
title: "Edit",
|
|
1414
|
+
children: /* @__PURE__ */ jsx(EditIcon, { color: actionIconColor })
|
|
1415
|
+
}
|
|
1416
|
+
),
|
|
1417
|
+
/* @__PURE__ */ jsx(
|
|
1418
|
+
"button",
|
|
1419
|
+
{
|
|
1420
|
+
class: "pp-action-btn pp-action-delete",
|
|
1421
|
+
onClick: () => handleDelete(msg),
|
|
1422
|
+
title: "Delete",
|
|
1423
|
+
children: /* @__PURE__ */ jsx(DeleteIcon, { color: actionIconColor })
|
|
1424
|
+
}
|
|
1425
|
+
)
|
|
1426
|
+
] })
|
|
1427
|
+
] }),
|
|
1428
|
+
replyData && replyData.content && /* @__PURE__ */ jsxs("div", { class: "pp-reply-quote", children: [
|
|
1429
|
+
/* @__PURE__ */ jsx("span", { class: "pp-reply-sender", children: replyData.sender === "visitor" ? "You" : "Support" }),
|
|
1430
|
+
/* @__PURE__ */ jsxs("span", { class: "pp-reply-content", children: [
|
|
1431
|
+
replyData.deleted ? "Message deleted" : (replyData.content || "").slice(0, 50),
|
|
1432
|
+
(replyData.content || "").length > 50 ? "..." : ""
|
|
1433
|
+
] })
|
|
1434
|
+
] }),
|
|
1435
|
+
isDeleted ? /* @__PURE__ */ jsxs("div", { class: "pp-message-content pp-deleted-content", children: [
|
|
1436
|
+
/* @__PURE__ */ jsx("span", { class: "pp-deleted-icon", children: "\u{1F5D1}\uFE0F" }),
|
|
1437
|
+
" Message deleted"
|
|
1438
|
+
] }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1439
|
+
msg.content && /* @__PURE__ */ jsx("div", { class: "pp-message-content", children: msg.content }),
|
|
1440
|
+
msg.attachments && msg.attachments.length > 0 && /* @__PURE__ */ jsx("div", { class: "pp-message-attachments", children: msg.attachments.map((att) => /* @__PURE__ */ jsx(AttachmentDisplay, { attachment: att }, att.id)) })
|
|
1441
|
+
] }),
|
|
1442
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-message-time", children: [
|
|
1443
|
+
formatTime(msg.timestamp),
|
|
1444
|
+
isEdited && !isDeleted && /* @__PURE__ */ jsx("span", { class: "pp-edited-badge", children: "edited" }),
|
|
1445
|
+
msg.sender === "ai" && /* @__PURE__ */ jsx("span", { class: "pp-ai-badge", children: "AI" }),
|
|
1446
|
+
msg.sender === "visitor" && !isDeleted && /* @__PURE__ */ jsx("span", { class: `pp-status pp-status-${msg.status ?? "sent"}`, children: /* @__PURE__ */ jsx(StatusIcon, { status: msg.status }) })
|
|
1447
|
+
] })
|
|
1448
|
+
]
|
|
1449
|
+
},
|
|
1450
|
+
msg.id
|
|
1451
|
+
);
|
|
1452
|
+
}),
|
|
1453
|
+
isTyping && /* @__PURE__ */ jsxs("div", { class: "pp-message pp-message-operator pp-typing", children: [
|
|
1454
|
+
/* @__PURE__ */ jsx("span", {}),
|
|
1455
|
+
/* @__PURE__ */ jsx("span", {}),
|
|
1456
|
+
/* @__PURE__ */ jsx("span", {})
|
|
1457
|
+
] }),
|
|
1458
|
+
/* @__PURE__ */ jsx("div", { ref: messagesEndRef })
|
|
1459
|
+
] }),
|
|
1460
|
+
messageMenu && /* @__PURE__ */ jsxs(
|
|
1461
|
+
"div",
|
|
1462
|
+
{
|
|
1463
|
+
class: "pp-message-menu",
|
|
1464
|
+
style: { top: `${messageMenu.y}px`, left: `${messageMenu.x}px` },
|
|
1465
|
+
children: [
|
|
1466
|
+
/* @__PURE__ */ jsxs("button", { onClick: () => handleReply(messageMenu.message), children: [
|
|
1467
|
+
/* @__PURE__ */ jsx(ReplyIcon, { color: actionIconColor }),
|
|
1468
|
+
" Reply"
|
|
1469
|
+
] }),
|
|
1470
|
+
messageMenu.message.sender === "visitor" && !messageMenu.message.deletedAt && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1471
|
+
/* @__PURE__ */ jsxs("button", { onClick: () => handleStartEdit(messageMenu.message), children: [
|
|
1472
|
+
/* @__PURE__ */ jsx(EditIcon, { color: actionIconColor }),
|
|
1473
|
+
" Edit"
|
|
1474
|
+
] }),
|
|
1475
|
+
/* @__PURE__ */ jsxs("button", { class: "pp-menu-delete", onClick: () => handleDelete(messageMenu.message), children: [
|
|
1476
|
+
/* @__PURE__ */ jsx(DeleteIcon, { color: "#ef4444" }),
|
|
1477
|
+
" Delete"
|
|
1478
|
+
] })
|
|
1479
|
+
] })
|
|
1480
|
+
]
|
|
1481
|
+
}
|
|
1482
|
+
),
|
|
1483
|
+
editingMessage && /* @__PURE__ */ jsxs("div", { class: "pp-edit-modal", children: [
|
|
1484
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-edit-header", children: [
|
|
1485
|
+
/* @__PURE__ */ jsx("span", { children: "Edit message" }),
|
|
1486
|
+
/* @__PURE__ */ jsx("button", { onClick: handleCancelEdit, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
1487
|
+
] }),
|
|
1488
|
+
/* @__PURE__ */ jsx(
|
|
1489
|
+
"textarea",
|
|
1490
|
+
{
|
|
1491
|
+
class: "pp-edit-input",
|
|
1492
|
+
value: editContent,
|
|
1493
|
+
onInput: (e) => setEditContent(e.target.value),
|
|
1494
|
+
autoFocus: true
|
|
1495
|
+
}
|
|
1496
|
+
),
|
|
1497
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-edit-actions", children: [
|
|
1498
|
+
/* @__PURE__ */ jsx("button", { class: "pp-edit-cancel", onClick: handleCancelEdit, children: "Cancel" }),
|
|
1499
|
+
/* @__PURE__ */ jsx("button", { class: "pp-edit-save", onClick: handleSaveEdit, disabled: !editContent.trim(), children: "Save" })
|
|
1500
|
+
] })
|
|
1501
|
+
] }),
|
|
1502
|
+
replyingTo && /* @__PURE__ */ jsxs("div", { class: "pp-reply-preview", children: [
|
|
1503
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-reply-preview-content", children: [
|
|
1504
|
+
/* @__PURE__ */ jsx("span", { class: "pp-reply-label", children: "Replying to" }),
|
|
1505
|
+
/* @__PURE__ */ jsxs("span", { class: "pp-reply-text", children: [
|
|
1506
|
+
replyingTo.content.slice(0, 50),
|
|
1507
|
+
replyingTo.content.length > 50 ? "..." : ""
|
|
1508
|
+
] })
|
|
1509
|
+
] }),
|
|
1510
|
+
/* @__PURE__ */ jsx("button", { class: "pp-reply-cancel", onClick: handleCancelReply, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
1511
|
+
] }),
|
|
1512
|
+
pendingAttachments.length > 0 && /* @__PURE__ */ jsx("div", { class: "pp-attachments-preview", children: pendingAttachments.map((pending) => /* @__PURE__ */ jsxs("div", { class: `pp-attachment-preview pp-attachment-${pending.status}`, children: [
|
|
1513
|
+
pending.preview ? /* @__PURE__ */ jsx("img", { src: pending.preview, alt: pending.file.name, class: "pp-preview-img" }) : /* @__PURE__ */ jsx("div", { class: "pp-preview-file", children: /* @__PURE__ */ jsx(FileIcon, { mimeType: pending.file.type }) }),
|
|
1514
|
+
/* @__PURE__ */ jsx(
|
|
1515
|
+
"button",
|
|
1516
|
+
{
|
|
1517
|
+
class: "pp-remove-attachment",
|
|
1518
|
+
onClick: () => handleRemoveAttachment(pending.id),
|
|
1519
|
+
"aria-label": "Remove attachment",
|
|
1520
|
+
type: "button",
|
|
1521
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
1522
|
+
}
|
|
1523
|
+
),
|
|
1524
|
+
pending.status === "uploading" && /* @__PURE__ */ jsx("div", { class: "pp-upload-progress", style: { width: `${pending.progress}%` } }),
|
|
1525
|
+
pending.status === "error" && /* @__PURE__ */ jsx("div", { class: "pp-upload-error", title: pending.error, children: "!" })
|
|
1526
|
+
] }, pending.id)) }),
|
|
1527
|
+
/* @__PURE__ */ jsxs("form", { class: "pp-input-form", onSubmit: handleSubmit, children: [
|
|
1528
|
+
/* @__PURE__ */ jsx(
|
|
1529
|
+
"input",
|
|
1530
|
+
{
|
|
1531
|
+
ref: (el) => {
|
|
1532
|
+
fileInputRef.current = el;
|
|
1533
|
+
if (el) {
|
|
1534
|
+
el.onchange = handleFileSelect;
|
|
1535
|
+
}
|
|
1536
|
+
},
|
|
1537
|
+
type: "file",
|
|
1538
|
+
class: "pp-file-input",
|
|
1539
|
+
accept: "image/*,audio/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.txt",
|
|
1540
|
+
multiple: true
|
|
1541
|
+
}
|
|
1542
|
+
),
|
|
1543
|
+
/* @__PURE__ */ jsx(
|
|
1544
|
+
"button",
|
|
1545
|
+
{
|
|
1546
|
+
type: "button",
|
|
1547
|
+
class: "pp-attach-btn",
|
|
1548
|
+
onClick: () => fileInputRef.current?.click(),
|
|
1549
|
+
disabled: !isConnected || isUploading,
|
|
1550
|
+
"aria-label": "Attach file",
|
|
1551
|
+
children: /* @__PURE__ */ jsx(AttachIcon, {})
|
|
1552
|
+
}
|
|
1553
|
+
),
|
|
1554
|
+
/* @__PURE__ */ jsx(
|
|
1555
|
+
"input",
|
|
1556
|
+
{
|
|
1557
|
+
ref: inputRef,
|
|
1558
|
+
type: "text",
|
|
1559
|
+
class: "pp-input",
|
|
1560
|
+
placeholder: config.placeholder ?? "Type a message...",
|
|
1561
|
+
value: inputValue,
|
|
1562
|
+
onInput: handleInputChange,
|
|
1563
|
+
disabled: !isConnected
|
|
1564
|
+
}
|
|
1565
|
+
),
|
|
1566
|
+
/* @__PURE__ */ jsx(
|
|
1567
|
+
"button",
|
|
1568
|
+
{
|
|
1569
|
+
type: "submit",
|
|
1570
|
+
class: "pp-send-btn",
|
|
1571
|
+
disabled: !inputValue.trim() && pendingAttachments.filter((a) => a.status === "ready").length === 0 || !isConnected || isUploading,
|
|
1572
|
+
"aria-label": "Send message",
|
|
1573
|
+
children: /* @__PURE__ */ jsx(SendIcon, {})
|
|
1574
|
+
}
|
|
1575
|
+
)
|
|
1576
|
+
] }),
|
|
1577
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-footer", children: [
|
|
1578
|
+
"Powered by ",
|
|
1579
|
+
/* @__PURE__ */ jsx("a", { href: "https://pocketping.io", target: "_blank", rel: "noopener", children: "PocketPing" })
|
|
1580
|
+
] })
|
|
1581
|
+
]
|
|
1582
|
+
}
|
|
1583
|
+
)
|
|
597
1584
|
] });
|
|
598
1585
|
}
|
|
599
1586
|
function checkPageVisibility(config) {
|
|
@@ -649,6 +1636,89 @@ function StatusIcon({ status }) {
|
|
|
649
1636
|
}
|
|
650
1637
|
return null;
|
|
651
1638
|
}
|
|
1639
|
+
function AttachIcon() {
|
|
1640
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: /* @__PURE__ */ 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" }) });
|
|
1641
|
+
}
|
|
1642
|
+
function ReplyIcon({ color, size = 16 }) {
|
|
1643
|
+
const strokeColor = color || "currentColor";
|
|
1644
|
+
return /* @__PURE__ */ 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: [
|
|
1645
|
+
/* @__PURE__ */ jsx("polyline", { points: "9 17 4 12 9 7" }),
|
|
1646
|
+
/* @__PURE__ */ jsx("path", { d: "M20 18v-2a4 4 0 0 0-4-4H4" })
|
|
1647
|
+
] });
|
|
1648
|
+
}
|
|
1649
|
+
function EditIcon({ color, size = 16 }) {
|
|
1650
|
+
const strokeColor = color || "currentColor";
|
|
1651
|
+
return /* @__PURE__ */ 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__ */ jsx("path", { d: "M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" }) });
|
|
1652
|
+
}
|
|
1653
|
+
function DeleteIcon({ color, size = 16 }) {
|
|
1654
|
+
const strokeColor = color || "currentColor";
|
|
1655
|
+
return /* @__PURE__ */ 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: [
|
|
1656
|
+
/* @__PURE__ */ jsx("polyline", { points: "3 6 5 6 21 6" }),
|
|
1657
|
+
/* @__PURE__ */ 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" })
|
|
1658
|
+
] });
|
|
1659
|
+
}
|
|
1660
|
+
function FileIcon({ mimeType }) {
|
|
1661
|
+
if (mimeType === "application/pdf") {
|
|
1662
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
1663
|
+
/* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
1664
|
+
/* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" }),
|
|
1665
|
+
/* @__PURE__ */ jsx("path", { d: "M9 15h6" }),
|
|
1666
|
+
/* @__PURE__ */ jsx("path", { d: "M9 11h6" })
|
|
1667
|
+
] });
|
|
1668
|
+
}
|
|
1669
|
+
if (mimeType.startsWith("audio/")) {
|
|
1670
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
1671
|
+
/* @__PURE__ */ jsx("path", { d: "M9 18V5l12-2v13" }),
|
|
1672
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "18", r: "3" }),
|
|
1673
|
+
/* @__PURE__ */ jsx("circle", { cx: "18", cy: "16", r: "3" })
|
|
1674
|
+
] });
|
|
1675
|
+
}
|
|
1676
|
+
if (mimeType.startsWith("video/")) {
|
|
1677
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
1678
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "2", width: "20", height: "20", rx: "2.18", ry: "2.18" }),
|
|
1679
|
+
/* @__PURE__ */ jsx("line", { x1: "7", y1: "2", x2: "7", y2: "22" }),
|
|
1680
|
+
/* @__PURE__ */ jsx("line", { x1: "17", y1: "2", x2: "17", y2: "22" }),
|
|
1681
|
+
/* @__PURE__ */ jsx("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
|
|
1682
|
+
/* @__PURE__ */ jsx("line", { x1: "2", y1: "7", x2: "7", y2: "7" }),
|
|
1683
|
+
/* @__PURE__ */ jsx("line", { x1: "2", y1: "17", x2: "7", y2: "17" }),
|
|
1684
|
+
/* @__PURE__ */ jsx("line", { x1: "17", y1: "17", x2: "22", y2: "17" }),
|
|
1685
|
+
/* @__PURE__ */ jsx("line", { x1: "17", y1: "7", x2: "22", y2: "7" })
|
|
1686
|
+
] });
|
|
1687
|
+
}
|
|
1688
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
1689
|
+
/* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
1690
|
+
/* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" })
|
|
1691
|
+
] });
|
|
1692
|
+
}
|
|
1693
|
+
function AttachmentDisplay({ attachment }) {
|
|
1694
|
+
const isImage = attachment.mimeType.startsWith("image/");
|
|
1695
|
+
const isAudio = attachment.mimeType.startsWith("audio/");
|
|
1696
|
+
const isVideo = attachment.mimeType.startsWith("video/");
|
|
1697
|
+
const formatSize = (bytes) => {
|
|
1698
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1699
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1700
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1701
|
+
};
|
|
1702
|
+
if (isImage) {
|
|
1703
|
+
return /* @__PURE__ */ jsx("a", { href: attachment.url, target: "_blank", rel: "noopener", class: "pp-attachment pp-attachment-image", children: /* @__PURE__ */ jsx("img", { src: attachment.thumbnailUrl || attachment.url, alt: attachment.filename }) });
|
|
1704
|
+
}
|
|
1705
|
+
if (isAudio) {
|
|
1706
|
+
return /* @__PURE__ */ jsxs("div", { class: "pp-attachment pp-attachment-audio", children: [
|
|
1707
|
+
/* @__PURE__ */ jsx("audio", { controls: true, preload: "metadata", children: /* @__PURE__ */ jsx("source", { src: attachment.url, type: attachment.mimeType }) }),
|
|
1708
|
+
/* @__PURE__ */ jsx("span", { class: "pp-attachment-name", children: attachment.filename })
|
|
1709
|
+
] });
|
|
1710
|
+
}
|
|
1711
|
+
if (isVideo) {
|
|
1712
|
+
return /* @__PURE__ */ jsx("div", { class: "pp-attachment pp-attachment-video", children: /* @__PURE__ */ jsx("video", { controls: true, preload: "metadata", children: /* @__PURE__ */ jsx("source", { src: attachment.url, type: attachment.mimeType }) }) });
|
|
1713
|
+
}
|
|
1714
|
+
return /* @__PURE__ */ jsxs("a", { href: attachment.url, target: "_blank", rel: "noopener", class: "pp-attachment pp-attachment-file", children: [
|
|
1715
|
+
/* @__PURE__ */ jsx(FileIcon, { mimeType: attachment.mimeType }),
|
|
1716
|
+
/* @__PURE__ */ jsxs("div", { class: "pp-attachment-info", children: [
|
|
1717
|
+
/* @__PURE__ */ jsx("span", { class: "pp-attachment-name", children: attachment.filename }),
|
|
1718
|
+
/* @__PURE__ */ jsx("span", { class: "pp-attachment-size", children: formatSize(attachment.size) })
|
|
1719
|
+
] })
|
|
1720
|
+
] });
|
|
1721
|
+
}
|
|
652
1722
|
|
|
653
1723
|
// src/version.ts
|
|
654
1724
|
var VERSION = "0.3.6";
|
|
@@ -764,7 +1834,7 @@ var PocketPingClient = class {
|
|
|
764
1834
|
this.cleanupTrackedElements();
|
|
765
1835
|
this.disableInspectorMode();
|
|
766
1836
|
}
|
|
767
|
-
async sendMessage(content) {
|
|
1837
|
+
async sendMessage(content, attachmentIds, replyTo) {
|
|
768
1838
|
if (!this.session) {
|
|
769
1839
|
throw new Error("Not connected");
|
|
770
1840
|
}
|
|
@@ -775,7 +1845,8 @@ var PocketPingClient = class {
|
|
|
775
1845
|
content,
|
|
776
1846
|
sender: "visitor",
|
|
777
1847
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
778
|
-
status: "sending"
|
|
1848
|
+
status: "sending",
|
|
1849
|
+
replyTo
|
|
779
1850
|
};
|
|
780
1851
|
this.session.messages.push(tempMessage);
|
|
781
1852
|
this.emit("message", tempMessage);
|
|
@@ -785,7 +1856,9 @@ var PocketPingClient = class {
|
|
|
785
1856
|
body: JSON.stringify({
|
|
786
1857
|
sessionId: this.session.sessionId,
|
|
787
1858
|
content,
|
|
788
|
-
sender: "visitor"
|
|
1859
|
+
sender: "visitor",
|
|
1860
|
+
attachmentIds: attachmentIds || [],
|
|
1861
|
+
replyTo
|
|
789
1862
|
})
|
|
790
1863
|
});
|
|
791
1864
|
const messageIndex = this.session.messages.findIndex((m) => m.id === tempId);
|
|
@@ -793,6 +1866,9 @@ var PocketPingClient = class {
|
|
|
793
1866
|
this.session.messages[messageIndex].id = response.messageId;
|
|
794
1867
|
this.session.messages[messageIndex].timestamp = response.timestamp;
|
|
795
1868
|
this.session.messages[messageIndex].status = "sent";
|
|
1869
|
+
if (response.attachments && response.attachments.length > 0) {
|
|
1870
|
+
this.session.messages[messageIndex].attachments = response.attachments;
|
|
1871
|
+
}
|
|
796
1872
|
this.emit("message", this.session.messages[messageIndex]);
|
|
797
1873
|
}
|
|
798
1874
|
const message = this.session.messages[messageIndex] || {
|
|
@@ -801,7 +1877,8 @@ var PocketPingClient = class {
|
|
|
801
1877
|
content,
|
|
802
1878
|
sender: "visitor",
|
|
803
1879
|
timestamp: response.timestamp,
|
|
804
|
-
status: "sent"
|
|
1880
|
+
status: "sent",
|
|
1881
|
+
attachments: response.attachments
|
|
805
1882
|
};
|
|
806
1883
|
this.config.onMessage?.(message);
|
|
807
1884
|
return message;
|
|
@@ -814,6 +1891,110 @@ var PocketPingClient = class {
|
|
|
814
1891
|
throw error;
|
|
815
1892
|
}
|
|
816
1893
|
}
|
|
1894
|
+
/**
|
|
1895
|
+
* Upload a file attachment
|
|
1896
|
+
* Returns the attachment data after successful upload
|
|
1897
|
+
* @param file - File object to upload
|
|
1898
|
+
* @param onProgress - Optional callback for upload progress (0-100)
|
|
1899
|
+
* @example
|
|
1900
|
+
* const attachment = await PocketPing.uploadFile(file, (progress) => {
|
|
1901
|
+
* console.log(`Upload ${progress}% complete`)
|
|
1902
|
+
* })
|
|
1903
|
+
* await PocketPing.sendMessage('Check this file', [attachment.id])
|
|
1904
|
+
*/
|
|
1905
|
+
async uploadFile(file, onProgress) {
|
|
1906
|
+
if (!this.session) {
|
|
1907
|
+
throw new Error("Not connected");
|
|
1908
|
+
}
|
|
1909
|
+
this.emit("uploadStart", { filename: file.name, size: file.size });
|
|
1910
|
+
try {
|
|
1911
|
+
const initResponse = await this.fetch("/upload", {
|
|
1912
|
+
method: "POST",
|
|
1913
|
+
body: JSON.stringify({
|
|
1914
|
+
sessionId: this.session.sessionId,
|
|
1915
|
+
filename: file.name,
|
|
1916
|
+
mimeType: file.type || "application/octet-stream",
|
|
1917
|
+
size: file.size
|
|
1918
|
+
})
|
|
1919
|
+
});
|
|
1920
|
+
onProgress?.(10);
|
|
1921
|
+
this.emit("uploadProgress", { filename: file.name, progress: 10 });
|
|
1922
|
+
await this.uploadToPresignedUrl(initResponse.uploadUrl, file, (progress) => {
|
|
1923
|
+
const mappedProgress = 10 + progress * 0.8;
|
|
1924
|
+
onProgress?.(mappedProgress);
|
|
1925
|
+
this.emit("uploadProgress", { filename: file.name, progress: mappedProgress });
|
|
1926
|
+
});
|
|
1927
|
+
const completeResponse = await this.fetch("/upload/complete", {
|
|
1928
|
+
method: "POST",
|
|
1929
|
+
body: JSON.stringify({
|
|
1930
|
+
sessionId: this.session.sessionId,
|
|
1931
|
+
attachmentId: initResponse.attachmentId
|
|
1932
|
+
})
|
|
1933
|
+
});
|
|
1934
|
+
onProgress?.(100);
|
|
1935
|
+
this.emit("uploadComplete", completeResponse);
|
|
1936
|
+
return {
|
|
1937
|
+
id: completeResponse.id,
|
|
1938
|
+
filename: completeResponse.filename,
|
|
1939
|
+
mimeType: completeResponse.mimeType,
|
|
1940
|
+
size: completeResponse.size,
|
|
1941
|
+
url: completeResponse.url,
|
|
1942
|
+
thumbnailUrl: completeResponse.thumbnailUrl,
|
|
1943
|
+
status: completeResponse.status
|
|
1944
|
+
};
|
|
1945
|
+
} catch (error) {
|
|
1946
|
+
this.emit("uploadError", { filename: file.name, error });
|
|
1947
|
+
throw error;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Upload multiple files at once
|
|
1952
|
+
* @param files - Array of File objects to upload
|
|
1953
|
+
* @param onProgress - Optional callback for overall progress (0-100)
|
|
1954
|
+
* @returns Array of uploaded attachments
|
|
1955
|
+
*/
|
|
1956
|
+
async uploadFiles(files, onProgress) {
|
|
1957
|
+
const attachments = [];
|
|
1958
|
+
const totalFiles = files.length;
|
|
1959
|
+
for (let i = 0; i < totalFiles; i++) {
|
|
1960
|
+
const file = files[i];
|
|
1961
|
+
const baseProgress = i / totalFiles * 100;
|
|
1962
|
+
const fileProgress = 100 / totalFiles;
|
|
1963
|
+
const attachment = await this.uploadFile(file, (progress) => {
|
|
1964
|
+
const totalProgress = baseProgress + progress / 100 * fileProgress;
|
|
1965
|
+
onProgress?.(totalProgress);
|
|
1966
|
+
});
|
|
1967
|
+
attachments.push(attachment);
|
|
1968
|
+
}
|
|
1969
|
+
return attachments;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Upload file to presigned URL with progress tracking
|
|
1973
|
+
*/
|
|
1974
|
+
uploadToPresignedUrl(url, file, onProgress) {
|
|
1975
|
+
return new Promise((resolve, reject) => {
|
|
1976
|
+
const xhr = new XMLHttpRequest();
|
|
1977
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
1978
|
+
if (event.lengthComputable) {
|
|
1979
|
+
const progress = event.loaded / event.total * 100;
|
|
1980
|
+
onProgress?.(progress);
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
xhr.addEventListener("load", () => {
|
|
1984
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
1985
|
+
resolve();
|
|
1986
|
+
} else {
|
|
1987
|
+
reject(new Error(`Upload failed with status ${xhr.status}`));
|
|
1988
|
+
}
|
|
1989
|
+
});
|
|
1990
|
+
xhr.addEventListener("error", () => {
|
|
1991
|
+
reject(new Error("Upload failed"));
|
|
1992
|
+
});
|
|
1993
|
+
xhr.open("PUT", url);
|
|
1994
|
+
xhr.setRequestHeader("Content-Type", file.type || "application/octet-stream");
|
|
1995
|
+
xhr.send(file);
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
817
1998
|
async fetchMessages(after) {
|
|
818
1999
|
if (!this.session) {
|
|
819
2000
|
throw new Error("Not connected");
|
|
@@ -867,6 +2048,54 @@ var PocketPingClient = class {
|
|
|
867
2048
|
console.error("[PocketPing] Failed to send read status:", err);
|
|
868
2049
|
}
|
|
869
2050
|
}
|
|
2051
|
+
/**
|
|
2052
|
+
* Edit a message (visitor can only edit their own messages)
|
|
2053
|
+
* @param messageId - ID of the message to edit
|
|
2054
|
+
* @param content - New content for the message
|
|
2055
|
+
*/
|
|
2056
|
+
async editMessage(messageId, content) {
|
|
2057
|
+
if (!this.session) {
|
|
2058
|
+
throw new Error("Not connected");
|
|
2059
|
+
}
|
|
2060
|
+
const response = await this.fetch(`/message/${messageId}`, {
|
|
2061
|
+
method: "PATCH",
|
|
2062
|
+
body: JSON.stringify({
|
|
2063
|
+
sessionId: this.session.sessionId,
|
|
2064
|
+
content
|
|
2065
|
+
})
|
|
2066
|
+
});
|
|
2067
|
+
const messageIndex = this.session.messages.findIndex((m) => m.id === messageId);
|
|
2068
|
+
if (messageIndex >= 0) {
|
|
2069
|
+
this.session.messages[messageIndex].content = response.message.content;
|
|
2070
|
+
this.session.messages[messageIndex].editedAt = response.message.editedAt;
|
|
2071
|
+
this.emit("messageEdited", this.session.messages[messageIndex]);
|
|
2072
|
+
}
|
|
2073
|
+
return this.session.messages[messageIndex];
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Delete a message (soft delete - visitor can only delete their own messages)
|
|
2077
|
+
* @param messageId - ID of the message to delete
|
|
2078
|
+
*/
|
|
2079
|
+
async deleteMessage(messageId) {
|
|
2080
|
+
if (!this.session) {
|
|
2081
|
+
throw new Error("Not connected");
|
|
2082
|
+
}
|
|
2083
|
+
const response = await this.fetch(`/message/${messageId}`, {
|
|
2084
|
+
method: "DELETE",
|
|
2085
|
+
body: JSON.stringify({
|
|
2086
|
+
sessionId: this.session.sessionId
|
|
2087
|
+
})
|
|
2088
|
+
});
|
|
2089
|
+
if (response.deleted) {
|
|
2090
|
+
const messageIndex = this.session.messages.findIndex((m) => m.id === messageId);
|
|
2091
|
+
if (messageIndex >= 0) {
|
|
2092
|
+
this.session.messages[messageIndex].deletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2093
|
+
this.session.messages[messageIndex].content = "";
|
|
2094
|
+
this.emit("messageDeleted", this.session.messages[messageIndex]);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
return response.deleted;
|
|
2098
|
+
}
|
|
870
2099
|
async getPresence() {
|
|
871
2100
|
return this.fetch("/presence", { method: "GET" });
|
|
872
2101
|
}
|
|
@@ -1421,7 +2650,14 @@ var PocketPingClient = class {
|
|
|
1421
2650
|
}
|
|
1422
2651
|
connectSSE() {
|
|
1423
2652
|
if (!this.session) return;
|
|
1424
|
-
const
|
|
2653
|
+
const params = new URLSearchParams({
|
|
2654
|
+
sessionId: this.session.sessionId
|
|
2655
|
+
});
|
|
2656
|
+
const lastEventTimestamp = this.getLastEventTimestamp();
|
|
2657
|
+
if (lastEventTimestamp) {
|
|
2658
|
+
params.set("after", lastEventTimestamp);
|
|
2659
|
+
}
|
|
2660
|
+
const sseUrl = this.config.endpoint.replace(/\/$/, "") + `/stream?${params.toString()}`;
|
|
1425
2661
|
try {
|
|
1426
2662
|
this.sse = new EventSource(sseUrl);
|
|
1427
2663
|
const connectionTimeout = setTimeout(() => {
|
|
@@ -1476,6 +2712,19 @@ var PocketPingClient = class {
|
|
|
1476
2712
|
handleRealtimeEvent(event) {
|
|
1477
2713
|
this.handleWebSocketEvent(event);
|
|
1478
2714
|
}
|
|
2715
|
+
getLastEventTimestamp() {
|
|
2716
|
+
if (!this.session) return null;
|
|
2717
|
+
let latest = null;
|
|
2718
|
+
for (const msg of this.session.messages) {
|
|
2719
|
+
const candidates = [msg.timestamp, msg.editedAt, msg.deletedAt, msg.deliveredAt, msg.readAt].filter(Boolean).map((value) => new Date(value)).filter((date) => !isNaN(date.getTime()));
|
|
2720
|
+
for (const date of candidates) {
|
|
2721
|
+
if (!latest || date > latest) {
|
|
2722
|
+
latest = date;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
return latest ? latest.toISOString() : null;
|
|
2727
|
+
}
|
|
1479
2728
|
handleWebSocketEvent(event) {
|
|
1480
2729
|
switch (event.type) {
|
|
1481
2730
|
case "message":
|
|
@@ -1498,12 +2747,41 @@ var PocketPingClient = class {
|
|
|
1498
2747
|
}
|
|
1499
2748
|
if (existingIndex >= 0) {
|
|
1500
2749
|
const existing = this.session.messages[existingIndex];
|
|
2750
|
+
let updated = false;
|
|
1501
2751
|
if (message.status && message.status !== existing.status) {
|
|
1502
2752
|
existing.status = message.status;
|
|
1503
|
-
|
|
1504
|
-
if (message.
|
|
2753
|
+
updated = true;
|
|
2754
|
+
if (message.deliveredAt) {
|
|
2755
|
+
existing.deliveredAt = message.deliveredAt;
|
|
2756
|
+
}
|
|
2757
|
+
if (message.readAt) {
|
|
2758
|
+
existing.readAt = message.readAt;
|
|
2759
|
+
}
|
|
1505
2760
|
this.emit("read", { messageIds: [message.id], status: message.status });
|
|
1506
2761
|
}
|
|
2762
|
+
if (message.content !== void 0 && message.content !== existing.content) {
|
|
2763
|
+
existing.content = message.content;
|
|
2764
|
+
updated = true;
|
|
2765
|
+
}
|
|
2766
|
+
if (message.editedAt !== void 0 && message.editedAt !== existing.editedAt) {
|
|
2767
|
+
existing.editedAt = message.editedAt;
|
|
2768
|
+
updated = true;
|
|
2769
|
+
}
|
|
2770
|
+
if (message.deletedAt !== void 0 && message.deletedAt !== existing.deletedAt) {
|
|
2771
|
+
existing.deletedAt = message.deletedAt;
|
|
2772
|
+
updated = true;
|
|
2773
|
+
}
|
|
2774
|
+
if (message.replyTo !== void 0) {
|
|
2775
|
+
existing.replyTo = message.replyTo;
|
|
2776
|
+
updated = true;
|
|
2777
|
+
}
|
|
2778
|
+
if (message.attachments !== void 0) {
|
|
2779
|
+
existing.attachments = message.attachments;
|
|
2780
|
+
updated = true;
|
|
2781
|
+
}
|
|
2782
|
+
if (updated) {
|
|
2783
|
+
this.emit("message", existing);
|
|
2784
|
+
}
|
|
1507
2785
|
} else {
|
|
1508
2786
|
this.session.messages.push(message);
|
|
1509
2787
|
this.emit("message", message);
|
|
@@ -1542,6 +2820,29 @@ var PocketPingClient = class {
|
|
|
1542
2820
|
}
|
|
1543
2821
|
this.emit("read", readData);
|
|
1544
2822
|
break;
|
|
2823
|
+
case "message_edited":
|
|
2824
|
+
if (this.session) {
|
|
2825
|
+
const editData = event.data;
|
|
2826
|
+
const msgIndex = this.session.messages.findIndex((m) => m.id === editData.messageId);
|
|
2827
|
+
if (msgIndex >= 0) {
|
|
2828
|
+
const existing = this.session.messages[msgIndex];
|
|
2829
|
+
existing.content = editData.content;
|
|
2830
|
+
existing.editedAt = editData.editedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2831
|
+
this.emit("message", existing);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
break;
|
|
2835
|
+
case "message_deleted":
|
|
2836
|
+
if (this.session) {
|
|
2837
|
+
const deleteData = event.data;
|
|
2838
|
+
const msgIndex = this.session.messages.findIndex((m) => m.id === deleteData.messageId);
|
|
2839
|
+
if (msgIndex >= 0) {
|
|
2840
|
+
const existing = this.session.messages[msgIndex];
|
|
2841
|
+
existing.deletedAt = deleteData.deletedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2842
|
+
this.emit("message", existing);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
break;
|
|
1545
2846
|
case "event":
|
|
1546
2847
|
const customEvent = event.data;
|
|
1547
2848
|
this.emitCustomEvent(customEvent);
|
|
@@ -1601,11 +2902,45 @@ var PocketPingClient = class {
|
|
|
1601
2902
|
const poll = async () => {
|
|
1602
2903
|
if (!this.session) return;
|
|
1603
2904
|
try {
|
|
1604
|
-
const
|
|
1605
|
-
const newMessages = await this.fetchMessages(
|
|
2905
|
+
const lastEventTimestamp = this.getLastEventTimestamp();
|
|
2906
|
+
const newMessages = await this.fetchMessages(lastEventTimestamp ?? void 0);
|
|
1606
2907
|
this.pollingFailures = 0;
|
|
1607
2908
|
for (const message of newMessages) {
|
|
1608
|
-
|
|
2909
|
+
const existingIndex = this.session.messages.findIndex((m) => m.id === message.id);
|
|
2910
|
+
if (existingIndex >= 0) {
|
|
2911
|
+
const existing = this.session.messages[existingIndex];
|
|
2912
|
+
let updated = false;
|
|
2913
|
+
if (message.status && message.status !== existing.status) {
|
|
2914
|
+
existing.status = message.status;
|
|
2915
|
+
updated = true;
|
|
2916
|
+
if (message.deliveredAt) existing.deliveredAt = message.deliveredAt;
|
|
2917
|
+
if (message.readAt) existing.readAt = message.readAt;
|
|
2918
|
+
this.emit("read", { messageIds: [message.id], status: message.status });
|
|
2919
|
+
}
|
|
2920
|
+
if (message.content !== void 0 && message.content !== existing.content) {
|
|
2921
|
+
existing.content = message.content;
|
|
2922
|
+
updated = true;
|
|
2923
|
+
}
|
|
2924
|
+
if (message.editedAt !== void 0 && message.editedAt !== existing.editedAt) {
|
|
2925
|
+
existing.editedAt = message.editedAt;
|
|
2926
|
+
updated = true;
|
|
2927
|
+
}
|
|
2928
|
+
if (message.deletedAt !== void 0 && message.deletedAt !== existing.deletedAt) {
|
|
2929
|
+
existing.deletedAt = message.deletedAt;
|
|
2930
|
+
updated = true;
|
|
2931
|
+
}
|
|
2932
|
+
if (message.replyTo !== void 0) {
|
|
2933
|
+
existing.replyTo = message.replyTo;
|
|
2934
|
+
updated = true;
|
|
2935
|
+
}
|
|
2936
|
+
if (message.attachments !== void 0) {
|
|
2937
|
+
existing.attachments = message.attachments;
|
|
2938
|
+
updated = true;
|
|
2939
|
+
}
|
|
2940
|
+
if (updated) {
|
|
2941
|
+
this.emit("message", existing);
|
|
2942
|
+
}
|
|
2943
|
+
} else {
|
|
1609
2944
|
this.session.messages.push(message);
|
|
1610
2945
|
this.emit("message", message);
|
|
1611
2946
|
this.config.onMessage?.(message);
|
|
@@ -1770,11 +3105,23 @@ function close() {
|
|
|
1770
3105
|
function toggle() {
|
|
1771
3106
|
client?.toggleOpen();
|
|
1772
3107
|
}
|
|
1773
|
-
function sendMessage(content) {
|
|
3108
|
+
function sendMessage(content, attachmentIds) {
|
|
3109
|
+
if (!client) {
|
|
3110
|
+
throw new Error("[PocketPing] Not initialized");
|
|
3111
|
+
}
|
|
3112
|
+
return client.sendMessage(content, attachmentIds);
|
|
3113
|
+
}
|
|
3114
|
+
async function uploadFile(file, onProgress) {
|
|
3115
|
+
if (!client) {
|
|
3116
|
+
throw new Error("[PocketPing] Not initialized");
|
|
3117
|
+
}
|
|
3118
|
+
return client.uploadFile(file, onProgress);
|
|
3119
|
+
}
|
|
3120
|
+
async function uploadFiles(files, onProgress) {
|
|
1774
3121
|
if (!client) {
|
|
1775
3122
|
throw new Error("[PocketPing] Not initialized");
|
|
1776
3123
|
}
|
|
1777
|
-
return client.
|
|
3124
|
+
return client.uploadFiles(files, onProgress);
|
|
1778
3125
|
}
|
|
1779
3126
|
function trigger(eventName, data, options) {
|
|
1780
3127
|
if (!client) {
|
|
@@ -1843,7 +3190,7 @@ if (typeof document !== "undefined") {
|
|
|
1843
3190
|
}
|
|
1844
3191
|
}
|
|
1845
3192
|
}
|
|
1846
|
-
var index_default = { init, destroy, open, close, toggle, sendMessage, trigger, onEvent, offEvent, on, identify, reset, getIdentity, setupTrackedElements, getTrackedElements };
|
|
3193
|
+
var index_default = { init, destroy, open, close, toggle, sendMessage, uploadFile, uploadFiles, trigger, onEvent, offEvent, on, identify, reset, getIdentity, setupTrackedElements, getTrackedElements };
|
|
1847
3194
|
export {
|
|
1848
3195
|
close,
|
|
1849
3196
|
index_default as default,
|
|
@@ -1860,5 +3207,7 @@ export {
|
|
|
1860
3207
|
sendMessage,
|
|
1861
3208
|
setupTrackedElements,
|
|
1862
3209
|
toggle,
|
|
1863
|
-
trigger
|
|
3210
|
+
trigger,
|
|
3211
|
+
uploadFile,
|
|
3212
|
+
uploadFiles
|
|
1864
3213
|
};
|