@better-zap/react 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,12 +30,27 @@ let _hugeicons_react = require("@hugeicons/react");
30
30
  let _hugeicons_core_free_icons = require("@hugeicons/core-free-icons");
31
31
  let class_variance_authority = require("class-variance-authority");
32
32
  let better_zap = require("better-zap");
33
- //#region src/react/utils.ts
33
+ //#region src/utils.ts
34
34
  function cn(...inputs) {
35
35
  return (0, tailwind_merge.twMerge)((0, clsx.clsx)(inputs));
36
36
  }
37
+ function getDisplayDate(dateStr) {
38
+ const dateObj = new Date(dateStr);
39
+ const now = /* @__PURE__ */ new Date();
40
+ const isToday = dateObj.toDateString() === now.toDateString();
41
+ const yesterday = new Date(now);
42
+ yesterday.setDate(yesterday.getDate() - 1);
43
+ const isYesterday = dateObj.toDateString() === yesterday.toDateString();
44
+ if (isToday) return "HOJE";
45
+ else if (isYesterday) return "ONTEM";
46
+ else return dateObj.toLocaleDateString("pt-BR", {
47
+ day: "2-digit",
48
+ month: "2-digit",
49
+ year: "numeric"
50
+ });
51
+ }
37
52
  //#endregion
38
- //#region src/react/whatsapp-dashboard.tsx
53
+ //#region src/whatsapp-dashboard.tsx
39
54
  const MOBILE_BREAKPOINT = 1024;
40
55
  function useIsMobile() {
41
56
  const [isMobile, setIsMobile] = (0, react.useState)(false);
@@ -76,7 +91,7 @@ function WhatsappDashboard({ children, className, defaultMobileView = "list", ..
76
91
  });
77
92
  }
78
93
  //#endregion
79
- //#region src/react/message-bubble.tsx
94
+ //#region src/message-bubble.tsx
80
95
  const bubbleVariants = (0, class_variance_authority.cva)("relative shadow-[0_1px_0.5px_rgba(11,20,26,0.13)] rounded-lg px-3 py-2 max-w-[65%]", { variants: { variant: {
81
96
  outgoing: "bg-green-100 text-green-900 rounded-tr-none",
82
97
  incoming: "bg-gray-100 text-gray-900 rounded-tl-none",
@@ -174,24 +189,7 @@ function FormattedMessage({ text }) {
174
189
  }) });
175
190
  }
176
191
  //#endregion
177
- //#region src/date.ts
178
- function getDisplayDate(dateStr) {
179
- const dateObj = new Date(dateStr);
180
- const now = /* @__PURE__ */ new Date();
181
- const isToday = dateObj.toDateString() === now.toDateString();
182
- const yesterday = new Date(now);
183
- yesterday.setDate(yesterday.getDate() - 1);
184
- const isYesterday = dateObj.toDateString() === yesterday.toDateString();
185
- if (isToday) return "HOJE";
186
- else if (isYesterday) return "ONTEM";
187
- else return dateObj.toLocaleDateString("pt-BR", {
188
- day: "2-digit",
189
- month: "2-digit",
190
- year: "numeric"
191
- });
192
- }
193
- //#endregion
194
- //#region src/react/message-view.tsx
192
+ //#region src/message-view.tsx
195
193
  function MessageView({ children, className, ...props }) {
196
194
  const { isMobile, mobileView } = useWhatsappDashboard();
197
195
  const hasContent = react.default.Children.count(children) > 0;
@@ -368,7 +366,7 @@ function MessageViewEmpty({ className, ...props }) {
368
366
  });
369
367
  }
370
368
  //#endregion
371
- //#region src/react/conversation-search.tsx
369
+ //#region src/conversation-search.tsx
372
370
  function ConversationSearch({ value, onChange, className }) {
373
371
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
374
372
  className: cn("border-b border-[#e9edef] shrink-0 p-2", className),
@@ -389,11 +387,46 @@ function ConversationSearch({ value, onChange, className }) {
389
387
  });
