@greatapps/greatchat-ui 0.1.4 → 0.1.6

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
@@ -2474,19 +2474,1711 @@ function NewConversationDialog({
2474
2474
  ] })
2475
2475
  ] }) });
2476
2476
  }
2477
+
2478
+ // src/components/whatsapp-status-badge.tsx
2479
+ import { jsx as jsx24 } from "react/jsx-runtime";
2480
+ function WhatsappStatusBadge({
2481
+ status,
2482
+ hasSession
2483
+ }) {
2484
+ if (!hasSession) {
2485
+ return /* @__PURE__ */ jsx24(Badge, { variant: "outline", className: "text-xs text-zinc-500 border-zinc-300", children: "Sem sess\xE3o" });
2486
+ }
2487
+ if (!status) {
2488
+ return /* @__PURE__ */ jsx24(Badge, { variant: "outline", className: "text-xs text-zinc-500 border-zinc-300", children: "Verificando..." });
2489
+ }
2490
+ if (status.connected && status.logged_in) {
2491
+ return /* @__PURE__ */ jsx24(
2492
+ Badge,
2493
+ {
2494
+ variant: "outline",
2495
+ className: "text-xs bg-green-500/10 text-green-600 border-green-200",
2496
+ children: "Conectado"
2497
+ }
2498
+ );
2499
+ }
2500
+ if (status.connected && !status.logged_in) {
2501
+ return /* @__PURE__ */ jsx24(
2502
+ Badge,
2503
+ {
2504
+ variant: "outline",
2505
+ className: "text-xs bg-yellow-500/10 text-yellow-600 border-yellow-200",
2506
+ children: "Reconectando..."
2507
+ }
2508
+ );
2509
+ }
2510
+ if (status.logged_in && !status.connected) {
2511
+ return /* @__PURE__ */ jsx24(
2512
+ Badge,
2513
+ {
2514
+ variant: "outline",
2515
+ className: "text-xs bg-yellow-500/10 text-yellow-600 border-yellow-200",
2516
+ children: "Desconectado"
2517
+ }
2518
+ );
2519
+ }
2520
+ return /* @__PURE__ */ jsx24(
2521
+ Badge,
2522
+ {
2523
+ variant: "outline",
2524
+ className: "text-xs bg-red-500/10 text-red-600 border-red-200",
2525
+ children: "Offline"
2526
+ }
2527
+ );
2528
+ }
2529
+
2530
+ // src/components/channel-card.tsx
2531
+ import { jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
2532
+ function ChannelCard({
2533
+ channel,
2534
+ config,
2535
+ onEdit,
2536
+ onDelete,
2537
+ linkedAgentName,
2538
+ linkedAgentActive = true,
2539
+ actions
2540
+ }) {
2541
+ const { data: status } = useChannelWhatsappStatus(config, channel.id);
2542
+ const hasSession = !!channel.external_id;
2543
+ return /* @__PURE__ */ jsxs14("div", { className: "rounded-lg border bg-card text-card-foreground shadow-sm", children: [
2544
+ /* @__PURE__ */ jsxs14("div", { className: "flex flex-row items-start justify-between p-4 pb-2", children: [
2545
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
2546
+ /* @__PURE__ */ jsx25("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-green-500/10", children: /* @__PURE__ */ jsx25("svg", { className: "h-5 w-5 text-green-600", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx25("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }) }),
2547
+ /* @__PURE__ */ jsxs14("div", { children: [
2548
+ /* @__PURE__ */ jsx25("h3", { className: "text-sm font-medium", children: channel.name }),
2549
+ /* @__PURE__ */ jsx25("p", { className: "text-xs text-muted-foreground", children: channel.identifier || "Sem n\xFAmero" })
2550
+ ] })
2551
+ ] }),
2552
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1", children: [
2553
+ onEdit && /* @__PURE__ */ jsx25(
2554
+ Button,
2555
+ {
2556
+ variant: "ghost",
2557
+ size: "icon",
2558
+ className: "h-7 w-7",
2559
+ onClick: onEdit,
2560
+ children: /* @__PURE__ */ jsxs14("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2561
+ /* @__PURE__ */ jsx25("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }),
2562
+ /* @__PURE__ */ jsx25("path", { d: "m15 5 4 4" })
2563
+ ] })
2564
+ }
2565
+ ),
2566
+ onDelete && /* @__PURE__ */ jsx25(
2567
+ Button,
2568
+ {
2569
+ variant: "ghost",
2570
+ size: "icon",
2571
+ className: "h-7 w-7 text-destructive hover:text-destructive",
2572
+ onClick: onDelete,
2573
+ children: /* @__PURE__ */ jsxs14("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2574
+ /* @__PURE__ */ jsx25("path", { d: "M3 6h18" }),
2575
+ /* @__PURE__ */ jsx25("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
2576
+ /* @__PURE__ */ jsx25("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })
2577
+ ] })
2578
+ }
2579
+ ),
2580
+ /* @__PURE__ */ jsx25(WhatsappStatusBadge, { status, hasSession })
2581
+ ] })
2582
+ ] }),
2583
+ /* @__PURE__ */ jsxs14("div", { className: "p-4 pt-0 space-y-3", children: [
2584
+ linkedAgentName && /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
2585
+ /* @__PURE__ */ jsxs14("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2586
+ /* @__PURE__ */ jsx25("path", { d: "M12 8V4H8" }),
2587
+ /* @__PURE__ */ jsx25("rect", { width: "16", height: "12", x: "4", y: "8", rx: "2" }),
2588
+ /* @__PURE__ */ jsx25("path", { d: "M2 14h2" }),
2589
+ /* @__PURE__ */ jsx25("path", { d: "M20 14h2" }),
2590
+ /* @__PURE__ */ jsx25("path", { d: "M15 13v2" }),
2591
+ /* @__PURE__ */ jsx25("path", { d: "M9 13v2" })
2592
+ ] }),
2593
+ /* @__PURE__ */ jsxs14("span", { children: [
2594
+ "Agent: ",
2595
+ /* @__PURE__ */ jsx25("strong", { children: linkedAgentName })
2596
+ ] }),
2597
+ !linkedAgentActive && /* @__PURE__ */ jsx25("span", { className: "text-[10px] px-1 py-0 border rounded", children: "inativo" })
2598
+ ] }),
2599
+ actions
2600
+ ] })
2601
+ ] });
2602
+ }
2603
+
2604
+ // src/components/whatsapp-icon.tsx
2605
+ import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
2606
+ function WhatsappIcon(props) {
2607
+ return /* @__PURE__ */ jsxs15(
2608
+ "svg",
2609
+ {
2610
+ xmlns: "http://www.w3.org/2000/svg",
2611
+ width: "24",
2612
+ height: "24",
2613
+ viewBox: "0 0 24 24",
2614
+ fill: "none",
2615
+ stroke: "currentColor",
2616
+ strokeWidth: 2,
2617
+ strokeLinecap: "round",
2618
+ strokeLinejoin: "round",
2619
+ ...props,
2620
+ children: [
2621
+ /* @__PURE__ */ jsx26("path", { d: "M3 21l1.65 -3.8a9 9 0 1 1 3.4 2.9l-5.05 .9" }),
2622
+ /* @__PURE__ */ jsx26("path", { d: "M9 10a.5 .5 0 0 0 1 0v-1a.5 .5 0 0 0 -1 0v1a5 5 0 0 0 5 5h1a.5 .5 0 0 0 0 -1h-1a.5 .5 0 0 0 0 1" })
2623
+ ]
2624
+ }
2625
+ );
2626
+ }
2627
+
2628
+ // src/components/whatsapp-qr-dialog.tsx
2629
+ import { useEffect as useEffect3, useState as useState6, useCallback as useCallback2 } from "react";
2630
+ import { Loader2 as Loader22, Check as Check4, AlertCircle as AlertCircle2, RefreshCw } from "lucide-react";
2631
+ import { toast } from "sonner";
2632
+ import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
2633
+ function WhatsappQrDialog({
2634
+ open,
2635
+ onOpenChange,
2636
+ channelId,
2637
+ config
2638
+ }) {
2639
+ const connectChannel = useConnectChannel(config);
2640
+ const [state, setState] = useState6("connecting");
2641
+ const [errorMsg, setErrorMsg] = useState6("");
2642
+ const { data: qrUrl } = useChannelQR(
2643
+ config,
2644
+ channelId,
2645
+ open && (state === "waiting_qr" || state === "showing_qr")
2646
+ );
2647
+ const { data: status } = useChannelWhatsappStatus(
2648
+ config,
2649
+ channelId,
2650
+ open && state !== "connected"
2651
+ );
2652
+ const startConnect = useCallback2(() => {
2653
+ setState("connecting");
2654
+ setErrorMsg("");
2655
+ connectChannel.mutate(channelId, {
2656
+ onSuccess: () => setState("waiting_qr"),
2657
+ onError: (err) => {
2658
+ setState("error");
2659
+ setErrorMsg(err.message || "Erro ao conectar");
2660
+ }
2661
+ });
2662
+ }, [channelId, connectChannel]);
2663
+ useEffect3(() => {
2664
+ if (!open) {
2665
+ setState("connecting");
2666
+ setErrorMsg("");
2667
+ return;
2668
+ }
2669
+ startConnect();
2670
+ }, [open, channelId]);
2671
+ useEffect3(() => {
2672
+ if (qrUrl && (state === "waiting_qr" || state === "showing_qr")) {
2673
+ setState("showing_qr");
2674
+ }
2675
+ }, [qrUrl, state]);
2676
+ useEffect3(() => {
2677
+ if (status?.connected && status?.logged_in) {
2678
+ setState("connected");
2679
+ toast.success("WhatsApp conectado com sucesso!");
2680
+ setTimeout(() => onOpenChange(false), 1500);
2681
+ }
2682
+ }, [status, onOpenChange]);
2683
+ return /* @__PURE__ */ jsx27(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs16(DialogContent, { className: "sm:max-w-md", children: [
2684
+ /* @__PURE__ */ jsxs16(DialogHeader, { children: [
2685
+ /* @__PURE__ */ jsx27(DialogTitle, { children: "Conectar WhatsApp" }),
2686
+ /* @__PURE__ */ jsx27(DialogDescription, { children: "Escaneie o QR code com seu WhatsApp para conectar" })
2687
+ ] }),
2688
+ /* @__PURE__ */ jsxs16("div", { className: "flex min-h-[300px] items-center justify-center", children: [
2689
+ state === "connecting" && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-3 text-muted-foreground", children: [
2690
+ /* @__PURE__ */ jsx27(Loader22, { className: "h-8 w-8 animate-spin" }),
2691
+ /* @__PURE__ */ jsx27("p", { className: "text-sm", children: "Iniciando conex\xE3o..." })
2692
+ ] }),
2693
+ state === "waiting_qr" && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-3 text-muted-foreground", children: [
2694
+ /* @__PURE__ */ jsx27(Loader22, { className: "h-8 w-8 animate-spin" }),
2695
+ /* @__PURE__ */ jsx27("p", { className: "text-sm", children: "Gerando QR code..." })
2696
+ ] }),
2697
+ state === "showing_qr" && qrUrl && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-3", children: [
2698
+ /* @__PURE__ */ jsx27(
2699
+ "img",
2700
+ {
2701
+ src: qrUrl,
2702
+ alt: "QR Code WhatsApp",
2703
+ className: "h-64 w-64 rounded-lg border"
2704
+ }
2705
+ ),
2706
+ /* @__PURE__ */ jsx27("p", { className: "text-sm text-muted-foreground", children: "Abra o WhatsApp > Aparelhos conectados > Conectar" })
2707
+ ] }),
2708
+ state === "connected" && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-3 text-green-600", children: [
2709
+ /* @__PURE__ */ jsx27(Check4, { className: "h-12 w-12" }),
2710
+ /* @__PURE__ */ jsx27("p", { className: "text-lg font-medium", children: "Conectado!" })
2711
+ ] }),
2712
+ state === "error" && /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-3 text-destructive", children: [
2713
+ /* @__PURE__ */ jsx27(AlertCircle2, { className: "h-8 w-8" }),
2714
+ /* @__PURE__ */ jsx27("p", { className: "text-sm", children: errorMsg || "Erro ao gerar QR code" }),
2715
+ /* @__PURE__ */ jsxs16(
2716
+ Button,
2717
+ {
2718
+ variant: "outline",
2719
+ size: "sm",
2720
+ onClick: startConnect,
2721
+ children: [
2722
+ /* @__PURE__ */ jsx27(RefreshCw, { className: "mr-2 h-4 w-4" }),
2723
+ "Tentar novamente"
2724
+ ]
2725
+ }
2726
+ )
2727
+ ] })
2728
+ ] })
2729
+ ] }) });
2730
+ }
2731
+
2732
+ // src/components/channel-create-dialog.tsx
2733
+ import { useState as useState7 } from "react";
2734
+
2735
+ // src/components/ui/label.tsx
2736
+ import { Label as LabelPrimitive } from "radix-ui";
2737
+ import { jsx as jsx28 } from "react/jsx-runtime";
2738
+ function Label({
2739
+ className,
2740
+ ...props
2741
+ }) {
2742
+ return /* @__PURE__ */ jsx28(
2743
+ LabelPrimitive.Root,
2744
+ {
2745
+ "data-slot": "label",
2746
+ className: cn(
2747
+ "gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
2748
+ className
2749
+ ),
2750
+ ...props
2751
+ }
2752
+ );
2753
+ }
2754
+
2755
+ // src/components/channel-create-dialog.tsx
2756
+ import { Loader2 as Loader23 } from "lucide-react";
2757
+ import { toast as toast2 } from "sonner";
2758
+ import { jsx as jsx29, jsxs as jsxs17 } from "react/jsx-runtime";
2759
+ function ChannelCreateDialog({
2760
+ open,
2761
+ onOpenChange,
2762
+ config,
2763
+ renderAgentSelect
2764
+ }) {
2765
+ const createChannel = useCreateChannel(config);
2766
+ const [name, setName] = useState7("");
2767
+ const [identifier, setIdentifier] = useState7("");
2768
+ const [idAgent, setIdAgent] = useState7(null);
2769
+ async function handleSubmit(e) {
2770
+ e.preventDefault();
2771
+ if (!name.trim()) return;
2772
+ try {
2773
+ await createChannel.mutateAsync({
2774
+ name: name.trim(),
2775
+ type: "whatsapp_unofficial",
2776
+ provider: "gwhatsmeow",
2777
+ identifier: identifier.trim() || void 0,
2778
+ id_agent: idAgent
2779
+ });
2780
+ toast2.success("Canal criado! Agora conecte via QR code.");
2781
+ setName("");
2782
+ setIdentifier("");
2783
+ setIdAgent(null);
2784
+ onOpenChange(false);
2785
+ } catch {
2786
+ toast2.error("Erro ao criar canal");
2787
+ }
2788
+ }
2789
+ return /* @__PURE__ */ jsx29(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs17(DialogContent, { children: [
2790
+ /* @__PURE__ */ jsx29(DialogHeader, { children: /* @__PURE__ */ jsxs17(DialogTitle, { className: "flex items-center gap-2", children: [
2791
+ /* @__PURE__ */ jsx29(WhatsappIcon, { className: "h-5 w-5 text-green-600" }),
2792
+ "Novo Canal WhatsApp"
2793
+ ] }) }),
2794
+ /* @__PURE__ */ jsxs17("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
2795
+ /* @__PURE__ */ jsxs17("div", { className: "space-y-2", children: [
2796
+ /* @__PURE__ */ jsx29(Label, { htmlFor: "channel-name", children: "Nome do canal *" }),
2797
+ /* @__PURE__ */ jsx29(
2798
+ Input,
2799
+ {
2800
+ id: "channel-name",
2801
+ value: name,
2802
+ onChange: (e) => setName(e.target.value),
2803
+ placeholder: "Ex: WhatsApp Principal",
2804
+ required: true,
2805
+ disabled: createChannel.isPending
2806
+ }
2807
+ )
2808
+ ] }),
2809
+ /* @__PURE__ */ jsxs17("div", { className: "space-y-2", children: [
2810
+ /* @__PURE__ */ jsx29(Label, { htmlFor: "channel-identifier", children: "N\xFAmero do WhatsApp (opcional)" }),
2811
+ /* @__PURE__ */ jsx29(
2812
+ Input,
2813
+ {
2814
+ id: "channel-identifier",
2815
+ value: identifier,
2816
+ onChange: (e) => setIdentifier(e.target.value),
2817
+ placeholder: "5511999999999",
2818
+ disabled: createChannel.isPending
2819
+ }
2820
+ ),
2821
+ /* @__PURE__ */ jsx29("p", { className: "text-xs text-muted-foreground", children: "Ser\xE1 detectado automaticamente ao escanear o QR code" })
2822
+ ] }),
2823
+ renderAgentSelect?.({
2824
+ value: idAgent,
2825
+ onChange: setIdAgent,
2826
+ disabled: createChannel.isPending
2827
+ }),
2828
+ /* @__PURE__ */ jsxs17(DialogFooter, { children: [
2829
+ /* @__PURE__ */ jsx29(
2830
+ Button,
2831
+ {
2832
+ type: "button",
2833
+ variant: "outline",
2834
+ onClick: () => onOpenChange(false),
2835
+ disabled: createChannel.isPending,
2836
+ children: "Cancelar"
2837
+ }
2838
+ ),
2839
+ /* @__PURE__ */ jsxs17(Button, { type: "submit", disabled: createChannel.isPending || !name.trim(), children: [
2840
+ createChannel.isPending && /* @__PURE__ */ jsx29(Loader23, { className: "mr-2 h-4 w-4 animate-spin" }),
2841
+ "Criar Canal"
2842
+ ] })
2843
+ ] })
2844
+ ] })
2845
+ ] }) });
2846
+ }
2847
+
2848
+ // src/components/channel-edit-dialog.tsx
2849
+ import { useState as useState8, useEffect as useEffect4 } from "react";
2850
+ import { Loader2 as Loader24 } from "lucide-react";
2851
+ import { toast as toast3 } from "sonner";
2852
+ import { jsx as jsx30, jsxs as jsxs18 } from "react/jsx-runtime";
2853
+ function ChannelEditDialog({
2854
+ open,
2855
+ onOpenChange,
2856
+ channel,
2857
+ config,
2858
+ renderAgentSelect
2859
+ }) {
2860
+ const updateChannel = useUpdateChannel(config);
2861
+ const [name, setName] = useState8(channel.name);
2862
+ const [identifier, setIdentifier] = useState8(channel.identifier || "");
2863
+ const [idAgent, setIdAgent] = useState8(channel.id_agent);
2864
+ useEffect4(() => {
2865
+ if (open) {
2866
+ setName(channel.name);
2867
+ setIdentifier(channel.identifier || "");
2868
+ setIdAgent(channel.id_agent);
2869
+ }
2870
+ }, [open, channel]);
2871
+ async function handleSubmit(e) {
2872
+ e.preventDefault();
2873
+ if (!name.trim()) return;
2874
+ try {
2875
+ await updateChannel.mutateAsync({
2876
+ id: channel.id,
2877
+ body: {
2878
+ name: name.trim(),
2879
+ identifier: identifier.trim() || void 0,
2880
+ id_agent: idAgent
2881
+ }
2882
+ });
2883
+ toast3.success("Canal atualizado");
2884
+ onOpenChange(false);
2885
+ } catch {
2886
+ toast3.error("Erro ao atualizar canal");
2887
+ }
2888
+ }
2889
+ return /* @__PURE__ */ jsx30(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs18(DialogContent, { children: [
2890
+ /* @__PURE__ */ jsx30(DialogHeader, { children: /* @__PURE__ */ jsxs18(DialogTitle, { className: "flex items-center gap-2", children: [
2891
+ /* @__PURE__ */ jsx30(WhatsappIcon, { className: "h-5 w-5 text-green-600" }),
2892
+ "Editar Canal"
2893
+ ] }) }),
2894
+ /* @__PURE__ */ jsxs18("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
2895
+ /* @__PURE__ */ jsxs18("div", { className: "space-y-2", children: [
2896
+ /* @__PURE__ */ jsx30(Label, { htmlFor: "edit-channel-name", children: "Nome do canal *" }),
2897
+ /* @__PURE__ */ jsx30(
2898
+ Input,
2899
+ {
2900
+ id: "edit-channel-name",
2901
+ value: name,
2902
+ onChange: (e) => setName(e.target.value),
2903
+ placeholder: "Ex: WhatsApp Principal",
2904
+ required: true,
2905
+ disabled: updateChannel.isPending
2906
+ }
2907
+ )
2908
+ ] }),
2909
+ /* @__PURE__ */ jsxs18("div", { className: "space-y-2", children: [
2910
+ /* @__PURE__ */ jsx30(Label, { htmlFor: "edit-channel-identifier", children: "N\xFAmero do WhatsApp (opcional)" }),
2911
+ /* @__PURE__ */ jsx30(
2912
+ Input,
2913
+ {
2914
+ id: "edit-channel-identifier",
2915
+ value: identifier,
2916
+ onChange: (e) => setIdentifier(e.target.value),
2917
+ placeholder: "5511999999999",
2918
+ disabled: updateChannel.isPending
2919
+ }
2920
+ )
2921
+ ] }),
2922
+ renderAgentSelect?.({
2923
+ value: idAgent,
2924
+ onChange: setIdAgent,
2925
+ disabled: updateChannel.isPending
2926
+ }),
2927
+ /* @__PURE__ */ jsxs18(DialogFooter, { children: [
2928
+ /* @__PURE__ */ jsx30(
2929
+ Button,
2930
+ {
2931
+ type: "button",
2932
+ variant: "outline",
2933
+ onClick: () => onOpenChange(false),
2934
+ disabled: updateChannel.isPending,
2935
+ children: "Cancelar"
2936
+ }
2937
+ ),
2938
+ /* @__PURE__ */ jsxs18(Button, { type: "submit", disabled: updateChannel.isPending || !name.trim(), children: [
2939
+ updateChannel.isPending && /* @__PURE__ */ jsx30(Loader24, { className: "mr-2 h-4 w-4 animate-spin" }),
2940
+ "Salvar"
2941
+ ] })
2942
+ ] })
2943
+ ] })
2944
+ ] }) });
2945
+ }
2946
+
2947
+ // src/components/contact-form-dialog.tsx
2948
+ import { useEffect as useEffect5, useState as useState9 } from "react";
2949
+ import { Loader2 as Loader25 } from "lucide-react";
2950
+ import { toast as toast4 } from "sonner";
2951
+ import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
2952
+ function ContactFormDialog({
2953
+ open,
2954
+ onOpenChange,
2955
+ contact,
2956
+ config
2957
+ }) {
2958
+ const isEditing = !!contact;
2959
+ const createContact = useCreateContact(config);
2960
+ const updateContact = useUpdateContact(config);
2961
+ const [name, setName] = useState9("");
2962
+ const [phoneNumber, setPhoneNumber] = useState9("");
2963
+ const [identifier, setIdentifier] = useState9("");
2964
+ useEffect5(() => {
2965
+ if (contact) {
2966
+ setName(contact.name);
2967
+ setPhoneNumber(contact.phone_number || "");
2968
+ setIdentifier(contact.identifier || "");
2969
+ } else {
2970
+ setName("");
2971
+ setPhoneNumber("");
2972
+ setIdentifier("");
2973
+ }
2974
+ }, [contact, open]);
2975
+ const isPending = createContact.isPending || updateContact.isPending;
2976
+ async function handleSubmit(e) {
2977
+ e.preventDefault();
2978
+ if (!name.trim()) return;
2979
+ const body = {
2980
+ name: name.trim(),
2981
+ phone_number: phoneNumber.trim() || void 0,
2982
+ identifier: identifier.trim() || void 0
2983
+ };
2984
+ try {
2985
+ if (isEditing) {
2986
+ await updateContact.mutateAsync({ id: contact.id, body });
2987
+ toast4.success("Contato atualizado");
2988
+ } else {
2989
+ await createContact.mutateAsync(body);
2990
+ toast4.success("Contato criado");
2991
+ }
2992
+ onOpenChange(false);
2993
+ } catch {
2994
+ toast4.error(isEditing ? "Erro ao atualizar" : "Erro ao criar contato");
2995
+ }
2996
+ }
2997
+ return /* @__PURE__ */ jsx31(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs19(DialogContent, { children: [
2998
+ /* @__PURE__ */ jsx31(DialogHeader, { children: /* @__PURE__ */ jsx31(DialogTitle, { children: isEditing ? "Editar Contato" : "Novo Contato" }) }),
2999
+ /* @__PURE__ */ jsxs19("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
3000
+ /* @__PURE__ */ jsxs19("div", { className: "space-y-2", children: [
3001
+ /* @__PURE__ */ jsx31(Label, { htmlFor: "contact-name", children: "Nome *" }),
3002
+ /* @__PURE__ */ jsx31(
3003
+ Input,
3004
+ {
3005
+ id: "contact-name",
3006
+ value: name,
3007
+ onChange: (e) => setName(e.target.value),
3008
+ placeholder: "Nome do contato",
3009
+ required: true,
3010
+ disabled: isPending
3011
+ }
3012
+ )
3013
+ ] }),
3014
+ /* @__PURE__ */ jsxs19("div", { className: "space-y-2", children: [
3015
+ /* @__PURE__ */ jsx31(Label, { htmlFor: "contact-phone", children: "Telefone" }),
3016
+ /* @__PURE__ */ jsx31(
3017
+ Input,
3018
+ {
3019
+ id: "contact-phone",
3020
+ value: phoneNumber,
3021
+ onChange: (e) => setPhoneNumber(e.target.value),
3022
+ placeholder: "5511999999999",
3023
+ disabled: isPending
3024
+ }
3025
+ )
3026
+ ] }),
3027
+ /* @__PURE__ */ jsxs19("div", { className: "space-y-2", children: [
3028
+ /* @__PURE__ */ jsx31(Label, { htmlFor: "contact-identifier", children: "Identificador (WhatsApp ID)" }),
3029
+ /* @__PURE__ */ jsx31(
3030
+ Input,
3031
+ {
3032
+ id: "contact-identifier",
3033
+ value: identifier,
3034
+ onChange: (e) => setIdentifier(e.target.value),
3035
+ placeholder: "5511999999999@s.whatsapp.net",
3036
+ disabled: isPending
3037
+ }
3038
+ )
3039
+ ] }),
3040
+ /* @__PURE__ */ jsxs19(DialogFooter, { children: [
3041
+ /* @__PURE__ */ jsx31(
3042
+ Button,
3043
+ {
3044
+ type: "button",
3045
+ variant: "outline",
3046
+ onClick: () => onOpenChange(false),
3047
+ disabled: isPending,
3048
+ children: "Cancelar"
3049
+ }
3050
+ ),
3051
+ /* @__PURE__ */ jsxs19(Button, { type: "submit", disabled: isPending || !name.trim(), children: [
3052
+ isPending ? /* @__PURE__ */ jsx31(Loader25, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
3053
+ isEditing ? "Salvar" : "Criar"
3054
+ ] })
3055
+ ] })
3056
+ ] })
3057
+ ] }) });
3058
+ }
3059
+
3060
+ // src/components/contacts-table.tsx
3061
+ import { useMemo as useMemo4, useState as useState11 } from "react";
3062
+
3063
+ // src/components/data-table.tsx
3064
+ import {
3065
+ flexRender,
3066
+ getCoreRowModel,
3067
+ getSortedRowModel,
3068
+ useReactTable
3069
+ } from "@tanstack/react-table";
3070
+ import { useState as useState10 } from "react";
3071
+
3072
+ // src/components/ui/table.tsx
3073
+ import { jsx as jsx32 } from "react/jsx-runtime";
3074
+ function Table({ className, ...props }) {
3075
+ return /* @__PURE__ */ jsx32("div", { "data-slot": "table-container", className: "relative w-full overflow-x-auto", children: /* @__PURE__ */ jsx32(
3076
+ "table",
3077
+ {
3078
+ "data-slot": "table",
3079
+ className: cn("w-full caption-bottom text-sm", className),
3080
+ ...props
3081
+ }
3082
+ ) });
3083
+ }
3084
+ function TableHeader({ className, ...props }) {
3085
+ return /* @__PURE__ */ jsx32(
3086
+ "thead",
3087
+ {
3088
+ "data-slot": "table-header",
3089
+ className: cn("[&_tr]:border-b", className),
3090
+ ...props
3091
+ }
3092
+ );
3093
+ }
3094
+ function TableBody({ className, ...props }) {
3095
+ return /* @__PURE__ */ jsx32(
3096
+ "tbody",
3097
+ {
3098
+ "data-slot": "table-body",
3099
+ className: cn("[&_tr:last-child]:border-0", className),
3100
+ ...props
3101
+ }
3102
+ );
3103
+ }
3104
+ function TableRow({ className, ...props }) {
3105
+ return /* @__PURE__ */ jsx32(
3106
+ "tr",
3107
+ {
3108
+ "data-slot": "table-row",
3109
+ className: cn("hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", className),
3110
+ ...props
3111
+ }
3112
+ );
3113
+ }
3114
+ function TableHead({ className, ...props }) {
3115
+ return /* @__PURE__ */ jsx32(
3116
+ "th",
3117
+ {
3118
+ "data-slot": "table-head",
3119
+ className: cn("text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0", className),
3120
+ ...props
3121
+ }
3122
+ );
3123
+ }
3124
+ function TableCell({ className, ...props }) {
3125
+ return /* @__PURE__ */ jsx32(
3126
+ "td",
3127
+ {
3128
+ "data-slot": "table-cell",
3129
+ className: cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0", className),
3130
+ ...props
3131
+ }
3132
+ );
3133
+ }
3134
+
3135
+ // src/components/data-table.tsx
3136
+ import { ChevronLeft, ChevronRight as ChevronRight2, ArrowUp, ArrowDown, ArrowUpDown } from "lucide-react";
3137
+ import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
3138
+ function DataTable({
3139
+ columns,
3140
+ data,
3141
+ isLoading,
3142
+ emptyMessage = "Nenhum registro encontrado",
3143
+ total,
3144
+ page = 1,
3145
+ onPageChange,
3146
+ pageSize = 15,
3147
+ onRowClick,
3148
+ selectedRowId,
3149
+ getRowId,
3150
+ compact
3151
+ }) {
3152
+ const [sorting, setSorting] = useState10([]);
3153
+ const table = useReactTable({
3154
+ data,
3155
+ columns,
3156
+ getCoreRowModel: getCoreRowModel(),
3157
+ getSortedRowModel: getSortedRowModel(),
3158
+ onSortingChange: setSorting,
3159
+ state: { sorting }
3160
+ });
3161
+ const totalPages = total ? Math.ceil(total / pageSize) : 1;
3162
+ const showPagination = onPageChange && total && total > pageSize;
3163
+ return /* @__PURE__ */ jsxs20("div", { className: "space-y-4", children: [
3164
+ /* @__PURE__ */ jsx33("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs20(Table, { children: [
3165
+ /* @__PURE__ */ jsx33(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx33(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx33(
3166
+ TableHead,
3167
+ {
3168
+ className: cn(compact && "py-1.5 text-xs"),
3169
+ style: { width: header.getSize() !== 150 ? header.getSize() : void 0 },
3170
+ children: header.isPlaceholder ? null : header.column.getCanSort() ? /* @__PURE__ */ jsxs20(
3171
+ "button",
3172
+ {
3173
+ type: "button",
3174
+ className: "flex items-center gap-1 hover:text-foreground -ml-1 px-1 py-0.5 rounded cursor-pointer select-none",
3175
+ onClick: header.column.getToggleSortingHandler(),
3176
+ children: [
3177
+ flexRender(header.column.columnDef.header, header.getContext()),
3178
+ {
3179
+ asc: /* @__PURE__ */ jsx33(ArrowUp, { className: "h-3.5 w-3.5" }),
3180
+ desc: /* @__PURE__ */ jsx33(ArrowDown, { className: "h-3.5 w-3.5" })
3181
+ }[header.column.getIsSorted()] ?? /* @__PURE__ */ jsx33(ArrowUpDown, { className: "h-3.5 w-3.5 text-muted-foreground/50" })
3182
+ ]
3183
+ }
3184
+ ) : flexRender(header.column.columnDef.header, header.getContext())
3185
+ },
3186
+ header.id
3187
+ )) }, headerGroup.id)) }),
3188
+ /* @__PURE__ */ jsx33(TableBody, { children: isLoading ? Array.from({ length: compact ? 3 : 5 }).map((_, i) => /* @__PURE__ */ jsx33(TableRow, { children: columns.map((_2, j) => /* @__PURE__ */ jsx33(TableCell, { className: cn(compact && "py-1.5"), children: /* @__PURE__ */ jsx33(Skeleton, { className: "h-4 w-full max-w-[120px]" }) }, j)) }, i)) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ jsx33(TableRow, { children: /* @__PURE__ */ jsx33(
3189
+ TableCell,
3190
+ {
3191
+ colSpan: columns.length,
3192
+ className: cn(
3193
+ "text-center text-muted-foreground",
3194
+ compact ? "py-4" : "py-8"
3195
+ ),
3196
+ children: emptyMessage
3197
+ }
3198
+ ) }) : table.getRowModel().rows.map((row) => {
3199
+ const rowId = getRowId ? getRowId(row.original) : void 0;
3200
+ const isSelected = selectedRowId != null && rowId != null && rowId === selectedRowId;
3201
+ return /* @__PURE__ */ jsx33(
3202
+ TableRow,
3203
+ {
3204
+ className: cn(
3205
+ onRowClick && "cursor-pointer",
3206
+ isSelected && "bg-accent"
3207
+ ),
3208
+ onClick: () => onRowClick?.(row.original),
3209
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx33(TableCell, { className: cn(compact && "py-1.5"), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))
3210
+ },
3211
+ row.id
3212
+ );
3213
+ }) })
3214
+ ] }) }),
3215
+ showPagination && /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between px-2", children: [
3216
+ /* @__PURE__ */ jsxs20("p", { className: "text-sm text-muted-foreground", children: [
3217
+ total,
3218
+ " registro",
3219
+ total !== 1 ? "s" : ""
3220
+ ] }),
3221
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-2", children: [
3222
+ /* @__PURE__ */ jsxs20(
3223
+ Button,
3224
+ {
3225
+ variant: "outline",
3226
+ size: "sm",
3227
+ onClick: () => onPageChange(page - 1),
3228
+ disabled: page <= 1,
3229
+ children: [
3230
+ /* @__PURE__ */ jsx33(ChevronLeft, { className: "h-4 w-4" }),
3231
+ "Anterior"
3232
+ ]
3233
+ }
3234
+ ),
3235
+ /* @__PURE__ */ jsxs20("span", { className: "text-sm text-muted-foreground", children: [
3236
+ page,
3237
+ " de ",
3238
+ totalPages
3239
+ ] }),
3240
+ /* @__PURE__ */ jsxs20(
3241
+ Button,
3242
+ {
3243
+ variant: "outline",
3244
+ size: "sm",
3245
+ onClick: () => onPageChange(page + 1),
3246
+ disabled: page >= totalPages,
3247
+ children: [
3248
+ "Pr\xF3ximo",
3249
+ /* @__PURE__ */ jsx33(ChevronRight2, { className: "h-4 w-4" })
3250
+ ]
3251
+ }
3252
+ )
3253
+ ] })
3254
+ ] })
3255
+ ] });
3256
+ }
3257
+
3258
+ // src/components/contacts-table.tsx
3259
+ import { Pencil as Pencil2, Trash2 as Trash23, Search as Search3 } from "lucide-react";
3260
+ import { format as format3 } from "date-fns";
3261
+ import { ptBR as ptBR4 } from "date-fns/locale";
3262
+ import { toast as toast5 } from "sonner";
3263
+ import { Fragment as Fragment3, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
3264
+ function useColumns(onEdit, onDelete) {
3265
+ return [
3266
+ {
3267
+ accessorKey: "name",
3268
+ header: "Nome",
3269
+ cell: ({ row }) => /* @__PURE__ */ jsx34("span", { className: "font-medium", children: row.original.name }),
3270
+ sortingFn: (rowA, rowB) => rowA.original.name.toLowerCase().localeCompare(rowB.original.name.toLowerCase())
3271
+ },
3272
+ {
3273
+ accessorKey: "phone_number",
3274
+ header: "Telefone",
3275
+ cell: ({ row }) => row.original.phone_number || "\u2014",
3276
+ sortingFn: (rowA, rowB) => {
3277
+ const a = rowA.original.phone_number || "";
3278
+ const b = rowB.original.phone_number || "";
3279
+ return a.localeCompare(b);
3280
+ }
3281
+ },
3282
+ {
3283
+ accessorKey: "identifier",
3284
+ header: "Identificador",
3285
+ cell: ({ row }) => /* @__PURE__ */ jsx34("span", { className: "text-muted-foreground text-xs font-mono", children: row.original.identifier || "\u2014" }),
3286
+ sortingFn: (rowA, rowB) => {
3287
+ const a = rowA.original.identifier || "";
3288
+ const b = rowB.original.identifier || "";
3289
+ return a.localeCompare(b);
3290
+ }
3291
+ },
3292
+ {
3293
+ accessorKey: "datetime_add",
3294
+ header: "Criado em",
3295
+ cell: ({ row }) => /* @__PURE__ */ jsx34("span", { className: "text-muted-foreground text-sm", children: format3(new Date(row.original.datetime_add), "dd/MM/yyyy", { locale: ptBR4 }) })
3296
+ },
3297
+ {
3298
+ id: "actions",
3299
+ size: 80,
3300
+ enableSorting: false,
3301
+ cell: ({ row }) => /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1", children: [
3302
+ /* @__PURE__ */ jsxs21(Tooltip, { children: [
3303
+ /* @__PURE__ */ jsx34(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(
3304
+ Button,
3305
+ {
3306
+ variant: "ghost",
3307
+ size: "icon",
3308
+ className: "h-8 w-8",
3309
+ onClick: () => onEdit(row.original),
3310
+ children: /* @__PURE__ */ jsx34(Pencil2, { className: "h-4 w-4" })
3311
+ }
3312
+ ) }),
3313
+ /* @__PURE__ */ jsx34(TooltipContent, { children: "Editar" })
3314
+ ] }),
3315
+ /* @__PURE__ */ jsxs21(Tooltip, { children: [
3316
+ /* @__PURE__ */ jsx34(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx34(
3317
+ Button,
3318
+ {
3319
+ variant: "ghost",
3320
+ size: "icon",
3321
+ className: "h-8 w-8 text-destructive hover:text-destructive",
3322
+ onClick: () => onDelete(row.original.id),
3323
+ children: /* @__PURE__ */ jsx34(Trash23, { className: "h-4 w-4" })
3324
+ }
3325
+ ) }),
3326
+ /* @__PURE__ */ jsx34(TooltipContent, { children: "Excluir" })
3327
+ ] })
3328
+ ] })
3329
+ }
3330
+ ];
3331
+ }
3332
+ function ContactsTable({ config }) {
3333
+ const [search, setSearch] = useState11("");
3334
+ const [page, setPage] = useState11(1);
3335
+ const queryParams = useMemo4(() => {
3336
+ const params = {
3337
+ limit: "15",
3338
+ page: String(page)
3339
+ };
3340
+ if (search) {
3341
+ params.search = search;
3342
+ }
3343
+ return params;
3344
+ }, [search, page]);
3345
+ const { data, isLoading } = useContacts(config, queryParams);
3346
+ const deleteContact = useDeleteContact(config);
3347
+ const [editContact, setEditContact] = useState11(null);
3348
+ const [deleteId, setDeleteId] = useState11(null);
3349
+ const contacts = data?.data || [];
3350
+ const total = data?.total || 0;
3351
+ const columns = useColumns(
3352
+ (contact) => setEditContact(contact),
3353
+ (id) => setDeleteId(id)
3354
+ );
3355
+ function handleDelete() {
3356
+ if (!deleteId) return;
3357
+ deleteContact.mutate(deleteId, {
3358
+ onSuccess: () => {
3359
+ toast5.success("Contato exclu\xEDdo");
3360
+ setDeleteId(null);
3361
+ },
3362
+ onError: () => toast5.error("Erro ao excluir contato")
3363
+ });
3364
+ }
3365
+ function handleSearchChange(value) {
3366
+ setSearch(value);
3367
+ setPage(1);
3368
+ }
3369
+ return /* @__PURE__ */ jsxs21(Fragment3, { children: [
3370
+ /* @__PURE__ */ jsx34("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs21("div", { className: "relative flex-1 max-w-md", children: [
3371
+ /* @__PURE__ */ jsx34(Search3, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
3372
+ /* @__PURE__ */ jsx34(
3373
+ Input,
3374
+ {
3375
+ placeholder: "Buscar por nome, telefone ou identificador...",
3376
+ value: search,
3377
+ onChange: (e) => handleSearchChange(e.target.value),
3378
+ className: "pl-9"
3379
+ }
3380
+ )
3381
+ ] }) }),
3382
+ /* @__PURE__ */ jsx34(
3383
+ DataTable,
3384
+ {
3385
+ columns,
3386
+ data: contacts,
3387
+ isLoading,
3388
+ emptyMessage: "Nenhum contato encontrado",
3389
+ total,
3390
+ page,
3391
+ onPageChange: setPage,
3392
+ pageSize: 15
3393
+ }
3394
+ ),
3395
+ /* @__PURE__ */ jsx34(
3396
+ ContactFormDialog,
3397
+ {
3398
+ open: !!editContact,
3399
+ onOpenChange: (open) => !open && setEditContact(null),
3400
+ contact: editContact ?? void 0,
3401
+ config
3402
+ }
3403
+ ),
3404
+ /* @__PURE__ */ jsx34(AlertDialog, { open: !!deleteId, onOpenChange: (open) => !open && setDeleteId(null), children: /* @__PURE__ */ jsxs21(AlertDialogContent, { children: [
3405
+ /* @__PURE__ */ jsxs21(AlertDialogHeader, { children: [
3406
+ /* @__PURE__ */ jsx34(AlertDialogTitle, { children: "Excluir contato?" }),
3407
+ /* @__PURE__ */ jsx34(AlertDialogDescription, { children: "Esta a\xE7\xE3o n\xE3o pode ser desfeita. O contato ser\xE1 removido permanentemente." })
3408
+ ] }),
3409
+ /* @__PURE__ */ jsxs21(AlertDialogFooter, { children: [
3410
+ /* @__PURE__ */ jsx34(AlertDialogCancel, { children: "Cancelar" }),
3411
+ /* @__PURE__ */ jsx34(
3412
+ AlertDialogAction,
3413
+ {
3414
+ onClick: handleDelete,
3415
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
3416
+ children: "Excluir"
3417
+ }
3418
+ )
3419
+ ] })
3420
+ ] }) })
3421
+ ] });
3422
+ }
3423
+
3424
+ // src/components/inbox-page.tsx
3425
+ import { useState as useState12, useCallback as useCallback3 } from "react";
3426
+ import { MessageCircle, User } from "lucide-react";
3427
+ import { Fragment as Fragment4, jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
3428
+ function InboxPage({ config, filterChannelId }) {
3429
+ const [selectedInbox, setSelectedInbox] = useState12(null);
3430
+ const [showContactPanel, setShowContactPanel] = useState12(false);
3431
+ const { data: inboxes, isLoading: inboxesLoading } = useInboxes(config);
3432
+ const { data: messages = [], isLoading: messagesLoading } = useInboxMessages(config, selectedInbox?.id ?? null);
3433
+ const { data: contact, isLoading: contactLoading } = useGetContact(
3434
+ config,
3435
+ showContactPanel && selectedInbox?.id_contact ? selectedInbox.id_contact : null
3436
+ );
3437
+ const sendMessage = useSendMessage(config);
3438
+ const retryMessage = useRetryMessage(config);
3439
+ const revokeMessage = useRevokeMessage(config);
3440
+ const editMessage = useEditMessage(config);
3441
+ const updateInbox = useUpdateInbox(config);
3442
+ const deleteInbox = useDeleteInbox(config);
3443
+ const handleSend = useCallback3(
3444
+ (content) => {
3445
+ if (!selectedInbox) return;
3446
+ sendMessage.mutate({ idInbox: selectedInbox.id, content });
3447
+ },
3448
+ [selectedInbox, sendMessage]
3449
+ );
3450
+ const handleStatusChange = useCallback3(
3451
+ (status) => {
3452
+ if (!selectedInbox) return;
3453
+ updateInbox.mutate({ id: selectedInbox.id, body: { status } });
3454
+ },
3455
+ [selectedInbox, updateInbox]
3456
+ );
3457
+ const handleRevoke = useCallback3(
3458
+ (message) => {
3459
+ if (!selectedInbox) return;
3460
+ revokeMessage.mutate({ id: message.id, idInbox: selectedInbox.id });
3461
+ },
3462
+ [selectedInbox, revokeMessage]
3463
+ );
3464
+ const handleEdit = useCallback3(
3465
+ (message, newContent) => {
3466
+ if (!selectedInbox) return;
3467
+ editMessage.mutate({
3468
+ id: message.id,
3469
+ idInbox: selectedInbox.id,
3470
+ content: newContent
3471
+ });
3472
+ },
3473
+ [selectedInbox, editMessage]
3474
+ );
3475
+ return /* @__PURE__ */ jsxs22("div", { className: "flex h-full", children: [
3476
+ /* @__PURE__ */ jsx35("div", { className: "w-[360px] shrink-0 border-r flex flex-col", children: /* @__PURE__ */ jsx35(
3477
+ InboxSidebar,
3478
+ {
3479
+ inboxes,
3480
+ isLoading: inboxesLoading,
3481
+ selectedInboxId: selectedInbox?.id ?? null,
3482
+ onSelectInbox: (inbox) => {
3483
+ setSelectedInbox(inbox);
3484
+ setShowContactPanel(false);
3485
+ },
3486
+ onDeleteInbox: (id) => deleteInbox.mutate(id),
3487
+ filterChannelId
3488
+ }
3489
+ ) }),
3490
+ /* @__PURE__ */ jsx35("div", { className: "flex-1 flex min-w-0", children: selectedInbox ? /* @__PURE__ */ jsxs22(Fragment4, { children: [
3491
+ /* @__PURE__ */ jsx35("div", { className: "flex-1 flex flex-col min-w-0", children: /* @__PURE__ */ jsx35(
3492
+ ChatView,
3493
+ {
3494
+ messages,
3495
+ isLoading: messagesLoading,
3496
+ onSend: handleSend,
3497
+ onRetry: retryMessage,
3498
+ onRevoke: handleRevoke,
3499
+ onEdit: handleEdit,
3500
+ renderHeader: /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between border-b px-4 py-3", children: [
3501
+ /* @__PURE__ */ jsx35("span", { className: "text-sm font-medium", children: selectedInbox.contact_name || "Conversa" }),
3502
+ /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
3503
+ /* @__PURE__ */ jsxs22(
3504
+ Select,
3505
+ {
3506
+ value: selectedInbox.status,
3507
+ onValueChange: handleStatusChange,
3508
+ children: [
3509
+ /* @__PURE__ */ jsx35(SelectTrigger, { className: "w-[130px] h-8 text-xs", children: /* @__PURE__ */ jsx35(SelectValue, { placeholder: "Status" }) }),
3510
+ /* @__PURE__ */ jsxs22(SelectContent, { children: [
3511
+ /* @__PURE__ */ jsx35(SelectItem, { value: "open", children: "Aberta" }),
3512
+ /* @__PURE__ */ jsx35(SelectItem, { value: "pending", children: "Pendente" }),
3513
+ /* @__PURE__ */ jsx35(SelectItem, { value: "resolved", children: "Resolvida" })
3514
+ ] })
3515
+ ]
3516
+ }
3517
+ ),
3518
+ selectedInbox.id_contact && /* @__PURE__ */ jsx35(
3519
+ Button,
3520
+ {
3521
+ variant: "ghost",
3522
+ size: "icon",
3523
+ className: "h-8 w-8",
3524
+ onClick: () => setShowContactPanel((v) => !v),
3525
+ children: /* @__PURE__ */ jsx35(User, { className: "h-4 w-4" })
3526
+ }
3527
+ )
3528
+ ] })
3529
+ ] })
3530
+ }
3531
+ ) }),
3532
+ showContactPanel && selectedInbox.id_contact && /* @__PURE__ */ jsx35(
3533
+ ContactInfoPanel,
3534
+ {
3535
+ contact: contact ?? null,
3536
+ isLoading: contactLoading,
3537
+ onClose: () => setShowContactPanel(false)
3538
+ }
3539
+ )
3540
+ ] }) : /* @__PURE__ */ jsxs22("div", { className: "flex-1 flex flex-col items-center justify-center text-muted-foreground gap-3", children: [
3541
+ /* @__PURE__ */ jsx35(MessageCircle, { className: "h-12 w-12 opacity-20" }),
3542
+ /* @__PURE__ */ jsx35("p", { className: "text-sm", children: "Selecione uma conversa para come\xE7ar" })
3543
+ ] }) })
3544
+ ] });
3545
+ }
3546
+
3547
+ // src/components/channels-page.tsx
3548
+ import { useState as useState13 } from "react";
3549
+ import { Plus as Plus2, QrCode, Unplug, LogOut } from "lucide-react";
3550
+ import { toast as toast6 } from "sonner";
3551
+ import { Fragment as Fragment5, jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
3552
+ function ChannelCardWrapper({
3553
+ channel,
3554
+ config,
3555
+ renderAgentSelect,
3556
+ getAgentInfo
3557
+ }) {
3558
+ const { data: status } = useChannelWhatsappStatus(config, channel.id);
3559
+ const disconnectChannel = useDisconnectChannel(config);
3560
+ const logoutChannel = useLogoutChannel(config);
3561
+ const deleteChannel = useDeleteChannel(config);
3562
+ const [qrOpen, setQrOpen] = useState13(false);
3563
+ const [editOpen, setEditOpen] = useState13(false);
3564
+ const [deleteOpen, setDeleteOpen] = useState13(false);
3565
+ const isFullyConnected = status?.connected === true && status?.logged_in === true;
3566
+ const hasSession = !!channel.external_id;
3567
+ const agentInfo = getAgentInfo?.(channel.id_agent);
3568
+ function handleDisconnect() {
3569
+ disconnectChannel.mutate(channel.id, {
3570
+ onSuccess: () => toast6.success("Canal desconectado"),
3571
+ onError: () => toast6.error("Erro ao desconectar")
3572
+ });
3573
+ }
3574
+ function handleLogout() {
3575
+ logoutChannel.mutate(channel.id, {
3576
+ onSuccess: () => toast6.success("Logout realizado. Ser\xE1 necess\xE1rio novo QR code."),
3577
+ onError: () => toast6.error("Erro ao fazer logout")
3578
+ });
3579
+ }
3580
+ function handleDelete() {
3581
+ deleteChannel.mutate(channel.id, {
3582
+ onSuccess: () => {
3583
+ toast6.success("Canal exclu\xEDdo");
3584
+ setDeleteOpen(false);
3585
+ },
3586
+ onError: () => toast6.error("Erro ao excluir canal")
3587
+ });
3588
+ }
3589
+ return /* @__PURE__ */ jsxs23(Fragment5, { children: [
3590
+ /* @__PURE__ */ jsx36(
3591
+ ChannelCard,
3592
+ {
3593
+ channel,
3594
+ config,
3595
+ onEdit: () => setEditOpen(true),
3596
+ onDelete: () => setDeleteOpen(true),
3597
+ linkedAgentName: agentInfo?.name,
3598
+ linkedAgentActive: agentInfo?.active !== false,
3599
+ actions: /* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap items-center gap-2", children: [
3600
+ !isFullyConnected && /* @__PURE__ */ jsxs23(
3601
+ Button,
3602
+ {
3603
+ size: "sm",
3604
+ variant: "outline",
3605
+ onClick: () => setQrOpen(true),
3606
+ children: [
3607
+ /* @__PURE__ */ jsx36(QrCode, { className: "mr-1.5 h-3.5 w-3.5" }),
3608
+ "Conectar via QR"
3609
+ ]
3610
+ }
3611
+ ),
3612
+ isFullyConnected && /* @__PURE__ */ jsxs23(
3613
+ Button,
3614
+ {
3615
+ size: "sm",
3616
+ variant: "outline",
3617
+ onClick: handleDisconnect,
3618
+ disabled: disconnectChannel.isPending,
3619
+ children: [
3620
+ /* @__PURE__ */ jsx36(Unplug, { className: "mr-1.5 h-3.5 w-3.5" }),
3621
+ "Desconectar"
3622
+ ]
3623
+ }
3624
+ ),
3625
+ hasSession && /* @__PURE__ */ jsxs23(
3626
+ Button,
3627
+ {
3628
+ size: "sm",
3629
+ variant: "outline",
3630
+ className: "text-destructive hover:text-destructive",
3631
+ onClick: handleLogout,
3632
+ disabled: logoutChannel.isPending,
3633
+ children: [
3634
+ /* @__PURE__ */ jsx36(LogOut, { className: "mr-1.5 h-3.5 w-3.5" }),
3635
+ "Logout"
3636
+ ]
3637
+ }
3638
+ )
3639
+ ] })
3640
+ }
3641
+ ),
3642
+ /* @__PURE__ */ jsx36(
3643
+ WhatsappQrDialog,
3644
+ {
3645
+ open: qrOpen,
3646
+ onOpenChange: setQrOpen,
3647
+ channelId: channel.id,
3648
+ config
3649
+ }
3650
+ ),
3651
+ /* @__PURE__ */ jsx36(
3652
+ ChannelEditDialog,
3653
+ {
3654
+ open: editOpen,
3655
+ onOpenChange: setEditOpen,
3656
+ channel,
3657
+ config,
3658
+ renderAgentSelect
3659
+ }
3660
+ ),
3661
+ /* @__PURE__ */ jsx36(AlertDialog, { open: deleteOpen, onOpenChange: setDeleteOpen, children: /* @__PURE__ */ jsxs23(AlertDialogContent, { children: [
3662
+ /* @__PURE__ */ jsxs23(AlertDialogHeader, { children: [
3663
+ /* @__PURE__ */ jsx36(AlertDialogTitle, { children: "Excluir canal?" }),
3664
+ /* @__PURE__ */ jsxs23(AlertDialogDescription, { children: [
3665
+ 'O canal "',
3666
+ channel.name,
3667
+ '" ser\xE1 removido permanentemente. Todas as conversas associadas ser\xE3o perdidas.'
3668
+ ] })
3669
+ ] }),
3670
+ /* @__PURE__ */ jsxs23(AlertDialogFooter, { children: [
3671
+ /* @__PURE__ */ jsx36(AlertDialogCancel, { children: "Cancelar" }),
3672
+ /* @__PURE__ */ jsx36(
3673
+ AlertDialogAction,
3674
+ {
3675
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
3676
+ onClick: handleDelete,
3677
+ children: "Excluir"
3678
+ }
3679
+ )
3680
+ ] })
3681
+ ] }) })
3682
+ ] });
3683
+ }
3684
+ function ChannelsPage({
3685
+ config,
3686
+ renderAgentSelect,
3687
+ getAgentInfo
3688
+ }) {
3689
+ const { data: channels, isLoading } = useChannels(config);
3690
+ const [createOpen, setCreateOpen] = useState13(false);
3691
+ return /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-6 p-4 flex-1 min-h-0 overflow-y-auto", children: [
3692
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between", children: [
3693
+ /* @__PURE__ */ jsxs23("div", { children: [
3694
+ /* @__PURE__ */ jsx36("h1", { className: "text-xl font-semibold", children: "Canais" }),
3695
+ /* @__PURE__ */ jsx36("p", { className: "text-sm text-muted-foreground", children: "Gerencie seus canais de comunica\xE7\xE3o" })
3696
+ ] }),
3697
+ /* @__PURE__ */ jsxs23(Button, { onClick: () => setCreateOpen(true), children: [
3698
+ /* @__PURE__ */ jsx36(Plus2, { className: "mr-2 h-4 w-4" }),
3699
+ "Novo Canal"
3700
+ ] })
3701
+ ] }),
3702
+ isLoading ? /* @__PURE__ */ jsx36("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border p-4 space-y-3", children: [
3703
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
3704
+ /* @__PURE__ */ jsx36(Skeleton, { className: "h-9 w-9 rounded-md" }),
3705
+ /* @__PURE__ */ jsxs23("div", { className: "space-y-1", children: [
3706
+ /* @__PURE__ */ jsx36(Skeleton, { className: "h-4 w-24" }),
3707
+ /* @__PURE__ */ jsx36(Skeleton, { className: "h-3 w-32" })
3708
+ ] })
3709
+ ] }),
3710
+ /* @__PURE__ */ jsx36(Skeleton, { className: "h-8 w-full" })
3711
+ ] }, i)) }) : !channels?.length ? /* @__PURE__ */ jsxs23("div", { className: "flex flex-col items-center justify-center py-12 text-muted-foreground gap-3", children: [
3712
+ /* @__PURE__ */ jsx36(WhatsappIcon, { className: "h-12 w-12 opacity-20" }),
3713
+ /* @__PURE__ */ jsx36("p", { className: "text-sm", children: "Nenhum canal configurado" }),
3714
+ /* @__PURE__ */ jsxs23(Button, { variant: "outline", onClick: () => setCreateOpen(true), children: [
3715
+ /* @__PURE__ */ jsx36(Plus2, { className: "mr-2 h-4 w-4" }),
3716
+ "Criar primeiro canal"
3717
+ ] })
3718
+ ] }) : /* @__PURE__ */ jsx36("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: channels.map((channel) => /* @__PURE__ */ jsx36(
3719
+ ChannelCardWrapper,
3720
+ {
3721
+ channel,
3722
+ config,
3723
+ renderAgentSelect,
3724
+ getAgentInfo
3725
+ },
3726
+ channel.id
3727
+ )) }),
3728
+ /* @__PURE__ */ jsx36(
3729
+ ChannelCreateDialog,
3730
+ {
3731
+ open: createOpen,
3732
+ onOpenChange: setCreateOpen,
3733
+ config,
3734
+ renderAgentSelect
3735
+ }
3736
+ )
3737
+ ] });
3738
+ }
3739
+
3740
+ // src/components/contacts-page.tsx
3741
+ import { useState as useState14 } from "react";
3742
+ import { Plus as Plus3 } from "lucide-react";
3743
+ import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
3744
+ function ContactsPage({ config }) {
3745
+ const [createOpen, setCreateOpen] = useState14(false);
3746
+ return /* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-6 p-4 flex-1 min-h-0 overflow-y-auto", children: [
3747
+ /* @__PURE__ */ jsxs24("div", { className: "flex items-center justify-between", children: [
3748
+ /* @__PURE__ */ jsxs24("div", { children: [
3749
+ /* @__PURE__ */ jsx37("h1", { className: "text-xl font-semibold", children: "Contatos" }),
3750
+ /* @__PURE__ */ jsx37("p", { className: "text-sm text-muted-foreground", children: "Gerencie seus contatos de conversas" })
3751
+ ] }),
3752
+ /* @__PURE__ */ jsxs24(Button, { onClick: () => setCreateOpen(true), children: [
3753
+ /* @__PURE__ */ jsx37(Plus3, { className: "mr-2 h-4 w-4" }),
3754
+ "Novo Contato"
3755
+ ] })
3756
+ ] }),
3757
+ /* @__PURE__ */ jsx37(ContactsTable, { config }),
3758
+ /* @__PURE__ */ jsx37(
3759
+ ContactFormDialog,
3760
+ {
3761
+ open: createOpen,
3762
+ onOpenChange: setCreateOpen,
3763
+ config
3764
+ }
3765
+ )
3766
+ ] });
3767
+ }
3768
+
3769
+ // src/components/chat-dashboard.tsx
3770
+ import { useState as useState15, useMemo as useMemo5 } from "react";
3771
+
3772
+ // src/components/ui/card.tsx
3773
+ import { jsx as jsx38 } from "react/jsx-runtime";
3774
+ function Card({
3775
+ className,
3776
+ size = "default",
3777
+ ...props
3778
+ }) {
3779
+ return /* @__PURE__ */ jsx38(
3780
+ "div",
3781
+ {
3782
+ "data-slot": "card",
3783
+ "data-size": size,
3784
+ className: cn("ring-foreground/10 bg-card text-card-foreground gap-6 overflow-hidden rounded-xl py-6 text-sm shadow-xs ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className),
3785
+ ...props
3786
+ }
3787
+ );
3788
+ }
3789
+ function CardHeader({ className, ...props }) {
3790
+ return /* @__PURE__ */ jsx38(
3791
+ "div",
3792
+ {
3793
+ "data-slot": "card-header",
3794
+ className: cn(
3795
+ "gap-1 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",
3796
+ className
3797
+ ),
3798
+ ...props
3799
+ }
3800
+ );
3801
+ }
3802
+ function CardTitle({ className, ...props }) {
3803
+ return /* @__PURE__ */ jsx38(
3804
+ "div",
3805
+ {
3806
+ "data-slot": "card-title",
3807
+ className: cn("text-base leading-normal font-medium group-data-[size=sm]/card:text-sm", className),
3808
+ ...props
3809
+ }
3810
+ );
3811
+ }
3812
+ function CardContent({ className, ...props }) {
3813
+ return /* @__PURE__ */ jsx38(
3814
+ "div",
3815
+ {
3816
+ "data-slot": "card-content",
3817
+ className: cn("px-6 group-data-[size=sm]/card:px-4", className),
3818
+ ...props
3819
+ }
3820
+ );
3821
+ }
3822
+
3823
+ // src/components/ui/progress.tsx
3824
+ import { Progress as ProgressPrimitive } from "radix-ui";
3825
+ import { jsx as jsx39 } from "react/jsx-runtime";
3826
+ function Progress({
3827
+ className,
3828
+ value,
3829
+ ...props
3830
+ }) {
3831
+ return /* @__PURE__ */ jsx39(
3832
+ ProgressPrimitive.Root,
3833
+ {
3834
+ "data-slot": "progress",
3835
+ className: cn(
3836
+ "bg-muted h-1.5 rounded-full relative flex w-full items-center overflow-x-hidden",
3837
+ className
3838
+ ),
3839
+ ...props,
3840
+ children: /* @__PURE__ */ jsx39(
3841
+ ProgressPrimitive.Indicator,
3842
+ {
3843
+ "data-slot": "progress-indicator",
3844
+ className: "bg-primary size-full flex-1 transition-all",
3845
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
3846
+ }
3847
+ )
3848
+ }
3849
+ );
3850
+ }
3851
+
3852
+ // src/components/chat-dashboard.tsx
3853
+ import {
3854
+ Inbox as InboxIcon2,
3855
+ MessageCircle as MessageCircle2,
3856
+ Clock as Clock2,
3857
+ CircleCheck,
3858
+ ArrowRight
3859
+ } from "lucide-react";
3860
+ import { formatDistanceToNow as formatDistanceToNow2 } from "date-fns";
3861
+ import { ptBR as ptBR5 } from "date-fns/locale";
3862
+ import { Fragment as Fragment6, jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
3863
+ function getGreeting(userName) {
3864
+ const hour = (/* @__PURE__ */ new Date()).getHours();
3865
+ const prefix = hour < 12 ? "Bom dia" : hour < 18 ? "Boa tarde" : "Boa noite";
3866
+ return userName ? `${prefix}, ${userName}!` : `${prefix}!`;
3867
+ }
3868
+ var statusColors2 = {
3869
+ open: "bg-green-500/10 text-green-600 border-green-200",
3870
+ pending: "bg-yellow-500/10 text-yellow-600 border-yellow-200",
3871
+ resolved: "bg-zinc-500/10 text-zinc-500 border-zinc-200"
3872
+ };
3873
+ var statusLabels2 = {
3874
+ open: "Aberta",
3875
+ pending: "Pendente",
3876
+ resolved: "Resolvida"
3877
+ };
3878
+ function StatCard({
3879
+ title,
3880
+ value,
3881
+ total,
3882
+ icon: Icon,
3883
+ loading,
3884
+ accentColor,
3885
+ onClick
3886
+ }) {
3887
+ const pct = total && value ? Math.round(value / total * 100) : 0;
3888
+ return /* @__PURE__ */ jsxs25(
3889
+ Card,
3890
+ {
3891
+ className: cn("cursor-pointer transition-shadow hover:shadow-md border-l-4", accentColor),
3892
+ onClick,
3893
+ children: [
3894
+ /* @__PURE__ */ jsxs25(CardHeader, { className: "flex flex-row items-center justify-between pb-2", children: [
3895
+ /* @__PURE__ */ jsx40(CardTitle, { className: "text-sm font-medium text-muted-foreground", children: title }),
3896
+ /* @__PURE__ */ jsx40(Icon, { className: "h-4 w-4 text-muted-foreground" })
3897
+ ] }),
3898
+ /* @__PURE__ */ jsx40(CardContent, { className: "space-y-2", children: loading ? /* @__PURE__ */ jsx40(Skeleton, { className: "h-8 w-16" }) : /* @__PURE__ */ jsxs25(Fragment6, { children: [
3899
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-baseline gap-2", children: [
3900
+ /* @__PURE__ */ jsx40("p", { className: "text-2xl font-bold", children: value ?? 0 }),
3901
+ total !== void 0 && total > 0 && title !== "Total" && /* @__PURE__ */ jsxs25("span", { className: "text-xs text-muted-foreground", children: [
3902
+ "de ",
3903
+ total
3904
+ ] })
3905
+ ] }),
3906
+ title !== "Total" && /* @__PURE__ */ jsx40(Progress, { value: pct, className: "h-1" })
3907
+ ] }) })
3908
+ ]
3909
+ }
3910
+ );
3911
+ }
3912
+ function ChannelHealthCard({
3913
+ channel,
3914
+ config,
3915
+ onClick
3916
+ }) {
3917
+ const { data: status } = useChannelWhatsappStatus(config, channel.id);
3918
+ return /* @__PURE__ */ jsxs25(
3919
+ "div",
3920
+ {
3921
+ className: "flex items-center gap-3 rounded-lg border p-3 cursor-pointer transition-colors hover:bg-accent",
3922
+ onClick,
3923
+ children: [
3924
+ /* @__PURE__ */ jsx40("div", { className: "flex h-9 w-9 items-center justify-center rounded-md bg-green-500/10", children: /* @__PURE__ */ jsx40(WhatsappIcon, { className: "h-5 w-5 text-green-600" }) }),
3925
+ /* @__PURE__ */ jsxs25("div", { className: "flex-1 min-w-0", children: [
3926
+ /* @__PURE__ */ jsx40("p", { className: "text-sm font-medium truncate", children: channel.name }),
3927
+ /* @__PURE__ */ jsx40("p", { className: "text-xs text-muted-foreground truncate", children: channel.identifier || "Sem n\xFAmero" })
3928
+ ] }),
3929
+ /* @__PURE__ */ jsx40(WhatsappStatusBadge, { status, hasSession: !!channel.external_id })
3930
+ ]
3931
+ }
3932
+ );
3933
+ }
3934
+ function RecentConversationItem({
3935
+ inbox,
3936
+ onClick
3937
+ }) {
3938
+ const timestamp = inbox.last_message_at || inbox.datetime_add;
3939
+ const timeAgo = formatDistanceToNow2(new Date(timestamp), {
3940
+ addSuffix: true,
3941
+ locale: ptBR5
3942
+ });
3943
+ const lastMessage = inbox.last_message_content_type === "text" ? inbox.last_message_content : inbox.last_message_content_type ? `[${inbox.last_message_content_type}]` : null;
3944
+ const directionPrefix = inbox.last_message_direction === "outbound" ? "Voc\xEA: " : "";
3945
+ return /* @__PURE__ */ jsxs25(
3946
+ "div",
3947
+ {
3948
+ className: "flex items-center gap-3 rounded-lg p-3 cursor-pointer transition-colors hover:bg-accent",
3949
+ onClick,
3950
+ children: [
3951
+ /* @__PURE__ */ jsx40(ContactAvatar, { name: inbox.contact_name || "?", className: "h-9 w-9" }),
3952
+ /* @__PURE__ */ jsxs25("div", { className: "flex-1 min-w-0", children: [
3953
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between gap-2", children: [
3954
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2 min-w-0", children: [
3955
+ /* @__PURE__ */ jsx40("span", { className: "text-sm font-medium truncate", children: inbox.contact_name || "Desconhecido" }),
3956
+ inbox.channel_name && /* @__PURE__ */ jsx40(Badge, { variant: "outline", className: "shrink-0 text-[10px] px-1.5 py-0 text-muted-foreground", children: inbox.channel_name })
3957
+ ] }),
3958
+ /* @__PURE__ */ jsx40("span", { className: "text-xs text-muted-foreground shrink-0", children: timeAgo })
3959
+ ] }),
3960
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between gap-2 mt-0.5", children: [
3961
+ /* @__PURE__ */ jsx40("p", { className: "text-xs text-muted-foreground truncate", children: lastMessage ? `${directionPrefix}${lastMessage}` : "Sem mensagens" }),
3962
+ /* @__PURE__ */ jsx40(
3963
+ Badge,
3964
+ {
3965
+ variant: "outline",
3966
+ className: cn("shrink-0 text-[10px] px-1.5 py-0", statusColors2[inbox.status]),
3967
+ children: statusLabels2[inbox.status] || inbox.status
3968
+ }
3969
+ )
3970
+ ] })
3971
+ ] })
3972
+ ]
3973
+ }
3974
+ );
3975
+ }
3976
+ function ChatDashboard({
3977
+ config,
3978
+ userName,
3979
+ onNavigateToInbox,
3980
+ onNavigateToChannels,
3981
+ renderExtraSection
3982
+ }) {
3983
+ const [selectedChannelId, setSelectedChannelId] = useState15(null);
3984
+ const { data: stats, isLoading: statsLoading } = useInboxStats(config);
3985
+ const { data: inboxes, isLoading: inboxesLoading } = useInboxes(config);
3986
+ const { data: channels, isLoading: channelsLoading } = useChannels(config);
3987
+ const filteredInboxes = useMemo5(() => {
3988
+ if (!inboxes) return [];
3989
+ if (!selectedChannelId) return inboxes;
3990
+ return inboxes.filter((i) => i.id_channel === selectedChannelId);
3991
+ }, [inboxes, selectedChannelId]);
3992
+ const filteredStats = useMemo5(() => {
3993
+ if (!selectedChannelId) return stats;
3994
+ const open = filteredInboxes.filter((i) => i.status === "open").length;
3995
+ const pending = filteredInboxes.filter((i) => i.status === "pending").length;
3996
+ const resolved = filteredInboxes.filter((i) => i.status === "resolved").length;
3997
+ return { total: filteredInboxes.length, open, pending, resolved };
3998
+ }, [stats, filteredInboxes, selectedChannelId]);
3999
+ const recentInboxes = useMemo5(() => {
4000
+ return [...filteredInboxes].sort((a, b) => {
4001
+ const da = a.last_message_at || a.datetime_add;
4002
+ const db = b.last_message_at || b.datetime_add;
4003
+ return new Date(db).getTime() - new Date(da).getTime();
4004
+ }).slice(0, 5);
4005
+ }, [filteredInboxes]);
4006
+ return /* @__PURE__ */ jsxs25("div", { className: "flex flex-col gap-6 p-4 flex-1 min-h-0 overflow-y-auto", children: [
4007
+ /* @__PURE__ */ jsxs25("div", { children: [
4008
+ /* @__PURE__ */ jsx40("h1", { className: "text-xl font-semibold", children: getGreeting(userName) }),
4009
+ /* @__PURE__ */ jsx40("p", { className: "text-sm text-muted-foreground", children: "Aqui est\xE1 o resumo das suas conversas e canais." })
4010
+ ] }),
4011
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2 flex-wrap", children: [
4012
+ /* @__PURE__ */ jsx40(
4013
+ "button",
4014
+ {
4015
+ className: cn(
4016
+ "inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors",
4017
+ !selectedChannelId ? "bg-primary text-primary-foreground border-primary" : "bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground"
4018
+ ),
4019
+ onClick: () => setSelectedChannelId(null),
4020
+ children: "Todos os canais"
4021
+ }
4022
+ ),
4023
+ channelsLoading ? /* @__PURE__ */ jsxs25(Fragment6, { children: [
4024
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-7 w-24 rounded-full" }),
4025
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-7 w-28 rounded-full" })
4026
+ ] }) : channels?.map((channel) => /* @__PURE__ */ jsxs25(
4027
+ "button",
4028
+ {
4029
+ className: cn(
4030
+ "inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors",
4031
+ selectedChannelId === channel.id ? "bg-primary text-primary-foreground border-primary" : "bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground"
4032
+ ),
4033
+ onClick: () => setSelectedChannelId(channel.id),
4034
+ children: [
4035
+ /* @__PURE__ */ jsx40(WhatsappIcon, { className: "h-3 w-3" }),
4036
+ channel.name
4037
+ ]
4038
+ },
4039
+ channel.id
4040
+ ))
4041
+ ] }),
4042
+ /* @__PURE__ */ jsxs25("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: [
4043
+ /* @__PURE__ */ jsx40(
4044
+ StatCard,
4045
+ {
4046
+ title: "Total",
4047
+ value: filteredStats?.total,
4048
+ total: filteredStats?.total,
4049
+ icon: InboxIcon2,
4050
+ loading: statsLoading && !selectedChannelId,
4051
+ accentColor: "border-l-blue-500",
4052
+ onClick: () => onNavigateToInbox?.()
4053
+ }
4054
+ ),
4055
+ /* @__PURE__ */ jsx40(
4056
+ StatCard,
4057
+ {
4058
+ title: "Abertas",
4059
+ value: filteredStats?.open,
4060
+ total: filteredStats?.total,
4061
+ icon: MessageCircle2,
4062
+ loading: statsLoading && !selectedChannelId,
4063
+ accentColor: "border-l-green-500",
4064
+ onClick: () => onNavigateToInbox?.({ status: "open" })
4065
+ }
4066
+ ),
4067
+ /* @__PURE__ */ jsx40(
4068
+ StatCard,
4069
+ {
4070
+ title: "Pendentes",
4071
+ value: filteredStats?.pending,
4072
+ total: filteredStats?.total,
4073
+ icon: Clock2,
4074
+ loading: statsLoading && !selectedChannelId,
4075
+ accentColor: "border-l-yellow-500",
4076
+ onClick: () => onNavigateToInbox?.({ status: "pending" })
4077
+ }
4078
+ ),
4079
+ /* @__PURE__ */ jsx40(
4080
+ StatCard,
4081
+ {
4082
+ title: "Resolvidas",
4083
+ value: filteredStats?.resolved,
4084
+ total: filteredStats?.total,
4085
+ icon: CircleCheck,
4086
+ loading: statsLoading && !selectedChannelId,
4087
+ accentColor: "border-l-zinc-400",
4088
+ onClick: () => onNavigateToInbox?.({ status: "resolved" })
4089
+ }
4090
+ )
4091
+ ] }),
4092
+ /* @__PURE__ */ jsxs25(Card, { children: [
4093
+ /* @__PURE__ */ jsxs25(CardHeader, { className: "flex flex-row items-center justify-between", children: [
4094
+ /* @__PURE__ */ jsx40(CardTitle, { className: "text-sm font-medium", children: "Sa\xFAde dos Canais" }),
4095
+ onNavigateToChannels && /* @__PURE__ */ jsxs25(
4096
+ "button",
4097
+ {
4098
+ onClick: onNavigateToChannels,
4099
+ className: "text-xs text-primary hover:underline flex items-center gap-1",
4100
+ children: [
4101
+ "Gerenciar",
4102
+ /* @__PURE__ */ jsx40(ArrowRight, { className: "h-3 w-3" })
4103
+ ]
4104
+ }
4105
+ )
4106
+ ] }),
4107
+ /* @__PURE__ */ jsx40(CardContent, { children: channelsLoading ? /* @__PURE__ */ jsx40("div", { className: "space-y-3", children: [1, 2].map((i) => /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-3 p-3", children: [
4108
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-8 w-8 rounded" }),
4109
+ /* @__PURE__ */ jsxs25("div", { className: "flex-1 space-y-1", children: [
4110
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-4 w-24" }),
4111
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-3 w-32" })
4112
+ ] })
4113
+ ] }, i)) }) : !channels?.length ? /* @__PURE__ */ jsx40("div", { className: "flex items-center justify-center h-full text-sm text-muted-foreground py-8", children: "Nenhum canal configurado" }) : /* @__PURE__ */ jsx40("div", { className: "space-y-2", children: channels.map((channel) => /* @__PURE__ */ jsx40(
4114
+ ChannelHealthCard,
4115
+ {
4116
+ channel,
4117
+ config,
4118
+ onClick: () => onNavigateToInbox?.({ channelId: channel.id })
4119
+ },
4120
+ channel.id
4121
+ )) }) })
4122
+ ] }),
4123
+ renderExtraSection?.(),
4124
+ /* @__PURE__ */ jsxs25(Card, { children: [
4125
+ /* @__PURE__ */ jsxs25(CardHeader, { className: "flex flex-row items-center justify-between", children: [
4126
+ /* @__PURE__ */ jsx40(CardTitle, { className: "text-sm font-medium", children: "Conversas Recentes" }),
4127
+ onNavigateToInbox && /* @__PURE__ */ jsxs25(
4128
+ "button",
4129
+ {
4130
+ onClick: () => onNavigateToInbox(),
4131
+ className: "text-xs text-primary hover:underline flex items-center gap-1",
4132
+ children: [
4133
+ "Ver todas",
4134
+ /* @__PURE__ */ jsx40(ArrowRight, { className: "h-3 w-3" })
4135
+ ]
4136
+ }
4137
+ )
4138
+ ] }),
4139
+ /* @__PURE__ */ jsx40(CardContent, { className: "p-0", children: inboxesLoading ? /* @__PURE__ */ jsx40("div", { className: "space-y-2 p-4", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-3 p-3", children: [
4140
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-9 w-9 rounded-full shrink-0" }),
4141
+ /* @__PURE__ */ jsxs25("div", { className: "flex-1 space-y-1.5", children: [
4142
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-4 w-28" }),
4143
+ /* @__PURE__ */ jsx40(Skeleton, { className: "h-3 w-40" })
4144
+ ] })
4145
+ ] }, i)) }) : recentInboxes.length === 0 ? /* @__PURE__ */ jsx40("div", { className: "flex items-center justify-center py-8 text-sm text-muted-foreground", children: "Nenhuma conversa encontrada" }) : /* @__PURE__ */ jsx40("div", { className: "divide-y", children: recentInboxes.map((inbox) => /* @__PURE__ */ jsx40(
4146
+ RecentConversationItem,
4147
+ {
4148
+ inbox,
4149
+ onClick: () => onNavigateToInbox?.()
4150
+ },
4151
+ inbox.id
4152
+ )) }) })
4153
+ ] })
4154
+ ] });
4155
+ }
2477
4156
  export {
4157
+ ChannelCard,
4158
+ ChannelCreateDialog,
4159
+ ChannelEditDialog,
4160
+ ChannelsPage,
4161
+ ChatDashboard,
2478
4162
  ChatInput,
2479
4163
  ChatView,
2480
4164
  ContactAvatar,
4165
+ ContactFormDialog,
2481
4166
  ContactInfoPanel,
4167
+ ContactsPage,
4168
+ ContactsTable,
2482
4169
  DEFAULT_CHANNEL_STATUS_POLLING,
2483
4170
  DEFAULT_INBOX_POLLING,
2484
4171
  DEFAULT_MESSAGES_POLLING,
2485
4172
  DEFAULT_QR_POLLING,
4173
+ DataTable,
2486
4174
  InboxItem,
4175
+ InboxPage,
2487
4176
  InboxSidebar,
2488
4177
  MessageBubble,
2489
4178
  NewConversationDialog,
4179
+ WhatsappIcon,
4180
+ WhatsappQrDialog,
4181
+ WhatsappStatusBadge,
2490
4182
  cn,
2491
4183
  createGchatClient,
2492
4184
  formatDateGroup,