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

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.js CHANGED
@@ -2586,6 +2586,930 @@ function useInboxActions() {
2586
2586
  [api]
2587
2587
  );
2588
2588
  }
2589
+
2590
+ // src/workspace/ConversationsWorkspace.tsx
2591
+ import { useEffect as useEffect10, useMemo as useMemo5, useState as useState14 } from "react";
2592
+
2593
+ // src/workspace/BulkTemplateModal.tsx
2594
+ import { useEffect as useEffect7, useMemo as useMemo3, useState as useState11 } from "react";
2595
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
2596
+ function BulkTemplateModal({
2597
+ labels,
2598
+ expiredCount,
2599
+ sending,
2600
+ onClose,
2601
+ onSend
2602
+ }) {
2603
+ const context = useConversations();
2604
+ if (!context) {
2605
+ throw new Error("BulkTemplateModal requires an ancestor <ConversationsProvider>");
2606
+ }
2607
+ const { api } = context;
2608
+ const [templates, setTemplates] = useState11([]);
2609
+ const [search, setSearch] = useState11("");
2610
+ const [selected, setSelected] = useState11("");
2611
+ useEffect7(() => {
2612
+ let active = true;
2613
+ void api.listTemplates?.().then((loaded) => {
2614
+ if (active) setTemplates(loaded);
2615
+ }).catch(() => {
2616
+ });
2617
+ return () => {
2618
+ active = false;
2619
+ };
2620
+ }, [api]);
2621
+ const filtered = useMemo3(() => {
2622
+ const term = search.trim().toLowerCase();
2623
+ if (!term) return templates;
2624
+ return templates.filter((template) => template.name.toLowerCase().includes(term));
2625
+ }, [templates, search]);
2626
+ return /* @__PURE__ */ jsx21("div", { className: "cv-workspace-modal", role: "dialog", "aria-modal": "true", "aria-label": labels.templateModalTitle, children: /* @__PURE__ */ jsxs19("div", { className: "cv-workspace-modal__box", children: [
2627
+ /* @__PURE__ */ jsxs19("header", { className: "cv-workspace-modal__header", children: [
2628
+ /* @__PURE__ */ jsxs19("div", { children: [
2629
+ /* @__PURE__ */ jsx21("h3", { children: labels.templateModalTitle }),
2630
+ /* @__PURE__ */ jsx21("p", { children: labels.templateModalAvailable(templates.length) })
2631
+ ] }),
2632
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: onClose, "aria-label": labels.templateModalCancel, children: "\u2715" })
2633
+ ] }),
2634
+ /* @__PURE__ */ jsx21("div", { className: "cv-workspace-modal__search", children: /* @__PURE__ */ jsx21(
2635
+ "input",
2636
+ {
2637
+ type: "search",
2638
+ value: search,
2639
+ onChange: (event) => setSearch(event.target.value),
2640
+ placeholder: labels.templateModalSearch,
2641
+ autoFocus: true
2642
+ }
2643
+ ) }),
2644
+ /* @__PURE__ */ jsxs19("div", { className: "cv-workspace-modal__list", children: [
2645
+ filtered.length === 0 ? /* @__PURE__ */ jsx21("p", { className: "cv-workspace-empty", children: labels.templateModalEmpty }) : null,
2646
+ filtered.map((template) => /* @__PURE__ */ jsxs19(
2647
+ "button",
2648
+ {
2649
+ type: "button",
2650
+ onClick: () => setSelected(template.name === selected ? "" : template.name),
2651
+ "aria-pressed": template.name === selected,
2652
+ className: `cv-workspace-modal__item${template.name === selected ? " cv-workspace-modal__item--on" : ""}`,
2653
+ children: [
2654
+ /* @__PURE__ */ jsx21("span", { className: "cv-workspace-modal__item-name", children: template.name }),
2655
+ /* @__PURE__ */ jsxs19("span", { className: "cv-workspace-modal__item-meta", children: [
2656
+ template.language,
2657
+ template.category ? ` \xB7 ${template.category.toLowerCase()}` : ""
2658
+ ] })
2659
+ ]
2660
+ },
2661
+ template.name
2662
+ ))
2663
+ ] }),
2664
+ expiredCount === 0 ? /* @__PURE__ */ jsx21("p", { className: "cv-workspace-modal__warning", children: labels.templateModalNoneExpired }) : null,
2665
+ /* @__PURE__ */ jsxs19("footer", { className: "cv-workspace-modal__footer", children: [
2666
+ /* @__PURE__ */ jsx21("button", { type: "button", onClick: onClose, children: labels.templateModalCancel }),
2667
+ /* @__PURE__ */ jsx21(
2668
+ "button",
2669
+ {
2670
+ type: "button",
2671
+ disabled: sending || expiredCount === 0,
2672
+ onClick: () => onSend(selected || void 0),
2673
+ children: sending ? labels.templateModalSending : labels.templateModalSend(expiredCount)
2674
+ }
2675
+ )
2676
+ ] })
2677
+ ] }) });
2678
+ }
2679
+
2680
+ // src/workspace/ConversationPane.tsx
2681
+ import { useEffect as useEffect8, useState as useState12 } from "react";
2682
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
2683
+ function ConversationPane({
2684
+ conversation,
2685
+ now,
2686
+ busy,
2687
+ labels,
2688
+ onTakeover,
2689
+ onReturnToBot,
2690
+ onFinish,
2691
+ onBack,
2692
+ extraUtilities,
2693
+ contextEntriesOf,
2694
+ quickReplies,
2695
+ quickReplyVariablesFor,
2696
+ flowLabel,
2697
+ onDownload,
2698
+ requireTakeoverToReply,
2699
+ messageSelection,
2700
+ initialComposerText,
2701
+ renderAboveTranscript,
2702
+ onAttach,
2703
+ composer = "simple",
2704
+ composerVariablesFor,
2705
+ onSendAttachments,
2706
+ onRecordAudio
2707
+ }) {
2708
+ const context = useConversations();
2709
+ if (!context) {
2710
+ throw new Error("ConversationPane requires an ancestor <ConversationsProvider>");
2711
+ }
2712
+ const { api } = context;
2713
+ const { messages, refetch } = useConversationMessages(conversation.id);
2714
+ const { context: conversationContext } = useConversationContext(conversation.id);
2715
+ const [documentsOpen, setDocumentsOpen] = useState12(false);
2716
+ const [sendFailure, setSendFailure] = useState12(void 0);
2717
+ const [selectedMessageIds, setSelectedMessageIds] = useState12(/* @__PURE__ */ new Set());
2718
+ const [draft, setDraft] = useState12(initialComposerText ?? "");
2719
+ const [queuedFiles, setQueuedFiles] = useState12([]);
2720
+ useEffect8(() => {
2721
+ setSelectedMessageIds(/* @__PURE__ */ new Set());
2722
+ setDraft(initialComposerText ?? "");
2723
+ setQueuedFiles([]);
2724
+ }, [conversation.id, initialComposerText]);
2725
+ function toggleMessageSelected(messageId) {
2726
+ setSelectedMessageIds((current) => {
2727
+ const next = new Set(current);
2728
+ if (next.has(messageId)) next.delete(messageId);
2729
+ else next.add(messageId);
2730
+ return next;
2731
+ });
2732
+ }
2733
+ function copySelectedMessages() {
2734
+ const transcript = messages.filter((message) => selectedMessageIds.has(message.id)).map(
2735
+ (message) => `[${new Date(message.timestamp).toLocaleString()}] ${message.sender}: ${message.content ?? `(${message.type})`}`
2736
+ ).join("\n");
2737
+ void navigator.clipboard.writeText(transcript);
2738
+ setSelectedMessageIds(/* @__PURE__ */ new Set());
2739
+ }
2740
+ const scroll = useScrollToLatestMessage({ conversationId: conversation.id, messageCount: messages.length });
2741
+ useConversationRealtime(conversation.id, () => {
2742
+ void refetch();
2743
+ });
2744
+ const blocked = isWindowBlocking(
2745
+ windowOf({ lastInboundAt: conversation.lastInboundAt, now, channel: conversation.channel })
2746
+ );
2747
+ async function runSend(action, fallback) {
2748
+ setSendFailure(void 0);
2749
+ try {
2750
+ await action();
2751
+ await refetch();
2752
+ } catch (error) {
2753
+ setSendFailure(error instanceof Error ? error.message : fallback);
2754
+ }
2755
+ }
2756
+ async function handleSend(text) {
2757
+ await runSend(() => api.sendMessage(conversation.id, text), labels.sendFailure);
2758
+ }
2759
+ async function handleRichSend() {
2760
+ if (onSendAttachments && queuedFiles.length > 0) {
2761
+ const files = queuedFiles;
2762
+ const caption = draft;
2763
+ await runSend(() => onSendAttachments(files, caption), labels.attachFailure);
2764
+ setQueuedFiles([]);
2765
+ setDraft("");
2766
+ return;
2767
+ }
2768
+ if (!draft.trim()) return;
2769
+ await handleSend(draft);
2770
+ setDraft("");
2771
+ }
2772
+ async function handleAttach(file) {
2773
+ if (!onAttach) return;
2774
+ await runSend(() => onAttach(file), labels.attachFailure);
2775
+ }
2776
+ function handleDownload() {
2777
+ downloadTextFile(
2778
+ buildTranscriptFilename(conversation.whatsappNumber, /* @__PURE__ */ new Date()),
2779
+ buildTranscriptText({
2780
+ messages,
2781
+ whatsappNumber: conversation.whatsappNumber,
2782
+ clientName: conversation.clientName
2783
+ })
2784
+ );
2785
+ }
2786
+ const contextEntries = contextEntriesOf?.(conversationContext);
2787
+ const composerVariables = composerVariablesFor?.(conversation, conversationContext);
2788
+ const richQuickReplies = quickReplies?.map((reply) => ({
2789
+ id: reply.key,
2790
+ label: reply.label,
2791
+ text: typeof reply.text === "string" ? applyQuickReplyVariables(reply.text, quickReplyVariablesFor?.(conversation, conversationContext) ?? {}) : reply.text(quickReplyVariablesFor?.(conversation, conversationContext) ?? {})
2792
+ }));
2793
+ const botOwnsConversation = Boolean(requireTakeoverToReply) && conversation.mode !== "human";
2794
+ return /* @__PURE__ */ jsxs20("div", { className: "cv-workspace-pane", children: [
2795
+ /* @__PURE__ */ jsx22(
2796
+ ConversationHeader,
2797
+ {
2798
+ conversation,
2799
+ busy,
2800
+ ...onTakeover ? { onTakeover } : {},
2801
+ ...onReturnToBot ? { onReturnToBot } : {},
2802
+ ...onFinish ? { onFinish } : {},
2803
+ onDownload: onDownload ?? handleDownload,
2804
+ onBack,
2805
+ onOpenDocuments: () => setDocumentsOpen(!documentsOpen),
2806
+ documentsOpen,
2807
+ ...extraUtilities ? { extraUtilities } : {}
2808
+ }
2809
+ ),
2810
+ contextEntries && contextEntries.length > 0 || flowLabel ? /* @__PURE__ */ jsx22(ConversationContextPanel, { entries: contextEntries ?? [], ...flowLabel ? { flowLabel } : {} }) : null,
2811
+ /* @__PURE__ */ jsx22(ConversationDocumentsPanel, { conversationId: conversation.id, open: documentsOpen }),
2812
+ renderAboveTranscript?.(conversation, conversationContext),
2813
+ /* @__PURE__ */ jsx22(
2814
+ ConversationWallpaper,
2815
+ {
2816
+ ref: scroll.containerRef,
2817
+ onScroll: scroll.handleScroll,
2818
+ className: "cv-workspace-transcript",
2819
+ children: messages.map((message, index) => {
2820
+ const previous = index > 0 ? messages[index - 1] : void 0;
2821
+ const startsNewDay = !previous || new Date(message.timestamp).toDateString() !== new Date(previous.timestamp).toDateString();
2822
+ return /* @__PURE__ */ jsxs20("div", { children: [
2823
+ startsNewDay ? /* @__PURE__ */ jsx22(DateDivider, { iso: message.timestamp }) : null,
2824
+ /* @__PURE__ */ jsx22(
2825
+ MessageBubble,
2826
+ {
2827
+ message,
2828
+ isMine: message.direction === "outbound",
2829
+ isFirstInGroup: !previous || previous.sender !== message.sender,
2830
+ ...messageSelection ? {
2831
+ isSelecting: selectedMessageIds.size > 0,
2832
+ isSelected: selectedMessageIds.has(message.id),
2833
+ onToggleSelect: () => toggleMessageSelected(message.id)
2834
+ } : {}
2835
+ }
2836
+ )
2837
+ ] }, message.id);
2838
+ })
2839
+ }
2840
+ ),
2841
+ messageSelection && selectedMessageIds.size > 0 ? /* @__PURE__ */ jsxs20("div", { className: "cv-workspace-selection", children: [
2842
+ /* @__PURE__ */ jsx22("span", { children: labels.messagesSelected(selectedMessageIds.size) }),
2843
+ /* @__PURE__ */ jsxs20("div", { className: "cv-workspace-selection__actions", children: [
2844
+ /* @__PURE__ */ jsx22("button", { type: "button", onClick: () => setSelectedMessageIds(/* @__PURE__ */ new Set()), children: labels.bulkClear }),
2845
+ /* @__PURE__ */ jsx22("button", { type: "button", onClick: copySelectedMessages, children: labels.copySelected })
2846
+ ] })
2847
+ ] }) : null,
2848
+ sendFailure ? /* @__PURE__ */ jsx22("p", { role: "alert", className: "cv-workspace-alert", children: sendFailure }) : null,
2849
+ blocked ? /* @__PURE__ */ jsx22(
2850
+ WindowExpiredNotice,
2851
+ {
2852
+ disabled: busy,
2853
+ onSendTemplate: () => void api.sendTemplate(conversation.id, {}).then(() => refetch())
2854
+ }
2855
+ ) : botOwnsConversation ? (
2856
+ // Responder com a conversa no bot atropelaria o fluxo automático no meio de uma pergunta.
2857
+ /* @__PURE__ */ jsx22("p", { className: "cv-workspace-notice", children: labels.takeoverToReply })
2858
+ ) : composer === "rich" ? /* @__PURE__ */ jsx22(
2859
+ RichMessageComposer,
2860
+ {
2861
+ value: draft,
2862
+ onChange: setDraft,
2863
+ onSend: () => void handleRichSend(),
2864
+ ...onSendAttachments ? { onAttachFiles: (files) => setQueuedFiles((current) => [...current, ...Array.from(files)]) } : onAttach ? {
2865
+ onAttachFiles: (files) => {
2866
+ for (const file of Array.from(files)) void handleAttach(file);
2867
+ }
2868
+ } : {},
2869
+ placeholder: labels.composerPlaceholder,
2870
+ isSending: busy,
2871
+ ...onRecordAudio ? {
2872
+ idleAction: /* @__PURE__ */ jsx22(
2873
+ AudioRecorderButton,
2874
+ {
2875
+ onRecorded: (file) => void runSend(() => onRecordAudio(file), labels.recordFailure),
2876
+ onFailure: (failureMessage) => setSendFailure(failureMessage)
2877
+ }
2878
+ )
2879
+ } : {},
2880
+ ...queuedFiles.length > 0 ? {
2881
+ attachmentsPreview: /* @__PURE__ */ jsx22("ul", { className: "cv-workspace-attachments", children: queuedFiles.map((file, index) => /* @__PURE__ */ jsxs20("li", { children: [
2882
+ /* @__PURE__ */ jsx22("span", { children: file.name }),
2883
+ /* @__PURE__ */ jsx22(
2884
+ "button",
2885
+ {
2886
+ type: "button",
2887
+ "aria-label": labels.attachmentRemove,
2888
+ onClick: () => setQueuedFiles((current) => current.filter((_, position) => position !== index)),
2889
+ children: "\u2715"
2890
+ }
2891
+ )
2892
+ ] }, `${file.name}-${index}`)) })
2893
+ } : {},
2894
+ ...richQuickReplies ? { quickReplies: [...richQuickReplies] } : {},
2895
+ ...composerVariables ? { variables: [...composerVariables] } : {}
2896
+ }
2897
+ ) : /* @__PURE__ */ jsx22(
2898
+ MessageComposer,
2899
+ {
2900
+ value: draft,
2901
+ onChange: setDraft,
2902
+ onSend: (text) => void handleSend(text),
2903
+ ...onAttach ? { onAttach: (file) => void handleAttach(file) } : {},
2904
+ placeholder: labels.composerPlaceholder,
2905
+ ...quickReplies ? { quickReplies } : {},
2906
+ ...quickReplyVariablesFor ? { quickReplyVariables: quickReplyVariablesFor(conversation, conversationContext) } : {}
2907
+ }
2908
+ )
2909
+ ] });
2910
+ }
2911
+
2912
+ // src/workspace/ConversationsInboxList.tsx
2913
+ import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
2914
+ function ConversationsInboxList({
2915
+ inbox,
2916
+ labels,
2917
+ className,
2918
+ renderFilters,
2919
+ renderBulkActions,
2920
+ renderRow,
2921
+ onSendTemplateToSelected
2922
+ }) {
2923
+ const hasSelection = inbox.selectedIds.size > 0;
2924
+ return /* @__PURE__ */ jsxs21("aside", { className, children: [
2925
+ hasSelection ? /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-bulk", children: [
2926
+ /* @__PURE__ */ jsx23("span", { className: "cv-workspace-bulk__count", children: labels.bulkSelected(inbox.selectedIds.size) }),
2927
+ /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-bulk__actions", children: [
2928
+ /* @__PURE__ */ jsx23("button", { type: "button", onClick: inbox.clearBulkSelection, children: labels.bulkClear }),
2929
+ onSendTemplateToSelected ? /* @__PURE__ */ jsx23("button", { type: "button", onClick: onSendTemplateToSelected, disabled: inbox.busy, children: labels.bulkTemplate }) : null,
2930
+ inbox.canFinalize ? /* @__PURE__ */ jsx23(
2931
+ "button",
2932
+ {
2933
+ type: "button",
2934
+ disabled: inbox.busy,
2935
+ onClick: () => {
2936
+ if (window.confirm(labels.bulkFinalizeConfirm(inbox.selectedIds.size))) {
2937
+ void inbox.finalizeSelected();
2938
+ }
2939
+ },
2940
+ children: labels.bulkFinalize
2941
+ }
2942
+ ) : null,
2943
+ renderBulkActions?.(inbox)
2944
+ ] })
2945
+ ] }) : null,
2946
+ /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-filters", children: [
2947
+ /* @__PURE__ */ jsx23(
2948
+ "input",
2949
+ {
2950
+ type: "search",
2951
+ value: inbox.search,
2952
+ onChange: (event) => inbox.setSearch(event.target.value),
2953
+ placeholder: labels.search,
2954
+ className: "cv-workspace-search"
2955
+ }
2956
+ ),
2957
+ /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-chips", children: [
2958
+ /* @__PURE__ */ jsx23("span", { className: "cv-workspace-chips__legend", children: labels.windowLegend }),
2959
+ WINDOW_FILTERS.map((filter) => /* @__PURE__ */ jsxs21(
2960
+ "button",
2961
+ {
2962
+ type: "button",
2963
+ onClick: () => inbox.setWindowFilter(filter.value),
2964
+ "aria-pressed": inbox.windowFilter === filter.value,
2965
+ className: `cv-workspace-chip${inbox.windowFilter === filter.value ? " cv-workspace-chip--on" : ""}`,
2966
+ children: [
2967
+ filter.dotClass ? /* @__PURE__ */ jsx23("span", { className: `cv-workspace-dot ${filter.dotClass}` }) : null,
2968
+ filter.label
2969
+ ]
2970
+ },
2971
+ filter.value
2972
+ ))
2973
+ ] }),
2974
+ inbox.channelFilters.length > 0 ? /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-chips", children: [
2975
+ /* @__PURE__ */ jsx23("span", { className: "cv-workspace-chips__legend", children: labels.channelLegend }),
2976
+ inbox.channelFilters.map((filter) => /* @__PURE__ */ jsxs21(
2977
+ "button",
2978
+ {
2979
+ type: "button",
2980
+ onClick: () => inbox.setChannelFilter(filter.value),
2981
+ "aria-pressed": inbox.channelFilter === filter.value,
2982
+ className: `cv-workspace-chip${inbox.channelFilter === filter.value ? " cv-workspace-chip--on" : ""}`,
2983
+ children: [
2984
+ filter.value === CHANNEL_FILTER_ALL ? null : /* @__PURE__ */ jsx23(ChannelIcon, { channel: filter.value }),
2985
+ filter.label
2986
+ ]
2987
+ },
2988
+ filter.value
2989
+ ))
2990
+ ] }) : null,
2991
+ renderFilters?.(inbox),
2992
+ /* @__PURE__ */ jsxs21("label", { className: "cv-workspace-selectall", children: [
2993
+ /* @__PURE__ */ jsx23("input", { type: "checkbox", checked: inbox.allOnPageSelected, onChange: inbox.toggleSelectAllOnPage }),
2994
+ labels.selectAll
2995
+ ] })
2996
+ ] }),
2997
+ /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-rows", children: [
2998
+ inbox.pageConversations.map(
2999
+ (conversation) => renderRow ? /* @__PURE__ */ jsx23("div", { children: renderRow(conversation) }, conversation.id) : /* @__PURE__ */ jsx23(
3000
+ ConversationRow,
3001
+ {
3002
+ conversation,
3003
+ active: conversation.id === inbox.selectedId,
3004
+ selected: inbox.selectedIds.has(conversation.id),
3005
+ now: inbox.now,
3006
+ busy: inbox.busy,
3007
+ onOpen: () => inbox.selectConversation(conversation.id),
3008
+ onToggleSelected: () => inbox.toggleSelected(conversation.id),
3009
+ onTakeover: () => void inbox.takeover(conversation.id)
3010
+ },
3011
+ conversation.id
3012
+ )
3013
+ ),
3014
+ !inbox.loading && inbox.filteredCount === 0 ? /* @__PURE__ */ jsx23("p", { className: "cv-workspace-empty", children: labels.emptyList }) : null
3015
+ ] }),
3016
+ /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-pager", children: [
3017
+ /* @__PURE__ */ jsx23("span", { children: labels.rangeOf(inbox.firstOnPage, inbox.lastOnPage, inbox.filteredCount) }),
3018
+ /* @__PURE__ */ jsxs21("div", { className: "cv-workspace-pager__buttons", children: [
3019
+ /* @__PURE__ */ jsx23("button", { type: "button", onClick: () => inbox.goToPage(1), disabled: inbox.page === 1, "aria-label": "Primeira p\xE1gina", children: "\xAB" }),
3020
+ /* @__PURE__ */ jsx23(
3021
+ "button",
3022
+ {
3023
+ type: "button",
3024
+ onClick: () => inbox.goToPage(inbox.page - 1),
3025
+ disabled: inbox.page === 1,
3026
+ "aria-label": "P\xE1gina anterior",
3027
+ children: "\u2039"
3028
+ }
3029
+ ),
3030
+ /* @__PURE__ */ jsx23("span", { children: labels.pageOf(inbox.page, inbox.pageCount) }),
3031
+ /* @__PURE__ */ jsx23(
3032
+ "button",
3033
+ {
3034
+ type: "button",
3035
+ onClick: () => inbox.goToPage(inbox.page + 1),
3036
+ disabled: inbox.page === inbox.pageCount,
3037
+ "aria-label": "Pr\xF3xima p\xE1gina",
3038
+ children: "\u203A"
3039
+ }
3040
+ ),
3041
+ /* @__PURE__ */ jsx23(
3042
+ "button",
3043
+ {
3044
+ type: "button",
3045
+ onClick: () => inbox.goToPage(inbox.pageCount),
3046
+ disabled: inbox.page === inbox.pageCount,
3047
+ "aria-label": "\xDAltima p\xE1gina",
3048
+ children: "\xBB"
3049
+ }
3050
+ )
3051
+ ] })
3052
+ ] })
3053
+ ] });
3054
+ }
3055
+
3056
+ // src/workspace/labels.ts
3057
+ var DEFAULT_CONVERSATIONS_WORKSPACE_LABELS = {
3058
+ title: "Conversas",
3059
+ conversations: "conversas",
3060
+ waiting: "aguardando",
3061
+ unread: "n\xE3o lidas",
3062
+ waitingOnly: "Aguardando atendimento",
3063
+ markSelectedAsRead: "Marcar selecionadas como lidas",
3064
+ search: "Buscar conversa...",
3065
+ windowLegend: "Janela:",
3066
+ channelLegend: "Canal:",
3067
+ selectAll: "Selecionar todas",
3068
+ emptyList: "Nenhuma conversa encontrada.",
3069
+ emptyDetail: "Selecione uma conversa.",
3070
+ bulkSelected: (count) => `${count} selecionada${count === 1 ? "" : "s"}`,
3071
+ bulkClear: "Limpar sele\xE7\xE3o",
3072
+ bulkFinalize: "Finalizar",
3073
+ bulkFinalizeConfirm: (count) => `Finalizar ${count} conversa${count === 1 ? "" : "s"}?`,
3074
+ bulkTemplate: "Enviar template",
3075
+ markAllAsRead: "Marcar todas como lidas",
3076
+ templateModalTitle: "Escolher template",
3077
+ templateModalSearch: "Buscar template...",
3078
+ templateModalEmpty: "Nenhum template encontrado.",
3079
+ templateModalCancel: "Cancelar",
3080
+ templateModalSending: "Enviando\u2026",
3081
+ templateModalNoneExpired: "Nenhuma das conversas selecionadas est\xE1 fora da janela de 24h.",
3082
+ templateModalAvailable: (count) => `${count} template${count === 1 ? "" : "s"} dispon\xEDve${count === 1 ? "l" : "is"}`,
3083
+ templateModalSend: (count) => `Enviar para ${count}`,
3084
+ messagesSelected: (count) => `${count} mensagem${count === 1 ? "" : "s"} selecionada${count === 1 ? "" : "s"}`,
3085
+ copySelected: "Copiar",
3086
+ composerPlaceholder: "Responder como atendente\u2026",
3087
+ attachFailure: "Falha ao enviar o arquivo.",
3088
+ attachmentRemove: "Remover anexo",
3089
+ recordFailure: "Falha ao gravar o \xE1udio.",
3090
+ sendFailure: "Falha ao enviar a mensagem.",
3091
+ takeoverToReply: "Assuma o atendimento para responder diretamente ao cliente.",
3092
+ signIn: "Entrar no painel",
3093
+ pageOf: (page, pageCount) => `${page} / ${pageCount}`,
3094
+ rangeOf: (first, last, total) => total === 0 ? `0 de 0` : `${first}\u2013${last} de ${total}`
3095
+ };
3096
+
3097
+ // src/workspace/useConversationsInbox.ts
3098
+ import { useCallback as useCallback7, useEffect as useEffect9, useMemo as useMemo4, useRef as useRef7, useState as useState13 } from "react";
3099
+ var CONVERSATIONS_PER_PAGE = 50;
3100
+ function defaultDescribeFailure(error) {
3101
+ const status = error.status;
3102
+ if (status === 401 || status === 403) {
3103
+ return "Sess\xE3o expirada nesta aba \u2014 entre no painel de novo para ver as conversas.";
3104
+ }
3105
+ return error instanceof Error && error.message ? `N\xE3o foi poss\xEDvel carregar as conversas: ${error.message}` : "N\xE3o foi poss\xEDvel carregar as conversas.";
3106
+ }
3107
+ function useConversationsInbox(params = {}) {
3108
+ const context = useConversations();
3109
+ if (!context) {
3110
+ throw new Error("useConversationsInbox requires an ancestor <ConversationsProvider>");
3111
+ }
3112
+ const { api } = context;
3113
+ const perPage = params.perPage ?? CONVERSATIONS_PER_PAGE;
3114
+ const markReadOnOpen = params.markReadOnOpen ?? true;
3115
+ const describeFailure = params.describeFailure ?? defaultDescribeFailure;
3116
+ const [waitingOnly, setWaitingOnly] = useState13(false);
3117
+ const [windowFilter, setWindowFilter] = useState13(CONVERSATION_WINDOW.ALL);
3118
+ const [channelFilter, setChannelFilter] = useState13(CHANNEL_FILTER_ALL);
3119
+ const [search, setSearch] = useState13("");
3120
+ const [page, setPage] = useState13(1);
3121
+ const [selectedId, setSelectedId] = useState13(void 0);
3122
+ const [selectedIds, setSelectedIds] = useState13(/* @__PURE__ */ new Set());
3123
+ const [busy, setBusy] = useState13(false);
3124
+ const { conversations, total, loading, error, refetch } = useConversationList({
3125
+ ...waitingOnly ? { waitingHuman: true } : {},
3126
+ ...search ? { search } : {},
3127
+ ...params.filters ? { filters: params.filters } : {},
3128
+ ...params.serverPaginated ? { page, limit: perPage } : {}
3129
+ });
3130
+ useGlobalRealtime(
3131
+ useCallback7(() => {
3132
+ void refetch();
3133
+ }, [refetch])
3134
+ );
3135
+ const now = useMemo4(() => Date.now(), [conversations]);
3136
+ const filtered = useMemo4(
3137
+ () => conversations.filter(
3138
+ (conversation) => channelFilter === CHANNEL_FILTER_ALL || (conversation.channel ?? DEFAULT_CONVERSATION_CHANNEL) === channelFilter
3139
+ ).filter(
3140
+ (conversation) => windowFilter === CONVERSATION_WINDOW.ALL || windowOf({ lastInboundAt: conversation.lastInboundAt, now, channel: conversation.channel }) === windowFilter
3141
+ ),
3142
+ [conversations, windowFilter, channelFilter, now]
3143
+ );
3144
+ const totalForPaging = params.serverPaginated ? total : filtered.length;
3145
+ const pageCount = Math.max(1, Math.ceil(totalForPaging / perPage));
3146
+ const currentPage = Math.min(page, pageCount);
3147
+ const pageConversations = params.serverPaginated ? filtered : filtered.slice((currentPage - 1) * perPage, currentPage * perPage);
3148
+ useEffect9(() => {
3149
+ setPage(1);
3150
+ }, [search, waitingOnly, windowFilter, channelFilter]);
3151
+ useEffect9(() => {
3152
+ if (selectedId && !conversations.some((conversation) => conversation.id === selectedId)) {
3153
+ setSelectedId(void 0);
3154
+ }
3155
+ }, [conversations, selectedId]);
3156
+ const lastMarkReadAttempt = useRef7(void 0);
3157
+ useEffect9(() => {
3158
+ if (!markReadOnOpen || !selectedId) return;
3159
+ const opened = conversations.find((conversation) => conversation.id === selectedId);
3160
+ if (!opened || opened.unread === 0) return;
3161
+ const attempt = `${selectedId}:${opened.unread}`;
3162
+ if (lastMarkReadAttempt.current === attempt) return;
3163
+ lastMarkReadAttempt.current = attempt;
3164
+ void api.markRead(selectedId).then(() => refetch()).catch(() => {
3165
+ });
3166
+ }, [markReadOnOpen, selectedId, conversations, refetch, api]);
3167
+ const toggleSelected = useCallback7((conversationId) => {
3168
+ setSelectedIds((current) => {
3169
+ const next = new Set(current);
3170
+ if (next.has(conversationId)) next.delete(conversationId);
3171
+ else next.add(conversationId);
3172
+ return next;
3173
+ });
3174
+ }, []);
3175
+ const pageIds = pageConversations.map((conversation) => conversation.id);
3176
+ const allOnPageSelected = pageIds.length > 0 && pageIds.every((id) => selectedIds.has(id));
3177
+ const toggleSelectAllOnPage = useCallback7(() => {
3178
+ setSelectedIds((current) => {
3179
+ const next = new Set(current);
3180
+ if (allOnPageSelected) pageIds.forEach((id) => next.delete(id));
3181
+ else pageIds.forEach((id) => next.add(id));
3182
+ return next;
3183
+ });
3184
+ }, [allOnPageSelected, pageIds]);
3185
+ const runOnSelection = useCallback7(
3186
+ async (action) => {
3187
+ setBusy(true);
3188
+ try {
3189
+ await Promise.all([...selectedIds].map(action));
3190
+ setSelectedIds(/* @__PURE__ */ new Set());
3191
+ await refetch();
3192
+ } finally {
3193
+ setBusy(false);
3194
+ }
3195
+ },
3196
+ [selectedIds, refetch]
3197
+ );
3198
+ const runConversationAction = useCallback7(
3199
+ async (action, conversationId) => {
3200
+ if (!action) return;
3201
+ setBusy(true);
3202
+ try {
3203
+ await action(conversationId);
3204
+ await refetch();
3205
+ } finally {
3206
+ setBusy(false);
3207
+ }
3208
+ },
3209
+ [refetch]
3210
+ );
3211
+ return {
3212
+ conversations,
3213
+ pageConversations,
3214
+ selectedConversation: conversations.find((conversation) => conversation.id === selectedId),
3215
+ loading,
3216
+ now,
3217
+ totalCount: conversations.length,
3218
+ unreadCount: conversations.reduce((total2, conversation) => total2 + conversation.unread, 0),
3219
+ waitingCount: conversations.filter((conversation) => conversation.waitingHuman).length,
3220
+ filteredCount: totalForPaging,
3221
+ expiredSelectedCount: conversations.filter(
3222
+ (conversation) => selectedIds.has(conversation.id) && isWindowBlocking(windowOf({ lastInboundAt: conversation.lastInboundAt, now, channel: conversation.channel }))
3223
+ ).length,
3224
+ page: currentPage,
3225
+ pageCount,
3226
+ firstOnPage: (currentPage - 1) * perPage + 1,
3227
+ lastOnPage: Math.min(currentPage * perPage, totalForPaging),
3228
+ selectedId,
3229
+ selectedIds,
3230
+ allOnPageSelected,
3231
+ waitingOnly,
3232
+ windowFilter,
3233
+ channelFilter,
3234
+ channelFilters: channelFiltersFor(conversations),
3235
+ search,
3236
+ busy,
3237
+ loadFailure: error ? describeFailure(error) : void 0,
3238
+ canTakeover: Boolean(api.takeover),
3239
+ canFinalize: Boolean(api.finalize),
3240
+ canListTemplates: Boolean(api.listTemplates),
3241
+ canMarkAllRead: Boolean(api.markAllRead),
3242
+ refetch,
3243
+ selectConversation: setSelectedId,
3244
+ clearSelection: () => setSelectedId(void 0),
3245
+ toggleSelected,
3246
+ toggleSelectAllOnPage,
3247
+ clearBulkSelection: () => setSelectedIds(/* @__PURE__ */ new Set()),
3248
+ setWaitingOnly,
3249
+ setWindowFilter,
3250
+ setChannelFilter,
3251
+ setSearch,
3252
+ goToPage: setPage,
3253
+ markSelectedAsRead: () => runOnSelection((conversationId) => api.markRead(conversationId)),
3254
+ markAllAsRead: async () => {
3255
+ if (!api.markAllRead) return;
3256
+ setBusy(true);
3257
+ try {
3258
+ await api.markAllRead();
3259
+ await refetch();
3260
+ } finally {
3261
+ setBusy(false);
3262
+ }
3263
+ },
3264
+ takeover: (conversationId) => runConversationAction(api.takeover, conversationId),
3265
+ releaseToBot: (conversationId) => runConversationAction(api.release, conversationId),
3266
+ finalize: (conversationId) => runConversationAction(api.finalize, conversationId),
3267
+ finalizeSelected: () => runOnSelection(async (conversationId) => {
3268
+ await api.finalize?.(conversationId);
3269
+ }),
3270
+ sendTemplateToSelected: (templateName) => runOnSelection(async (conversationId) => {
3271
+ await api.sendTemplate(conversationId, templateName ? { templateName } : {});
3272
+ })
3273
+ };
3274
+ }
3275
+
3276
+ // src/workspace/ConversationsWorkspace.tsx
3277
+ import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
3278
+ function ConversationsWorkspace({
3279
+ labels: labelsOverride,
3280
+ filters,
3281
+ perPage,
3282
+ markReadOnOpen,
3283
+ serverPaginated,
3284
+ initialConversationId,
3285
+ initialWhatsappNumber,
3286
+ simulator,
3287
+ quickReplies,
3288
+ quickReplyVariablesFor,
3289
+ flowLabelOf,
3290
+ onDownload,
3291
+ requireTakeoverToReply,
3292
+ messageSelection,
3293
+ initialComposerText,
3294
+ composer,
3295
+ composerVariablesFor,
3296
+ onSendAttachments,
3297
+ onRecordAudio,
3298
+ contextEntriesOf,
3299
+ onAttach,
3300
+ extraUtilitiesFor,
3301
+ renderFilters,
3302
+ renderBulkActions,
3303
+ renderRow,
3304
+ renderAboveTranscript,
3305
+ renderHeaderActions,
3306
+ onSendTemplateToSelected,
3307
+ signInHref,
3308
+ className
3309
+ }) {
3310
+ const labels = { ...DEFAULT_CONVERSATIONS_WORKSPACE_LABELS, ...labelsOverride };
3311
+ const inbox = useConversationsInbox({
3312
+ ...filters ? { filters } : {},
3313
+ ...perPage ? { perPage } : {},
3314
+ ...markReadOnOpen === void 0 ? {} : { markReadOnOpen },
3315
+ ...serverPaginated ? { serverPaginated } : {}
3316
+ });
3317
+ const [simulatorOpen, setSimulatorOpen] = useState14(false);
3318
+ const [templateModalOpen, setTemplateModalOpen] = useState14(false);
3319
+ const [openedFromLink, setOpenedFromLink] = useState14(void 0);
3320
+ useEffect10(() => {
3321
+ const link = initialConversationId ?? initialWhatsappNumber;
3322
+ if (!link || openedFromLink === link) return;
3323
+ const target = inbox.conversations.find(
3324
+ (conversation) => conversation.id === initialConversationId || conversation.whatsappNumber === initialWhatsappNumber
3325
+ );
3326
+ if (!target) return;
3327
+ inbox.selectConversation(target.id);
3328
+ setOpenedFromLink(link);
3329
+ }, [initialConversationId, initialWhatsappNumber, openedFromLink, inbox]);
3330
+ const selected = inbox.selectedConversation;
3331
+ const simulatorEnabled = Boolean(simulator && (simulator.enabled ?? true));
3332
+ const showSimulator = simulatorEnabled && simulatorOpen && Boolean(selected);
3333
+ const paneUtilities = useMemo5(() => {
3334
+ if (!selected) return void 0;
3335
+ const fromProduct = extraUtilitiesFor?.(selected) ?? [];
3336
+ if (!simulatorEnabled) return fromProduct;
3337
+ return [
3338
+ ...fromProduct,
3339
+ {
3340
+ key: "simulator",
3341
+ icon: simulator?.icon ?? "\u{1F9EA}",
3342
+ label: simulator?.label ?? "Simular cliente",
3343
+ active: simulatorOpen,
3344
+ run: () => setSimulatorOpen((open) => !open)
3345
+ }
3346
+ ];
3347
+ }, [selected, extraUtilitiesFor, simulatorEnabled, simulator, simulatorOpen]);
3348
+ return /* @__PURE__ */ jsxs22("div", { className: `cv-workspace${className ? ` ${className}` : ""}`, children: [
3349
+ /* @__PURE__ */ jsxs22("header", { className: "cv-workspace-header", children: [
3350
+ /* @__PURE__ */ jsxs22("div", { className: "cv-workspace-header__titles", children: [
3351
+ /* @__PURE__ */ jsx24("h1", { children: labels.title }),
3352
+ /* @__PURE__ */ jsxs22("p", { children: [
3353
+ /* @__PURE__ */ jsxs22("span", { title: labels.conversations, children: [
3354
+ "\u{1F4AC} ",
3355
+ inbox.totalCount,
3356
+ /* @__PURE__ */ jsxs22("span", { className: "cv-only-wide", children: [
3357
+ " ",
3358
+ labels.conversations
3359
+ ] })
3360
+ ] }),
3361
+ /* @__PURE__ */ jsxs22("span", { title: labels.waiting, className: "cv-workspace-header__waiting", children: [
3362
+ "\u23F3 ",
3363
+ inbox.waitingCount,
3364
+ /* @__PURE__ */ jsxs22("span", { className: "cv-only-wide", children: [
3365
+ " ",
3366
+ labels.waiting
3367
+ ] })
3368
+ ] }),
3369
+ /* @__PURE__ */ jsxs22("span", { title: labels.unread, children: [
3370
+ "\u2709\uFE0F ",
3371
+ inbox.unreadCount,
3372
+ /* @__PURE__ */ jsxs22("span", { className: "cv-only-wide", children: [
3373
+ " ",
3374
+ labels.unread
3375
+ ] })
3376
+ ] })
3377
+ ] })
3378
+ ] }),
3379
+ /* @__PURE__ */ jsxs22("div", { className: "cv-workspace-header__actions", children: [
3380
+ /* @__PURE__ */ jsxs22(
3381
+ "button",
3382
+ {
3383
+ type: "button",
3384
+ onClick: () => inbox.setWaitingOnly(!inbox.waitingOnly),
3385
+ "aria-pressed": inbox.waitingOnly,
3386
+ title: labels.waitingOnly,
3387
+ className: inbox.waitingOnly ? "cv-workspace-toggle cv-workspace-toggle--on" : "cv-workspace-toggle",
3388
+ children: [
3389
+ "\u23F3",
3390
+ /* @__PURE__ */ jsxs22("span", { className: "cv-only-wide", children: [
3391
+ " ",
3392
+ labels.waitingOnly
3393
+ ] })
3394
+ ]
3395
+ }
3396
+ ),
3397
+ /* @__PURE__ */ jsxs22(
3398
+ "button",
3399
+ {
3400
+ type: "button",
3401
+ onClick: () => void inbox.markSelectedAsRead(),
3402
+ disabled: inbox.selectedIds.size === 0 || inbox.busy,
3403
+ title: labels.markSelectedAsRead,
3404
+ "aria-label": labels.markSelectedAsRead,
3405
+ className: "cv-workspace-toggle",
3406
+ children: [
3407
+ "\u2713",
3408
+ /* @__PURE__ */ jsxs22("span", { className: "cv-only-wide", children: [
3409
+ " ",
3410
+ labels.markSelectedAsRead
3411
+ ] }),
3412
+ inbox.selectedIds.size > 0 ? ` (${inbox.selectedIds.size})` : ""
3413
+ ]
3414
+ }
3415
+ ),
3416
+ inbox.canMarkAllRead && inbox.unreadCount > 0 ? /* @__PURE__ */ jsxs22(
3417
+ "button",
3418
+ {
3419
+ type: "button",
3420
+ onClick: () => void inbox.markAllAsRead(),
3421
+ disabled: inbox.busy,
3422
+ title: labels.markAllAsRead,
3423
+ className: "cv-workspace-toggle",
3424
+ children: [
3425
+ "\u2713\u2713",
3426
+ /* @__PURE__ */ jsxs22("span", { className: "cv-only-wide", children: [
3427
+ " ",
3428
+ labels.markAllAsRead
3429
+ ] })
3430
+ ]
3431
+ }
3432
+ ) : null,
3433
+ renderHeaderActions?.(inbox)
3434
+ ] })
3435
+ ] }),
3436
+ inbox.loadFailure ? /* @__PURE__ */ jsxs22("p", { role: "alert", className: "cv-workspace-failure", children: [
3437
+ inbox.loadFailure,
3438
+ signInHref ? /* @__PURE__ */ jsxs22(Fragment4, { children: [
3439
+ " ",
3440
+ /* @__PURE__ */ jsx24("a", { href: signInHref, className: "cv-workspace-failure__link", children: labels.signIn })
3441
+ ] }) : null
3442
+ ] }) : null,
3443
+ /* @__PURE__ */ jsxs22(
3444
+ "div",
3445
+ {
3446
+ className: `cv-workspace-grid${showSimulator ? " cv-workspace-grid--with-simulator" : ""}`,
3447
+ "data-detail": selected ? "open" : "closed",
3448
+ children: [
3449
+ /* @__PURE__ */ jsx24(
3450
+ ConversationsInboxList,
3451
+ {
3452
+ inbox,
3453
+ labels,
3454
+ className: "cv-workspace-list",
3455
+ ...renderFilters ? { renderFilters } : {},
3456
+ ...renderBulkActions ? { renderBulkActions } : {},
3457
+ ...renderRow ? { renderRow } : {},
3458
+ ...onSendTemplateToSelected ? { onSendTemplateToSelected: () => onSendTemplateToSelected(inbox) } : inbox.canListTemplates ? { onSendTemplateToSelected: () => setTemplateModalOpen(true) } : {}
3459
+ }
3460
+ ),
3461
+ /* @__PURE__ */ jsx24("section", { className: "cv-workspace-detail", children: selected ? /* @__PURE__ */ jsx24(
3462
+ ConversationPane,
3463
+ {
3464
+ conversation: selected,
3465
+ now: inbox.now,
3466
+ busy: inbox.busy,
3467
+ labels,
3468
+ ...inbox.canTakeover ? { onTakeover: () => void inbox.takeover(selected.id) } : {},
3469
+ ...inbox.canTakeover ? { onReturnToBot: () => void inbox.releaseToBot(selected.id) } : {},
3470
+ ...inbox.canFinalize ? { onFinish: () => void inbox.finalize(selected.id) } : {},
3471
+ ...flowLabelOf ? { flowLabel: flowLabelOf(selected) } : {},
3472
+ ...onDownload ? { onDownload: () => onDownload(selected) } : {},
3473
+ ...requireTakeoverToReply ? { requireTakeoverToReply } : {},
3474
+ ...messageSelection ? { messageSelection } : {},
3475
+ ...initialComposerText ? { initialComposerText } : {},
3476
+ ...composer ? { composer } : {},
3477
+ ...composerVariablesFor ? { composerVariablesFor } : {},
3478
+ ...onSendAttachments ? {
3479
+ onSendAttachments: (files, caption) => onSendAttachments(selected, files, caption)
3480
+ } : {},
3481
+ ...onRecordAudio ? { onRecordAudio: (file) => onRecordAudio(selected, file) } : {},
3482
+ onBack: inbox.clearSelection,
3483
+ ...paneUtilities ? { extraUtilities: paneUtilities } : {},
3484
+ ...contextEntriesOf ? { contextEntriesOf } : {},
3485
+ ...quickReplies ? { quickReplies } : {},
3486
+ ...quickReplyVariablesFor ? { quickReplyVariablesFor } : {},
3487
+ ...renderAboveTranscript ? { renderAboveTranscript } : {},
3488
+ ...onAttach ? { onAttach: (file) => onAttach(selected, file) } : {}
3489
+ }
3490
+ ) : /* @__PURE__ */ jsx24("p", { className: "cv-workspace-empty", children: labels.emptyDetail }) }),
3491
+ showSimulator && selected ? (
3492
+ // `min-height:0` junto do `min-width:0`: sem isso a linha do grid cresce com o conteúdo do
3493
+ // painel, o scroll interno nunca ativa e quem rola passa a ser a página inteira.
3494
+ /* @__PURE__ */ jsx24("div", { className: "cv-workspace-simulator", children: simulator?.render({ conversationId: selected.id, close: () => setSimulatorOpen(false) }) })
3495
+ ) : null
3496
+ ]
3497
+ }
3498
+ ),
3499
+ templateModalOpen ? /* @__PURE__ */ jsx24(
3500
+ BulkTemplateModal,
3501
+ {
3502
+ labels,
3503
+ expiredCount: inbox.expiredSelectedCount,
3504
+ sending: inbox.busy,
3505
+ onClose: () => setTemplateModalOpen(false),
3506
+ onSend: (templateName) => {
3507
+ void inbox.sendTemplateToSelected(templateName).then(() => setTemplateModalOpen(false));
3508
+ }
3509
+ }
3510
+ ) : null
3511
+ ] });
3512
+ }
2589
3513
  export {
2590
3514
  AudioPlayer,
2591
3515
  AudioRecorderButton,
@@ -2594,6 +3518,7 @@ export {
2594
3518
  CHANNEL_BRAND_COLOR,
2595
3519
  CHANNEL_CAPABILITIES,
2596
3520
  CHANNEL_FILTER_ALL,
3521
+ CONVERSATIONS_PER_PAGE,
2597
3522
  CONVERSATION_CHANNEL,
2598
3523
  CONVERSATION_WINDOW,
2599
3524
  ChannelIcon,
@@ -2602,12 +3527,16 @@ export {
2602
3527
  ConversationHeader,
2603
3528
  ConversationListItem,
2604
3529
  ConversationLocalesProvider,
3530
+ ConversationPane,
2605
3531
  ConversationRow,
2606
3532
  ConversationWallpaper,
3533
+ ConversationsInboxList,
2607
3534
  ConversationsProvider,
3535
+ ConversationsWorkspace,
2608
3536
  DEFAULT_ACCEPTED_FILE_TYPES,
2609
3537
  DEFAULT_AUDIO_RECORDER_BUTTON_LABELS,
2610
3538
  DEFAULT_AVATAR_LABELS,
3539
+ DEFAULT_CONVERSATIONS_WORKSPACE_LABELS,
2611
3540
  DEFAULT_CONVERSATION_CHANNEL,
2612
3541
  DEFAULT_CONVERSATION_CONTEXT_LABELS,
2613
3542
  DEFAULT_CONVERSATION_DOCUMENTS_LABELS,
@@ -2685,6 +3614,7 @@ export {
2685
3614
  useConversationMessages,
2686
3615
  useConversationRealtime,
2687
3616
  useConversations,
3617
+ useConversationsInbox,
2688
3618
  useDarkMode,
2689
3619
  useGlobalRealtime,
2690
3620
  useInboxActions,