390
388
  }
391
389
  //#endregion
392
- //#region src/react/conversation-list.tsx
390
+ //#region src/conversation-filter-chips.tsx
391
+ const chips = [{
392
+ label: "Tudo",
393
+ value: "all"
394
+ }, {
395
+ label: "Não lidas",
396
+ value: "unread"
397
+ }];
398
+ function ConversationFilterChips({ value, onValueChange, unreadCount = 0, className }) {
399
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
400
+ className: cn("flex items-center gap-2 px-3 py-3", className),
401
+ children: chips.map((chip) => {
402
+ const isActive = chip.value === value;
403
+ const showCount = chip.value === "unread" && unreadCount > 0;
404
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
405
+ type: "button",
406
+ onClick: () => onValueChange(chip.value),
407
+ "aria-pressed": isActive,
408
+ className: cn("inline-flex h-8 items-center rounded-full border px-4 text-[15px] font-medium transition-colors", isActive ? "border-[#b8e6c1] bg-[#e7fce3] text-[#017561]" : "border-[#d1d7db] bg-white text-[#54656f] hover:bg-[#f5f6f6]"),
409
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: chip.label }), showCount ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
410
+ className: "ml-1",
411
+ children: unreadCount
412
+ }) : null]
413
+ }, chip.value);
414
+ })
415
+ });
416
+ }
417
+ //#endregion
418
+ //#region src/conversation-list.tsx
393
419
  function ConversationList({ conversations, isLoading, isError, selectedConversationId, onSelect, className }) {
394
420
  const { isMobile, mobileView, setMobileView } = useWhatsappDashboard();
395
421
  const [search, setSearch] = (0, react.useState)("");
396
- const filtered = conversations.filter((c) => c.phone.includes(search) || c.contactName?.toLowerCase().includes(search.toLowerCase()));
422
+ const [filter, setFilter] = (0, react.useState)("all");
423
+ const normalizedSearch = search.trim().toLowerCase();
424
+ const unreadConversationsCount = conversations.filter((c) => c.unreadCount > 0).length;
425
+ const filtered = conversations.filter((conversation) => {
426
+ const matchesSearch = normalizedSearch.length === 0 || conversation.phone.toLowerCase().includes(normalizedSearch) || conversation.contactName?.toLowerCase().includes(normalizedSearch);
427
+ const matchesFilter = filter === "all" || conversation.unreadCount > 0;
428
+ return matchesSearch && matchesFilter;
429
+ });
397
430
  const handleSelect = (id) => {
398
431
  onSelect(id);
399
432
  setMobileView("chat");
@@ -402,32 +435,40 @@ function ConversationList({ conversations, isLoading, isError, selectedConversat
402
435
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
403
436
  className: cn("flex flex-col h-full bg-white border-r border-[#e9edef]", isMobile ? "w-full" : "min-w-[320px] max-w-105", className),
404
437
  style: isVisible ? void 0 : { display: "none" },
405
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationSearch, {
406
- value: search,
407
- onChange: setSearch
408
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
409
- className: "flex-1 overflow-y-auto overflow-x-hidden chat-scrollbar",
410
- children: isLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
411
- className: "flex items-center justify-center h-full text-sm text-[#667781]",
412
- children: "Carregando..."
413
- }) : isError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
414
- className: "flex items-center justify-center h-full text-sm text-red-500",
415
- children: "Erro ao carregar conversas"
416
- }) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
417
- className: "flex flex-col items-center justify-center h-full gap-2 text-[#667781]",
418
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_hugeicons_react.HugeiconsIcon, {
419
- icon: _hugeicons_core_free_icons.Message01Icon,
420
- size: 32
421
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
422
- className: "text-sm",
423
- children: "Nenhuma conversa encontrada"
424
- })]
425
- }) : filtered.map((conversation) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationItem, {
426
- conversation,
427
- isSelected: selectedConversationId === conversation.id,
428
- onClick: () => handleSelect(conversation.id)
429
- }, conversation.id))
430
- })]
438
+ children: [
439
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationSearch, {
440
+ value: search,
441
+ onChange: setSearch
442
+ }),
443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationFilterChips, {
444
+ value: filter,
445
+ onValueChange: setFilter,
446
+ unreadCount: unreadConversationsCount
447
+ }),
448
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
449
+ className: "flex-1 overflow-y-auto overflow-x-hidden chat-scrollbar",
450
+ children: isLoading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
451
+ className: "flex items-center justify-center h-full text-sm text-[#667781]",
452
+ children: "Carregando..."
453
+ }) : isError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
454
+ className: "flex items-center justify-center h-full text-sm text-red-500",
455
+ children: "Erro ao carregar conversas"
456
+ }) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
457
+ className: "flex flex-col items-center justify-center h-full gap-2 text-[#667781]",
458
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_hugeicons_react.HugeiconsIcon, {
459
+ icon: _hugeicons_core_free_icons.Message01Icon,
460
+ size: 32
461
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
462
+ className: "text-sm",
463
+ children: "Nenhuma conversa encontrada"
464
+ })]
465
+ }) : filtered.map((conversation) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationItem, {
466
+ conversation,
467
+ isSelected: selectedConversationId === conversation.id,
468
+ onClick: () => handleSelect(conversation.id)
469
+ }, conversation.id))
470
+ })
471
+ ]
431
472
  });
