@adatechnology/conversations-ui 0.1.0-rc.22 → 0.1.0-rc.23

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/styles.css CHANGED
@@ -319,3 +319,480 @@
319
319
  border-left: 0;
320
320
  }
321
321
  }
322
+ .cv-workspace {
323
+ display: flex;
324
+ flex-direction: column;
325
+ height: 100%;
326
+ min-height: 0;
327
+ }
328
+ .cv-workspace-header {
329
+ display: flex;
330
+ align-items: center;
331
+ justify-content: space-between;
332
+ gap: 0.5rem;
333
+ padding: 0.75rem 1rem;
334
+ border-bottom: 1px solid rgb(229 231 235);
335
+ }
336
+ .dark .cv-workspace-header {
337
+ border-color: rgb(51 65 85);
338
+ }
339
+ .cv-workspace-header__titles {
340
+ min-width: 0;
341
+ }
342
+ .cv-workspace-header__titles h1 {
343
+ font-size: 1.125rem;
344
+ font-weight: 600;
345
+ overflow: hidden;
346
+ text-overflow: ellipsis;
347
+ white-space: nowrap;
348
+ }
349
+ .cv-workspace-header__titles p {
350
+ display: flex;
351
+ flex-wrap: wrap;
352
+ gap: 0.25rem 0.75rem;
353
+ font-size: 0.875rem;
354
+ color: rgb(107 114 128);
355
+ }
356
+ .cv-workspace-header__waiting {
357
+ color: rgb(217 119 6);
358
+ }
359
+ .dark .cv-workspace-header__waiting {
360
+ color: rgb(251 191 36);
361
+ }
362
+ .cv-workspace-header__actions {
363
+ display: flex;
364
+ flex-shrink: 0;
365
+ align-items: center;
366
+ gap: 0.5rem;
367
+ }
368
+ .cv-workspace-toggle {
369
+ border: 1px solid rgb(229 231 235);
370
+ border-radius: 0.375rem;
371
+ padding: 0.5rem 0.75rem;
372
+ font-size: 0.875rem;
373
+ min-height: 2.75rem;
374
+ }
375
+ .cv-workspace-toggle:disabled {
376
+ opacity: 0.5;
377
+ }
378
+ .cv-workspace-toggle--on {
379
+ background: rgb(37 99 235);
380
+ color: #fff;
381
+ border-color: rgb(37 99 235);
382
+ }
383
+ .dark .cv-workspace-toggle {
384
+ border-color: rgb(71 85 105);
385
+ color: rgb(226 232 240);
386
+ }
387
+ .cv-workspace-failure {
388
+ border-bottom: 1px solid rgb(253 230 138);
389
+ background: rgb(255 251 235);
390
+ padding: 0.5rem 1rem;
391
+ font-size: 0.875rem;
392
+ color: rgb(146 64 14);
393
+ }
394
+ .dark .cv-workspace-failure {
395
+ background: rgb(69 26 3);
396
+ color: rgb(253 230 138);
397
+ border-color: rgb(120 53 15);
398
+ }
399
+ .cv-workspace-grid {
400
+ display: grid;
401
+ flex: 1;
402
+ min-height: 0;
403
+ grid-template-columns: minmax(0, 1fr);
404
+ gap: 0.75rem;
405
+ padding: 0.75rem;
406
+ background: rgb(243 244 246);
407
+ }
408
+ .dark .cv-workspace-grid {
409
+ background: rgb(17 24 39);
410
+ }
411
+ .cv-workspace-list,
412
+ .cv-workspace-detail,
413
+ .cv-workspace-simulator {
414
+ display: flex;
415
+ flex-direction: column;
416
+ min-height: 0;
417
+ min-width: 0;
418
+ overflow: hidden;
419
+ border: 1px solid rgb(229 231 235);
420
+ border-radius: 0.75rem;
421
+ background: #fff;
422
+ }
423
+ .dark .cv-workspace-list,
424
+ .dark .cv-workspace-detail,
425
+ .dark .cv-workspace-simulator {
426
+ background: rgb(31 41 55);
427
+ border-color: rgb(51 65 85);
428
+ }
429
+ .cv-workspace-simulator {
430
+ flex-direction: row;
431
+ }
432
+ @media (max-width: 1023px) {
433
+ .cv-workspace-grid[data-detail=open] .cv-workspace-list {
434
+ display: none;
435
+ }
436
+ .cv-workspace-grid[data-detail=closed] .cv-workspace-detail {
437
+ display: none;
438
+ }
439
+ }
440
+ @media (min-width: 1024px) {
441
+ .cv-workspace-grid {
442
+ grid-template-columns: 360px minmax(0, 1fr);
443
+ }
444
+ .cv-workspace-grid--with-simulator {
445
+ grid-template-columns: minmax(0, 1fr) 24rem;
446
+ }
447
+ .cv-workspace-grid--with-simulator .cv-workspace-list {
448
+ display: none;
449
+ }
450
+ }
451
+ @media (min-width: 1280px) {
452
+ .cv-workspace-grid--with-simulator {
453
+ grid-template-columns: 320px minmax(0, 1fr) 24rem;
454
+ }
455
+ .cv-workspace-grid--with-simulator .cv-workspace-list {
456
+ display: flex;
457
+ }
458
+ }
459
+ .cv-workspace-pane {
460
+ display: flex;
461
+ flex-direction: column;
462
+ height: 100%;
463
+ min-height: 0;
464
+ }
465
+ .cv-workspace-transcript {
466
+ position: relative;
467
+ flex: 1;
468
+ min-height: 0;
469
+ overflow-y: auto;
470
+ padding: 0.75rem 1rem;
471
+ }
472
+ .cv-workspace-failure__link {
473
+ text-decoration: underline;
474
+ }
475
+ .cv-workspace-selection {
476
+ display: flex;
477
+ align-items: center;
478
+ justify-content: space-between;
479
+ gap: 0.5rem;
480
+ border-top: 1px solid #bfdbfe;
481
+ background: #eff6ff;
482
+ padding: 0.5rem 0.75rem;
483
+ font-size: 0.8125rem;
484
+ color: #1d4ed8;
485
+ }
486
+ .cv-workspace-selection__actions {
487
+ display: flex;
488
+ gap: 0.5rem;
489
+ }
490
+ .cv-workspace-selection__actions button {
491
+ min-height: 2.75rem;
492
+ border-radius: 0.375rem;
493
+ border: 1px solid #bfdbfe;
494
+ padding: 0 0.625rem;
495
+ }
496
+ .dark .cv-workspace-selection {
497
+ border-color: #1e40af;
498
+ background: rgb(23 37 84 / 40%);
499
+ color: #93c5fd;
500
+ }
501
+ .dark .cv-workspace-selection__actions button {
502
+ border-color: #1e40af;
503
+ }
504
+ .cv-workspace-notice {
505
+ border-top: 1px solid var(--cv-border, #e5e7eb);
506
+ background: #f3f4f6;
507
+ padding: 0.75rem 1rem;
508
+ text-align: center;
509
+ font-size: 0.875rem;
510
+ color: #6b7280;
511
+ }
512
+ .dark .cv-workspace-notice {
513
+ border-top-color: #374151;
514
+ background: #1f2937;
515
+ color: #9ca3af;
516
+ }
517
+ .cv-workspace-alert {
518
+ border-top: 1px solid rgb(254 202 202);
519
+ background: rgb(254 242 242);
520
+ padding: 0.5rem 1rem;
521
+ font-size: 0.875rem;
522
+ color: rgb(185 28 28);
523
+ }
524
+ .dark .cv-workspace-alert {
525
+ background: rgb(69 10 10);
526
+ color: rgb(252 165 165);
527
+ border-color: rgb(127 29 29);
528
+ }
529
+ .cv-workspace-filters {
530
+ display: flex;
531
+ flex-direction: column;
532
+ gap: 0.5rem;
533
+ padding: 0.75rem;
534
+ border-bottom: 1px solid rgb(229 231 235);
535
+ }
536
+ .dark .cv-workspace-filters {
537
+ border-color: rgb(51 65 85);
538
+ }
539
+ .cv-workspace-search {
540
+ width: 100%;
541
+ border: 1px solid rgb(229 231 235);
542
+ border-radius: 0.375rem;
543
+ padding: 0.5rem 0.75rem;
544
+ font-size: 0.875rem;
545
+ background: transparent;
546
+ }
547
+ .dark .cv-workspace-search {
548
+ border-color: rgb(71 85 105);
549
+ color: rgb(226 232 240);
550
+ }
551
+ .cv-workspace-chips {
552
+ display: flex;
553
+ flex-wrap: wrap;
554
+ align-items: center;
555
+ gap: 0.5rem;
556
+ font-size: 0.75rem;
557
+ }
558
+ .cv-workspace-chips__legend {
559
+ color: rgb(107 114 128);
560
+ }
561
+ .cv-workspace-chip {
562
+ display: flex;
563
+ align-items: center;
564
+ gap: 0.25rem;
565
+ border-radius: 0.375rem;
566
+ padding: 0.25rem 0.5rem;
567
+ }
568
+ .cv-workspace-chip--on {
569
+ background: rgb(229 231 235);
570
+ }
571
+ .dark .cv-workspace-chip--on {
572
+ background: rgb(51 65 85);
573
+ }
574
+ .cv-workspace-dot {
575
+ width: 0.5rem;
576
+ height: 0.5rem;
577
+ border-radius: 9999px;
578
+ }
579
+ .cv-workspace-selectall {
580
+ display: flex;
581
+ align-items: center;
582
+ gap: 0.5rem;
583
+ font-size: 0.75rem;
584
+ }
585
+ .cv-workspace-rows {
586
+ flex: 1;
587
+ min-height: 0;
588
+ overflow-y: auto;
589
+ }
590
+ .cv-workspace-empty {
591
+ padding: 1rem;
592
+ font-size: 0.875rem;
593
+ color: rgb(107 114 128);
594
+ }
595
+ .cv-workspace-bulk {
596
+ display: flex;
597
+ flex-wrap: wrap;
598
+ align-items: center;
599
+ justify-content: space-between;
600
+ gap: 0.5rem;
601
+ padding: 0.5rem 0.75rem;
602
+ border-bottom: 1px solid rgb(191 219 254);
603
+ background: rgb(239 246 255);
604
+ font-size: 0.75rem;
605
+ }
606
+ .dark .cv-workspace-bulk {
607
+ background: rgb(23 37 84);
608
+ border-color: rgb(30 58 138);
609
+ }
610
+ .cv-workspace-bulk__count {
611
+ font-weight: 500;
612
+ color: rgb(29 78 216);
613
+ }
614
+ .dark .cv-workspace-bulk__count {
615
+ color: rgb(147 197 253);
616
+ }
617
+ .cv-workspace-bulk__actions {
618
+ display: flex;
619
+ flex-wrap: wrap;
620
+ gap: 0.5rem;
621
+ }
622
+ .cv-workspace-bulk__actions button {
623
+ border: 1px solid rgb(191 219 254);
624
+ border-radius: 0.375rem;
625
+ padding: 0.25rem 0.5rem;
626
+ }
627
+ .cv-workspace-bulk__actions button:disabled {
628
+ opacity: 0.5;
629
+ }
630
+ .cv-workspace-pager {
631
+ display: flex;
632
+ align-items: center;
633
+ justify-content: space-between;
634
+ gap: 0.5rem;
635
+ border-top: 1px solid rgb(229 231 235);
636
+ padding: 0.5rem 0.75rem;
637
+ font-size: 0.75rem;
638
+ color: rgb(107 114 128);
639
+ }
640
+ .dark .cv-workspace-pager {
641
+ border-color: rgb(51 65 85);
642
+ }
643
+ .cv-workspace-pager__buttons {
644
+ display: flex;
645
+ align-items: center;
646
+ gap: 0.25rem;
647
+ }
648
+ .cv-workspace-pager__buttons button {
649
+ padding: 0 0.5rem;
650
+ }
651
+ .cv-workspace-pager__buttons button:disabled {
652
+ opacity: 0.4;
653
+ }
654
+ .cv-workspace-modal {
655
+ position: fixed;
656
+ inset: 0;
657
+ z-index: 50;
658
+ display: flex;
659
+ align-items: center;
660
+ justify-content: center;
661
+ padding: 1rem;
662
+ background: rgb(0 0 0 / 50%);
663
+ }
664
+ .cv-workspace-modal__box {
665
+ display: flex;
666
+ width: 100%;
667
+ max-width: 28rem;
668
+ max-height: 80vh;
669
+ flex-direction: column;
670
+ overflow: hidden;
671
+ border-radius: 0.75rem;
672
+ border: 1px solid #e5e7eb;
673
+ background: #fff;
674
+ box-shadow: 0 20px 25px -5px rgb(0 0 0 / 25%);
675
+ }
676
+ .cv-workspace-modal__header {
677
+ display: flex;
678
+ align-items: flex-start;
679
+ justify-content: space-between;
680
+ gap: 0.75rem;
681
+ border-bottom: 1px solid #e5e7eb;
682
+ padding: 1rem 1.25rem;
683
+ }
684
+ .cv-workspace-modal__header h3 {
685
+ font-weight: 600;
686
+ }
687
+ .cv-workspace-modal__header p {
688
+ margin-top: 0.125rem;
689
+ font-size: 0.75rem;
690
+ color: #6b7280;
691
+ }
692
+ .cv-workspace-modal__search {
693
+ border-bottom: 1px solid #f3f4f6;
694
+ padding: 0.75rem 1rem;
695
+ }
696
+ .cv-workspace-modal__search input {
697
+ width: 100%;
698
+ border-radius: 0.5rem;
699
+ border: 1px solid #e5e7eb;
700
+ padding: 0.5rem 0.75rem;
701
+ font-size: 0.875rem;
702
+ }
703
+ .cv-workspace-modal__list {
704
+ flex: 1;
705
+ overflow-y: auto;
706
+ padding: 0.5rem;
707
+ }
708
+ .cv-workspace-modal__item {
709
+ display: flex;
710
+ width: 100%;
711
+ flex-direction: column;
712
+ gap: 0.125rem;
713
+ border: 1px solid transparent;
714
+ border-radius: 0.5rem;
715
+ padding: 0.625rem 0.75rem;
716
+ text-align: left;
717
+ font-size: 0.875rem;
718
+ }
719
+ .cv-workspace-modal__item:hover {
720
+ background: #f9fafb;
721
+ }
722
+ .cv-workspace-modal__item--on {
723
+ border-color: #bfdbfe;
724
+ background: #eff6ff;
725
+ color: #1d4ed8;
726
+ }
727
+ .cv-workspace-modal__item-name {
728
+ overflow: hidden;
729
+ text-overflow: ellipsis;
730
+ white-space: nowrap;
731
+ font-weight: 500;
732
+ }
733
+ .cv-workspace-modal__item-meta {
734
+ font-size: 0.75rem;
735
+ color: #9ca3af;
736
+ }
737
+ .cv-workspace-modal__warning {
738
+ border-top: 1px solid #fde68a;
739
+ background: #fffbeb;
740
+ padding: 0.5rem 1rem;
741
+ font-size: 0.75rem;
742
+ color: #b45309;
743
+ }
744
+ .cv-workspace-modal__footer {
745
+ display: flex;
746
+ justify-content: flex-end;
747
+ gap: 0.5rem;
748
+ border-top: 1px solid #e5e7eb;
749
+ padding: 0.75rem 1rem;
750
+ }
751
+ .cv-workspace-modal__footer button {
752
+ min-height: 2.75rem;
753
+ border-radius: 0.5rem;
754
+ border: 1px solid #e5e7eb;
755
+ padding: 0 0.875rem;
756
+ font-size: 0.875rem;
757
+ }
758
+ .cv-workspace-modal__footer button:last-child {
759
+ border-color: transparent;
760
+ background: #2563eb;
761
+ color: #fff;
762
+ }
763
+ .cv-workspace-modal__footer button:disabled {
764
+ opacity: 0.5;
765
+ }
766
+ .dark .cv-workspace-modal__box {
767
+ border-color: #374151;
768
+ background: #1f2937;
769
+ }
770
+ .dark .cv-workspace-modal__header,
771
+ .dark .cv-workspace-modal__footer {
772
+ border-color: #374151;
773
+ }
774
+ .dark .cv-workspace-modal__search {
775
+ border-color: #374151;
776
+ }
777
+ .dark .cv-workspace-modal__search input {
778
+ border-color: #4b5563;
779
+ background: #374151;
780
+ color: #f3f4f6;
781
+ }
782
+ .dark .cv-workspace-modal__item:hover {
783
+ background: rgb(55 65 81 / 50%);
784
+ }
785
+ .dark .cv-workspace-modal__item--on {
786
+ border-color: #1e40af;
787
+ background: rgb(23 37 84 / 40%);
788
+ color: #93c5fd;
789
+ }
790
+ .dark .cv-workspace-modal__warning {
791
+ border-color: #92400e;
792
+ background: rgb(69 26 3 / 40%);
793
+ color: #fbbf24;
794
+ }
795
+ .dark .cv-workspace-modal__footer button {
796
+ border-color: #4b5563;
797
+ color: #f3f4f6;
798
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adatechnology/conversations-ui",
3
- "version": "0.1.0-rc.22",
3
+ "version": "0.1.0-rc.23",
4
4
  "description": "WhatsApp conversation UI components — parametrizável por endpoint, tema e feature flags",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/index.ts CHANGED
@@ -209,3 +209,18 @@ export { createMediaUrlResolver } from './lib/createMediaUrlResolver'
209
209
  export type { ConversationHeaderUtility } from './ConversationHeader'
210
210
  export { applyQuickReplyVariables, resolveQuickReply } from './MessageComposer'
211
211
  export type { QuickReply } from './MessageComposer'
212
+
213
+ // Tela de atendimento completa. Fica no export principal — e não num subpath — porque é a
214
+ // composição padrão do pacote: quem instala conversas quer esta tela, e as peças continuam
215
+ // exportadas ao lado para quem precisar montar outra.
216
+ export { ConversationsWorkspace, ConversationPane, ConversationsInboxList } from './workspace'
217
+ export { useConversationsInbox, CONVERSATIONS_PER_PAGE, DEFAULT_CONVERSATIONS_WORKSPACE_LABELS } from './workspace'
218
+ export type {
219
+ ConversationsWorkspaceProps,
220
+ ConversationsWorkspaceSimulator,
221
+ ConversationsWorkspaceLabels,
222
+ ConversationPaneProps,
223
+ ConversationsInboxListProps,
224
+ UseConversationsInboxParams,
225
+ UseConversationsInboxResult,
226
+ } from './workspace'
@@ -36,6 +36,13 @@ function createCapturingFetch(status = 200): { fetchImplementation: typeof fetch
36
36
  return { fetchImplementation, captured }
37
37
  }
38
38
 
39
+ /** `uploadMedia` é opcional no contrato — o cliente do webhook sempre traz, o teste garante isso. */
40
+ function uploadMediaOf(client: { uploadMedia?: (file: File) => Promise<unknown> }) {
41
+ const upload = client.uploadMedia
42
+ if (!upload) throw new Error('createPreviewWebhookClient deveria expor uploadMedia')
43
+ return upload
44
+ }
45
+
39
46
  describe('createPreviewWebhookClient', () => {
40
47
  it('assina com o mesmo HMAC que o servidor calcula em node:crypto', async () => {
41
48
  const { fetchImplementation, captured } = createCapturingFetch()
@@ -144,7 +151,7 @@ describe('createPreviewWebhookClient.uploadMedia', () => {
144
151
  fetchImplementation,
145
152
  })
146
153
 
147
- const uploaded = await client.uploadMedia(audioFile())
154
+ const uploaded = (await uploadMediaOf(client)(audioFile())) as { mediaId: string; mimeType?: string }
148
155
 
149
156
  expect(calls[0]?.url).toBe('http://localhost:3000/v1/preview/media')
150
157
  expect(uploaded.mediaId).toBe(`${PREVIEW_MEDIA_ID_PREFIX}upl_123`)
@@ -160,7 +167,7 @@ describe('createPreviewWebhookClient.uploadMedia', () => {
160
167
  fetchImplementation,
161
168
  })
162
169
 
163
- await client.uploadMedia(audioFile())
170
+ await uploadMediaOf(client)(audioFile())
164
171
 
165
172
  const expected = `sha256=${createHmac('sha256', APP_SECRET).update('audio/ogg').digest('hex')}`
166
173
  expect(calls[0]?.signature).toBe(expected)
@@ -175,7 +182,7 @@ describe('createPreviewWebhookClient.uploadMedia', () => {
175
182
  fetchImplementation,
176
183
  })
177
184
 
178
- await client.uploadMedia(audioFile())
185
+ await uploadMediaOf(client)(audioFile())
179
186
 
180
187
  expect(calls[0]?.url).toBe('/v1/preview/media')
181
188
  })
@@ -189,6 +196,6 @@ describe('createPreviewWebhookClient.uploadMedia', () => {
189
196
  fetchImplementation,
190
197
  })
191
198
 
192
- await expect(client.uploadMedia(audioFile())).rejects.toBeInstanceOf(PreviewMediaUploadRejectedError)
199
+ await expect(uploadMediaOf(client)(audioFile())).rejects.toBeInstanceOf(PreviewMediaUploadRejectedError)
193
200
  })
194
201
  })