432
473
  }
433
474
  function ConversationItem({ conversation, isSelected, onClick }) {
@@ -490,7 +531,7 @@ function formatTime(dateStr) {
490
531
  }
491
532
  }
492
533
  //#endregion
493
- //#region src/react/message-input.tsx
534
+ //#region src/message-input.tsx
494
535
  function MessageInput({ onSend, conversation, messages, disabled, placeholder = "Digite uma mensagem", className, contextWindowOpen = true }) {
495
536
  const [text, setText] = (0, react.useState)("");
496
537
  const [isSending, setIsSending] = (0, react.useState)(false);
@@ -605,6 +646,7 @@ function MessageInput({ onSend, conversation, messages, disabled, placeholder =
605
646
  });
606
647
  }
607
648
  //#endregion
649
+ exports.ConversationFilterChips = ConversationFilterChips;
608
650
  exports.ConversationItem = ConversationItem;
609
651
  exports.ConversationList = ConversationList;
610
652
  exports.FormattedMessage = FormattedMessage;
@@ -617,4 +659,5 @@ exports.MessageViewEmpty = MessageViewEmpty;
617
659
  exports.MessageViewHeader = MessageViewHeader;
618
660
  exports.WhatsappDashboard = WhatsappDashboard;
619
661
  exports.cn = cn;
662
+ exports.getDisplayDate = getDisplayDate;
620
663
  exports.useWhatsappDashboard = useWhatsappDashboard;
package/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import { Conversation, Conversation as Conversation$1, ConversationRecord, FreeformMessageWindow, UIMessage, UIMessage as UIMessage$1, UIMessageStatus, UIMessageStatus as UIMessageStatus$1 } from "better-zap";
4
4
  import { ClassValue } from "clsx";
5
5
 
6
- //#region src/react/whatsapp-dashboard.d.ts
6
+ //#region src/whatsapp-dashboard.d.ts
7
7
  type MobileView = "list" | "chat";
8
8
  interface WhatsappDashboardContextValue {
9
9
  isMobile: boolean;
@@ -22,7 +22,7 @@ declare function WhatsappDashboard({
22
22
  ...props
23
23
  }: WhatsappDashboardProps): react_jsx_runtime0.JSX.Element;
24
24
  //#endregion
25
- //#region src/react/message-view.d.ts
25
+ //#region src/message-view.d.ts
26
26
  interface MessageViewProps extends React.HTMLAttributes<HTMLDivElement> {
27
27
  children?: React.ReactNode;
28
28
  }
@@ -71,7 +71,7 @@ declare function MessageViewEmpty({
71
71
  ...props
72
72
  }: React.HTMLAttributes<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
73
73
  //#endregion
74
- //#region src/react/message-bubble.d.ts
74
+ //#region src/message-bubble.d.ts
75
75
  interface MessageBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
76
76
  content: string;
77
77
  sender: "user" | "bot";
@@ -96,7 +96,7 @@ declare function FormattedMessage({
96
96
  text: string;
97
97
  }): react_jsx_runtime0.JSX.Element | null;
98
98
  //#endregion
99
- //#region src/react/conversation-list.d.ts
99
+ //#region src/conversation-list.d.ts
100
100
  interface ConversationListProps {
101
101
  conversations: Conversation$1[];
102
102
  isLoading: boolean;
@@ -124,10 +124,26 @@ declare function ConversationItem({
124
124
  onClick
125
125
  }: ConversationItemProps): react_jsx_runtime0.JSX.Element;
126
126
  //#endregion
127
- //#region src/react/utils.d.ts
127
+ //#region src/conversation-filter-chips.d.ts
128
+ type ConversationFilterValue = "all" | "unread";
129
+ interface ConversationFilterChipsProps {
130
+ value: ConversationFilterValue;
131
+ onValueChange: (value: ConversationFilterValue) => void;
132
+ unreadCount?: number;
133
+ className?: string;
134
+ }
135
+ declare function ConversationFilterChips({
136
+ value,
137
+ onValueChange,
138
+ unreadCount,
139
+ className
140
+ }: ConversationFilterChipsProps): react_jsx_runtime0.JSX.Element;
141
+ //#endregion
142
+ //#region src/utils.d.ts
128
143
  declare function cn(...inputs: ClassValue[]): string;
144
+ declare function getDisplayDate(dateStr: string): string;
129
145
  //#endregion
130
- //#region src/react/message-input.d.ts
146
+ //#region src/message-input.d.ts
131
147
  interface MessageInputProps {
132
148
  onSend: (text: string) => void | Promise<void>;
133
149
  conversation?: Conversation$1 | null;
@@ -148,4 +164,4 @@ declare function MessageInput({
148
164
  contextWindowOpen
149
165
  }: MessageInputProps): react_jsx_runtime0.JSX.Element;
150
166
  //#endregion
151
- export { type Conversation, ConversationItem, ConversationList, type ConversationRecord, FormattedMessage, type FreeformMessageWindow, MessageBubble, MessageBubbleProps, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, type UIMessage, type UIMessageStatus, WhatsappDashboard, cn, useWhatsappDashboard };
167
+ export { type Conversation, ConversationFilterChips, ConversationFilterValue, ConversationItem, ConversationList, type ConversationRecord, FormattedMessage, type FreeformMessageWindow, MessageBubble, MessageBubbleProps, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, type UIMessage, type UIMessageStatus, WhatsappDashboard, cn, getDisplayDate, useWhatsappDashboard };
package/dist/index.d.mts CHANGED
@@ -3,7 +3,7 @@ import { ClassValue } from "clsx";
3
3
  import * as react_jsx_runtime0 from "react/jsx-runtime";
4
4
  import { Conversation, Conversation as Conversation$1, ConversationRecord, FreeformMessageWindow, UIMessage, UIMessage as UIMessage$1, UIMessageStatus, UIMessageStatus as UIMessageStatus$1 } from "better-zap";
5
5
 
6
- //#region src/react/whatsapp-dashboard.d.ts
6
+ //#region src/whatsapp-dashboard.d.ts
7
7
  type MobileView = "list" | "chat";
8
8
  interface WhatsappDashboardContextValue {
9
9
  isMobile: boolean;
@@ -22,7 +22,7 @@ declare function WhatsappDashboard({
22
22
  ...props
23
23
  }: WhatsappDashboardProps): react_jsx_runtime0.JSX.Element;
24
24
  //#endregion
25
- //#region src/react/message-view.d.ts
25
+ //#region src/message-view.d.ts
26
26
  interface MessageViewProps extends React.HTMLAttributes<HTMLDivElement> {
27
27
  children?: React.ReactNode;
28
28
  }
@@ -71,7 +71,7 @@ declare function MessageViewEmpty({
71
71
  ...props
72
72
  }: React.HTMLAttributes<HTMLDivElement>): react_jsx_runtime0.JSX.Element;
73
73
  //#endregion
74
- //#region src/react/message-bubble.d.ts
74
+ //#region src/message-bubble.d.ts
75
75
  interface MessageBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
76
76
  content: string;
77
77
  sender: "user" | "bot";
@@ -96,7 +96,7 @@ declare function FormattedMessage({
96
96
  text: string;
97
97
  }): react_jsx_runtime0.JSX.Element | null;
98
98
  //#endregion
99
- //#region src/react/conversation-list.d.ts
99
+ //#region src/conversation-list.d.ts
100
100
  interface ConversationListProps {
101
101
  conversations: Conversation$1[];
102
102
  isLoading: boolean;
@@ -124,10 +124,26 @@ declare function ConversationItem({
124
124
  onClick
125
125
  }: ConversationItemProps): react_jsx_runtime0.JSX.Element;
126
126
  //#endregion
127
- //#region src/react/utils.d.ts
127
+ //#region src/conversation-filter-chips.d.ts
128
+ type ConversationFilterValue = "all" | "unread";
129
+ interface ConversationFilterChipsProps {
130
+ value: ConversationFilterValue;
131
+ onValueChange: (value: ConversationFilterValue) => void;
132
+ unreadCount?: number;
133
+ className?: string;
134
+ }
135
+ declare function ConversationFilterChips({
136
+ value,
137
+ onValueChange,
138
+ unreadCount,
139
+ className
140
+ }: ConversationFilterChipsProps): react_jsx_runtime0.JSX.Element;
141
+ //#endregion
142
+ //#region src/utils.d.ts
128
143
  declare function cn(...inputs: ClassValue[]): string;
144
+ declare function getDisplayDate(dateStr: string): string;
129
145
  //#endregion
130
- //#region src/react/message-input.d.ts
146
+ //#region src/message-input.d.ts
131
147
  interface MessageInputProps {
132
148
  onSend: (text: string) => void | Promise<void>;
133
149
  conversation?: Conversation$1 | null;
@@ -148,4 +164,4 @@ declare function MessageInput({
148
164
  contextWindowOpen
149
165
  }: MessageInputProps): react_jsx_runtime0.JSX.Element;
150
166
  //#endregion
151
- export { type Conversation, ConversationItem, ConversationList, type ConversationRecord, FormattedMessage, type FreeformMessageWindow, MessageBubble, MessageBubbleProps, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, type UIMessage, type UIMessageStatus, WhatsappDashboard, cn, useWhatsappDashboard };
167
+ export { type Conversation, ConversationFilterChips, ConversationFilterValue, ConversationItem, ConversationList, type ConversationRecord, FormattedMessage, type FreeformMessageWindow, MessageBubble, MessageBubbleProps, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, type UIMessage, type UIMessageStatus, WhatsappDashboard, cn, getDisplayDate, useWhatsappDashboard };
package/dist/index.mjs CHANGED
@@ -6,12 +6,27 @@ import { HugeiconsIcon } from "@hugeicons/react";
6
6
  import { Add01Icon, ArrowLeft02Icon, Clock01Icon, InformationCircleIcon, Message01Icon, Mic01Icon, Search01Icon, Sent02Icon, SmileIcon, UserIcon } from "@hugeicons/core-free-icons";
7
7
  import { cva } from "class-variance-authority";
8
8
  import { resolveConversationFreeformMessageWindow } from "better-zap";
9
- //#region src/react/utils.ts
9
+ //#region src/utils.ts
10
10
  function cn(...inputs) {
11
11
  return twMerge(clsx(inputs));
12
12
  }
13
+ function getDisplayDate(dateStr) {
14
+ const dateObj = new Date(dateStr);
15
+ const now = /* @__PURE__ */ new Date();
16
+ const isToday = dateObj.toDateString() === now.toDateString();
17
+ const yesterday = new Date(now);
18
+ yesterday.setDate(yesterday.getDate() - 1);
19
+ const isYesterday = dateObj.toDateString() === yesterday.toDateString();
20
+ if (isToday) return "HOJE";
21
+ else if (isYesterday) return "ONTEM";
22
+ else return dateObj.toLocaleDateString("pt-BR", {
23
+ day: "2-digit",
24
+ month: "2-digit",
25
+ year: "numeric"
26
+ });
27
+ }
13
28
  //#endregion
14
- //#region src/react/whatsapp-dashboard.tsx
29
+ //#region src/whatsapp-dashboard.tsx
15
30
  const MOBILE_BREAKPOINT = 1024;
16
31
  function useIsMobile() {
17
32
  const [isMobile, setIsMobile] = useState(false);
@@ -52,7 +67,7 @@ function WhatsappDashboard({ children, className, defaultMobileView = "list", ..
52
67
  });
53
68
  }
54
69
  //#endregion
55
- //#region src/react/message-bubble.tsx
70
+ //#region src/message-bubble.tsx
56
71
  const bubbleVariants = cva("relative shadow-[0_1px_0.5px_rgba(11,20,26,0.13)] rounded-lg px-3 py-2 max-w-[65%]", { variants: { variant: {
57
72
  outgoing: "bg-green-100 text-green-900 rounded-tr-none",
58
73
  incoming: "bg-gray-100 text-gray-900 rounded-tl-none",
@@ -150,24 +165,7 @@ function FormattedMessage({ text }) {
150
165
  }) });
151
166
  }
152
167
  //#endregion
153
- //#region src/date.ts
154
- function getDisplayDate(dateStr) {
155
- const dateObj = new Date(dateStr);
156
- const now = /* @__PURE__ */ new Date();
157
- const isToday = dateObj.toDateString() === now.toDateString();
158
- const yesterday = new Date(now);
159
- yesterday.setDate(yesterday.getDate() - 1);
160
- const isYesterday = dateObj.toDateString() === yesterday.toDateString();
161
- if (isToday) return "HOJE";
162
- else if (isYesterday) return "ONTEM";
163
- else return dateObj.toLocaleDateString("pt-BR", {
164
- day: "2-digit",
165
- month: "2-digit",
166
- year: "numeric"
167
- });
168
- }
169
- //#endregion
170
- //#region src/react/message-view.tsx
168
+ //#region src/message-view.tsx
171
169
  function MessageView({ children, className, ...props }) {
172
170
  const { isMobile, mobileView } = useWhatsappDashboard();
173
171
  const hasContent = React.Children.count(children) > 0;
@@ -344,7 +342,7 @@ function MessageViewEmpty({ className, ...props }) {
344
342
  });
345
343
  }
346
344
  //#endregion
347
- //#region src/react/conversation-search.tsx
345
+ //#region src/conversation-search.tsx
348
346
  function ConversationSearch({ value, onChange, className }) {
349
347
  return /* @__PURE__ */ jsx("div", {
350
348
  className: cn("border-b border-[#e9edef] shrink-0 p-2", className),
@@ -365,11 +363,46 @@ function ConversationSearch({ value, onChange, className }) {
365
363
  });
366
364
  }
367
365
  //#endregion
368
- //#region src/react/conversation-list.tsx
366
+ //#region src/conversation-filter-chips.tsx
367
+ const chips = [{
368
+ label: "Tudo",
369
+ value: "all"
370
+ }, {
371
+ label: "Não lidas",
372
+ value: "unread"
373
+ }];
374
+ function ConversationFilterChips({ value, onValueChange, unreadCount = 0, className }) {
375
+ return /* @__PURE__ */ jsx("div", {
376
+ className: cn("flex items-center gap-2 px-3 py-3", className),
377
+ children: chips.map((chip) => {
378
+ const isActive = chip.value === value;
379
+ const showCount = chip.value === "unread" && unreadCount > 0;
380
+ return /* @__PURE__ */ jsxs("button", {
381
+ type: "button",
382
+ onClick: () => onValueChange(chip.value),
383
+ "aria-pressed": isActive,
384
+ className: cn("inline-flex h-8 items-center rounded-full border px-4 text-[15px] font-medium transition-colors", isActive ? "border-[#b8e6c1] bg-[#e7fce3] text-[#017561]" : "border-[#d1d7db] bg-white text-[#54656f] hover:bg-[#f5f6f6]"),
385
+ children: [/* @__PURE__ */ jsx("span", { children: chip.label }), showCount ? /* @__PURE__ */ jsx("span", {
386
+ className: "ml-1",
387
+ children: unreadCount
388
+ }) : null]
389
+ }, chip.value);
390
+ })
391
+ });
392
+ }
393
+ //#endregion
394
+ //#region src/conversation-list.tsx
369
395
  function ConversationList({ conversations, isLoading, isError, selectedConversationId, onSelect, className }) {
370
396
  const { isMobile, mobileView, setMobileView } = useWhatsappDashboard();
371
397
  const [search, setSearch] = useState("");
372
- const filtered = conversations.filter((c) => c.phone.includes(search) || c.contactName?.toLowerCase().includes(search.toLowerCase()));
398
+ const [filter, setFilter] = useState("all");
399
+ const normalizedSearch = search.trim().toLowerCase();
400
+ const unreadConversationsCount = conversations.filter((c) => c.unreadCount > 0).length;
401
+ const filtered = conversations.filter((conversation) => {
402
+ const matchesSearch = normalizedSearch.length === 0 || conversation.phone.toLowerCase().includes(normalizedSearch) || conversation.contactName?.toLowerCase().includes(normalizedSearch);
403
+ const matchesFilter = filter === "all" || conversation.unreadCount > 0;
404
+ return matchesSearch && matchesFilter;
405
+ });
373
406
  const handleSelect = (id) => {
374
407
  onSelect(id);
375
408
  setMobileView("chat");
@@ -378,32 +411,40 @@ function ConversationList({ conversations, isLoading, isError, selectedConversat
378
411
  return /* @__PURE__ */ jsxs("div", {
379
412
  className: cn("flex flex-col h-full bg-white border-r border-[#e9edef]", isMobile ? "w-full" : "min-w-[320px] max-w-105", className),
380
413
  style: isVisible ? void 0 : { display: "none" },
381
- children: [/* @__PURE__ */ jsx(ConversationSearch, {
382
- value: search,
383
- onChange: setSearch
384
- }), /* @__PURE__ */ jsx("div", {
385
- className: "flex-1 overflow-y-auto overflow-x-hidden chat-scrollbar",
386
- children: isLoading ? /* @__PURE__ */ jsx("div", {
387
- className: "flex items-center justify-center h-full text-sm text-[#667781]",
388
- children: "Carregando..."
389
- }) : isError ? /* @__PURE__ */ jsx("div", {
390
- className: "flex items-center justify-center h-full text-sm text-red-500",
391
- children: "Erro ao carregar conversas"
392
- }) : filtered.length === 0 ? /* @__PURE__ */ jsxs("div", {
393
- className: "flex flex-col items-center justify-center h-full gap-2 text-[#667781]",
394
- children: [/* @__PURE__ */ jsx(HugeiconsIcon, {
395
- icon: Message01Icon,
396
- size: 32
397
- }), /* @__PURE__ */ jsx("p", {
398
- className: "text-sm",
399
- children: "Nenhuma conversa encontrada"
400
- })]
401
- }) : filtered.map((conversation) => /* @__PURE__ */ jsx(ConversationItem, {
402
- conversation,
403
- isSelected: selectedConversationId === conversation.id,
404
- onClick: () => handleSelect(conversation.id)
405
- }, conversation.id))
406
- })]
414
+ children: [
415
+ /* @__PURE__ */ jsx(ConversationSearch, {
416
+ value: search,
417
+ onChange: setSearch
418
+ }),
419
+ /* @__PURE__ */ jsx(ConversationFilterChips, {
420
+ value: filter,
421
+ onValueChange: setFilter,
422
+ unreadCount: unreadConversationsCount
423
+ }),
424
+ /* @__PURE__ */ jsx("div", {
425
+ className: "flex-1 overflow-y-auto overflow-x-hidden chat-scrollbar",
426
+ children: isLoading ? /* @__PURE__ */ jsx("div", {
427
+ className: "flex items-center justify-center h-full text-sm text-[#667781]",
428
+ children: "Carregando..."
429
+ }) : isError ? /* @__PURE__ */ jsx("div", {
430
+ className: "flex items-center justify-center h-full text-sm text-red-500",
431
+ children: "Erro ao carregar conversas"
432
+ }) : filtered.length === 0 ? /* @__PURE__ */ jsxs("div", {
433
+ className: "flex flex-col items-center justify-center h-full gap-2 text-[#667781]",
434
+ children: [/* @__PURE__ */ jsx(HugeiconsIcon, {
435
+ icon: Message01Icon,
436
+ size: 32
437
+ }), /* @__PURE__ */ jsx("p", {
438
+ className: "text-sm",
439
+ children: "Nenhuma conversa encontrada"
440
+ })]
441
+ }) : filtered.map((conversation) => /* @__PURE__ */ jsx(ConversationItem, {
442
+ conversation,
443
+ isSelected: selectedConversationId === conversation.id,
444
+ onClick: () => handleSelect(conversation.id)
445
+ }, conversation.id))
446
+ })
447
+ ]
407
448
  });
408
449
  }
409
450
  function ConversationItem({ conversation, isSelected, onClick }) {
@@ -466,7 +507,7 @@ function formatTime(dateStr) {
466
507
  }
467
508
  }
468
509
  //#endregion
469
- //#region src/react/message-input.tsx
510
+ //#region src/message-input.tsx
470
511
  function MessageInput({ onSend, conversation, messages, disabled, placeholder = "Digite uma mensagem", className, contextWindowOpen = true }) {
471
512
  const [text, setText] = useState("");
472
513
  const [isSending, setIsSending] = useState(false);
@@ -581,4 +622,4 @@ function MessageInput({ onSend, conversation, messages, disabled, placeholder =
581
622
  });
582
623
  }
583
624
  //#endregion
584
- export { ConversationItem, ConversationList, FormattedMessage, MessageBubble, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, WhatsappDashboard, cn, useWhatsappDashboard };
625
+ export { ConversationFilterChips, ConversationItem, ConversationList, FormattedMessage, MessageBubble, MessageInput, MessageList, MessageView, MessageViewContent, MessageViewEmpty, MessageViewHeader, WhatsappDashboard, cn, getDisplayDate, useWhatsappDashboard };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-zap/react",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "React components for Better Zap.",
5
5
  "license": "ISC",
6
6
  "type": "module",
@@ -36,7 +36,7 @@
36
36
  "class-variance-authority": "^0.7.1",
37
37
  "clsx": "^2.1.1",
38
38
  "tailwind-merge": "^3.0.0",
39
- "better-zap": "0.0.2"
39
+ "better-zap": "0.0.4"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "react": "^19.0.0",
@@ -46,7 +46,7 @@
46
46
  "@types/react": "^19.0.0",
47
47
  "@types/react-dom": "^19.0.0",
48
48
  "tsdown": "^0.21.2",
49
- "typescript": "^5.9.3",
49
+ "typescript": "^6.0.2",
50
50
  "vitest": "^4.1.0"
51
51
  },
52
52
  "scripts": {