@triadxyz/widgets 0.0.1 → 0.0.3

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/.yarnrc.yml ADDED
@@ -0,0 +1 @@
1
+ nodeLinker: node-modules
package/dist/index.d.mts CHANGED
@@ -8,7 +8,7 @@ interface ButtonWidgetProps extends React.ButtonHTMLAttributes<HTMLButtonElement
8
8
  declare const ButtonWidget: React.FC<ButtonWidgetProps>;
9
9
 
10
10
  interface ChatMessage {
11
- authority: string;
11
+ authority?: string;
12
12
  name: string;
13
13
  image: string;
14
14
  predictionsCount: number;
@@ -36,9 +36,14 @@ interface LiveChatProps {
36
36
  classNames?: LiveChatClassNames;
37
37
  renderMessage?: (message: ChatMessage) => React.ReactNode;
38
38
  renderHeader?: () => React.ReactNode;
39
- authority: string;
39
+ authority: string | null;
40
40
  customerAuthority: string;
41
+ onConnectWallet?: () => void;
42
+ fallbackMessages?: {
43
+ connectWallet: string;
44
+ description: string;
45
+ };
41
46
  }
42
- declare function LiveChat({ isOpen, onClose, title, theme, classNames, renderMessage, renderHeader, authority, customerAuthority, }: LiveChatProps): react_jsx_runtime.JSX.Element | null;
47
+ declare function LiveChat({ isOpen, onClose, title, theme, classNames, renderMessage, renderHeader, authority, customerAuthority, fallbackMessages, onConnectWallet, }: LiveChatProps): react_jsx_runtime.JSX.Element | null;
43
48
 
44
49
  export { ButtonWidget, type ButtonWidgetProps, LiveChat, type LiveChatClassNames, type LiveChatProps, type LiveChatTheme };
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ interface ButtonWidgetProps extends React.ButtonHTMLAttributes<HTMLButtonElement
8
8
  declare const ButtonWidget: React.FC<ButtonWidgetProps>;
9
9
 
10
10
  interface ChatMessage {
11
- authority: string;
11
+ authority?: string;
12
12
  name: string;
13
13
  image: string;
14
14
  predictionsCount: number;
@@ -36,9 +36,14 @@ interface LiveChatProps {
36
36
  classNames?: LiveChatClassNames;
37
37
  renderMessage?: (message: ChatMessage) => React.ReactNode;
38
38
  renderHeader?: () => React.ReactNode;
39
- authority: string;
39
+ authority: string | null;
40
40
  customerAuthority: string;
41
+ onConnectWallet?: () => void;
42
+ fallbackMessages?: {
43
+ connectWallet: string;
44
+ description: string;
45
+ };
41
46
  }
42
- declare function LiveChat({ isOpen, onClose, title, theme, classNames, renderMessage, renderHeader, authority, customerAuthority, }: LiveChatProps): react_jsx_runtime.JSX.Element | null;
47
+ declare function LiveChat({ isOpen, onClose, title, theme, classNames, renderMessage, renderHeader, authority, customerAuthority, fallbackMessages, onConnectWallet, }: LiveChatProps): react_jsx_runtime.JSX.Element | null;
43
48
 
44
49
  export { ButtonWidget, type ButtonWidgetProps, LiveChat, type LiveChatClassNames, type LiveChatProps, type LiveChatTheme };
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- 'use strict';var jsxRuntime=require('react/jsx-runtime'),react=require('react'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),S=require('socket.io-client'),dateFns=require('date-fns');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var S__default=/*#__PURE__*/_interopDefault(S);var W=({label:s,variant:n="primary",className:p="",...m})=>jsxRuntime.jsx("button",{className:`px-4 py-2 rounded-lg font-medium transition-colors ${{primary:"bg-blue-600 text-white hover:bg-blue-700",secondary:"bg-gray-200 text-gray-800 hover:bg-gray-300"}[n]} ${p}`,...m,children:s});function d(...s){return tailwindMerge.twMerge(clsx.clsx(s))}var T=S__default.default("https://beta.triadfi.co",{path:"/socket.io",reconnection:true,reconnectionAttempts:5,reconnectionDelay:1e3,randomizationFactor:.5,timeout:5e3,transports:["websocket"]}),a=T;function w({authority:s,customerAuthority:n}){let[p,m]=react.useState([]),[i,u]=react.useState(0);return react.useEffect(()=>{if(!(!n))return a.connected||a.connect(),a.emit("chat:join",{authority:s,customerAuthority:n},r=>{r.error&&console.error("join error",r.error);}),a.off("chat:history"),a.on("chat:history",r=>{m(c=>c.length?c:r);}),a.off("chat:message"),a.on("chat:message",r=>{m(c=>[...c,r]);}),a.off("chat:users"),a.on("chat:users",r=>{u(r.count);}),()=>{a.off("chat:history"),a.off("chat:message"),a.off("chat:users");}},[s,n]),{messages:p,onlineCount:i,sendMessage:r=>{a.emit("chat:message",{authority:s,customerAuthority:n,message:r},c=>{c.error&&console.error("send error",c.error);});}}}function se({isOpen:s,onClose:n,title:p="Live Chat",theme:m,classNames:i,renderMessage:u,renderHeader:f,authority:r,customerAuthority:c}){let[l,g]=react.useState(""),x=react.useRef(null),h=m?.primaryColor||"#FF3D00",L=m?.background||"var(--chat-bg)",{sendMessage:R,onlineCount:D,messages:b}=w({authority:r||"random",customerAuthority:c}),z=()=>{x.current?.scrollIntoView({behavior:"smooth"});};react.useEffect(()=>{z();},[b]);let v=()=>{l.trim()&&(g(""),R(l));},k=t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),v());};return s?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("style",{children:`
1
+ 'use strict';var jsxRuntime=require('react/jsx-runtime'),react=require('react'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),S=require('socket.io-client'),dateFns=require('date-fns');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var S__default=/*#__PURE__*/_interopDefault(S);var I=({label:o,variant:n="primary",className:p="",...m})=>jsxRuntime.jsx("button",{className:`px-4 py-2 rounded-lg font-medium transition-colors ${{primary:"bg-blue-600 text-white hover:bg-blue-700",secondary:"bg-gray-200 text-gray-800 hover:bg-gray-300"}[n]} ${p}`,...m,children:o});function d(...o){return tailwindMerge.twMerge(clsx.clsx(o))}var T=S__default.default("https://beta.triadfi.co",{path:"/socket.io",reconnection:true,reconnectionAttempts:5,reconnectionDelay:1e3,randomizationFactor:.5,timeout:5e3,transports:["websocket"]}),s=T;function L({authority:o,customerAuthority:n}){let[p,m]=react.useState([]),[i,u]=react.useState(0);return react.useEffect(()=>{if(!(!o||!n))return s.connected||s.connect(),s.emit("chat:join",{authority:o,customerAuthority:n},t=>{t.error&&console.error("join error",t.error);}),s.off("chat:history"),s.on("chat:history",t=>{m(l=>l.length?l:t);}),s.off("chat:message"),s.on("chat:message",t=>{m(l=>[...l,t]);}),s.off("chat:users"),s.on("chat:users",t=>{u(t.count);}),()=>{s.off("chat:history"),s.off("chat:message"),s.off("chat:users");}},[o,n]),{messages:p,onlineCount:i,sendMessage:t=>{s.emit("chat:message",{authority:o,customerAuthority:n,message:t},l=>{l.error&&console.error("send error",l.error);});}}}function ie({isOpen:o,onClose:n,title:p="Live Chat",theme:m,classNames:i,renderMessage:u,renderHeader:h,authority:t,customerAuthority:l,fallbackMessages:f,onConnectWallet:g}){let[c,b]=react.useState(""),v=react.useRef(null),x=m?.primaryColor||"#FF3D00",M=m?.background||"var(--chat-bg)",{sendMessage:R,onlineCount:E,messages:y}=L({authority:t||void 0,customerAuthority:l}),j=()=>{v.current?.scrollIntoView({behavior:"smooth"});};react.useEffect(()=>{j();},[y]);let k=()=>{c.trim()&&(b(""),R(c));},C=a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),k());};return o?jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("style",{children:`
2
2
  :root {
3
3
  --chat-bg: #ffffff;
4
4
  }
5
5
  .dark {
6
6
  --chat-bg: #15181D;
7
7
  }
8
- `}),jsxRuntime.jsxs("div",{onClick:t=>t.stopPropagation(),className:d("fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl",i?.container),style:{top:"75px",width:"340px",height:"800px",maxHeight:"calc(100vh - 90px)",background:L},children:[f?f():jsxRuntime.jsxs("div",{className:d("flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10",i?.header),children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-3",children:[jsxRuntime.jsx("h2",{className:"text-lg font-semibold text-triad-dark-100 dark:text-white",children:p}),jsxRuntime.jsxs("div",{className:"flex items-center gap-1.5",children:[jsxRuntime.jsx("div",{className:"size-2 rounded-full bg-green-500 animate-pulse"}),jsxRuntime.jsxs("span",{className:"text-xs text-black/50 dark:text-white/50",children:[D," online"]})]})]}),jsxRuntime.jsx("button",{onClick:n,children:jsxRuntime.jsx(lucideReact.X,{size:18})})]}),jsxRuntime.jsxs("div",{className:d("flex-1 overflow-y-auto px-6 py-4 space-y-4",i?.messages),children:[b.map((t,y)=>u?u(t):jsxRuntime.jsxs("div",{className:`flex flex-col gap-1 ${t.authority===r?"items-end":"items-start"}`,children:[t.authority!==r&&jsxRuntime.jsx("span",{className:"text-xs font-medium text-triad-dark-100 dark:text-white",children:t.name}),jsxRuntime.jsx("div",{className:d("max-w-[75%] rounded-2xl px-4 py-2.5",t.authority===r?"text-white rounded-br-sm":"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm"),style:t.authority===r?{backgroundColor:h}:void 0,children:jsxRuntime.jsx("p",{className:"text-sm break-words",children:t.message})}),jsxRuntime.jsx("span",{className:"text-[10px] opacity-50",children:dateFns.format(t.timestamp,"HH:mm")})]},y)),jsxRuntime.jsx("div",{ref:x})]}),jsxRuntime.jsx("div",{className:"px-6 py-4 border-t border-black/10 dark:border-white/10",children:jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsx("input",{value:l,onChange:t=>g(t.target.value),onKeyDown:k,placeholder:"Digite sua mensagem...",className:d("flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none",i?.input)}),jsxRuntime.jsx("button",{onClick:v,disabled:!l.trim(),className:d("flex items-center justify-center size-10 rounded-xl transition-colors",i?.button),style:{backgroundColor:l.trim()?h:void 0,opacity:l.trim()?1:.5},children:jsxRuntime.jsx(lucideReact.Send,{size:18,className:"dark:text-white text-app-gay-400"})})]})})]}),jsxRuntime.jsx("div",{className:"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]",children:jsxRuntime.jsxs("div",{className:"flex-1 flex flex-col",children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between px-4 py-4 border-b",children:[jsxRuntime.jsx("h2",{children:p}),jsxRuntime.jsx("button",{onClick:n,children:jsxRuntime.jsx(lucideReact.X,{})})]}),jsxRuntime.jsxs("div",{className:"flex-1 overflow-y-auto px-4 py-4 space-y-4",children:[b.map((t,y)=>jsxRuntime.jsx("div",{children:t.message},y)),jsxRuntime.jsx("div",{ref:x})]}),jsxRuntime.jsxs("div",{className:"p-4 border-t flex gap-2",children:[jsxRuntime.jsx("input",{value:l,onChange:t=>g(t.target.value),onKeyDown:k,className:"flex-1"}),jsxRuntime.jsx("button",{className:d(i?.button),style:{backgroundColor:l.trim()?h:void 0,opacity:l.trim()?1:.5},onClick:v,children:jsxRuntime.jsx(lucideReact.Send,{className:"dark:text-white text-app-gay-400"})})]})]})})]}):null}exports.ButtonWidget=W;exports.LiveChat=se;//# sourceMappingURL=index.js.map
8
+ `}),jsxRuntime.jsxs("div",{onClick:a=>a.stopPropagation(),className:d("fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl",i?.container),style:{top:"75px",width:"340px",height:t?"800px":"auto",maxHeight:"calc(100vh - 90px)",background:M},children:[h?h():jsxRuntime.jsxs("div",{className:d("flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10",i?.header),children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-3",children:[jsxRuntime.jsx("h2",{className:"text-lg font-semibold text-triad-dark-100 dark:text-white",children:p}),jsxRuntime.jsxs("div",{className:"flex items-center gap-1.5",children:[jsxRuntime.jsx("div",{className:"size-2 rounded-full bg-green-500 animate-pulse"}),jsxRuntime.jsxs("span",{className:"text-xs text-app-gray-400 dark:text-app-gray-100",children:[E," online"]})]})]}),jsxRuntime.jsx("button",{onClick:n,children:jsxRuntime.jsx(lucideReact.X,{className:"dark:text-white text-black",size:18})})]}),t&&jsxRuntime.jsxs("div",{className:d("flex-1 overflow-y-auto px-6 py-4 space-y-4",i?.messages),children:[y.map((a,w)=>u?u(a):jsxRuntime.jsxs("div",{className:`flex flex-col gap-1 ${a.authority===t?"items-end":"items-start"}`,children:[a.authority!==t&&jsxRuntime.jsx("span",{className:"text-xs font-medium text-triad-dark-100 dark:text-white",children:a.name}),jsxRuntime.jsx("div",{className:d("max-w-[75%] rounded-2xl px-4 py-2.5",a.authority===t?"text-white rounded-br-sm":"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm"),style:a.authority===t?{backgroundColor:x}:void 0,children:jsxRuntime.jsx("p",{className:"text-sm break-words",children:a.message})}),jsxRuntime.jsx("span",{className:"text-[10px] opacity-50",children:dateFns.format(a.timestamp,"HH:mm")})]},w)),jsxRuntime.jsx("div",{ref:v})]}),jsxRuntime.jsx("div",{className:"px-6 py-4 border-t border-black/10 dark:border-white/10",children:t?jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsx("input",{value:c,onChange:a=>b(a.target.value),onKeyDown:C,placeholder:"Digite sua mensagem...",className:d("flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none",i?.input)}),jsxRuntime.jsx("button",{onClick:k,disabled:!c.trim(),className:d("flex items-center justify-center size-10 rounded-xl transition-colors",i?.button),style:{backgroundColor:c.trim()?x:void 0,opacity:c.trim()?1:.5},children:jsxRuntime.jsx(lucideReact.Send,{size:18,className:"dark:text-white text-app-gay-400"})})]}):jsxRuntime.jsxs("div",{className:"flex flex-col items-center justify-center gap-3 py-4 px-3 text-center",children:[jsxRuntime.jsx("div",{className:"flex items-center justify-center size-12 rounded-2xl",style:{background:`${x}15`},children:jsxRuntime.jsx("span",{className:"text-xl",children:"\u{1F4AC}"})}),jsxRuntime.jsxs("div",{className:"flex flex-col gap-1",children:[jsxRuntime.jsx("span",{className:"text-sm font-semibold text-black dark:text-white",children:f?.connectWallet||"Entre no chat"}),jsxRuntime.jsx("span",{className:"text-xs text-black/60 dark:text-white max-w-[220px]",children:f?.description||"Conecte sua carteira para participar das conversas em tempo real"})]}),g&&jsxRuntime.jsx("button",{onClick:g,style:{backgroundColor:x},className:"mt-2 w-full max-w-[220px] px-4 py-2.5 text-white text-sm font-semibold rounded-xl transition-all hover:opacity-90 active:scale-95 shadow-sm",children:"Conectar Carteira"})]})})]}),jsxRuntime.jsx("div",{className:"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]",children:jsxRuntime.jsxs("div",{className:"flex-1 flex flex-col",children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between px-4 py-4 border-b",children:[jsxRuntime.jsx("h2",{children:p}),jsxRuntime.jsx("button",{onClick:n,children:jsxRuntime.jsx(lucideReact.X,{})})]}),jsxRuntime.jsxs("div",{className:"flex-1 overflow-y-auto px-4 py-4 space-y-4",children:[y.map((a,w)=>jsxRuntime.jsx("div",{children:a.message},w)),jsxRuntime.jsx("div",{ref:v})]}),jsxRuntime.jsx("div",{className:"p-4 border-t flex flex-col gap-2",children:t?jsxRuntime.jsxs("div",{className:"flex gap-2 w-full",children:[jsxRuntime.jsx("input",{value:c,onChange:a=>b(a.target.value),onKeyDown:C,className:"flex-1 bg-black/5 dark:bg-white/5 dark:text-white px-4 py-2.5 rounded-xl text-sm outline-none",placeholder:"Digite sua mensagem..."}),jsxRuntime.jsx("button",{className:d("flex items-center justify-center size-10 rounded-xl transition-colors",i?.button),style:{backgroundColor:c.trim()?x:void 0,opacity:c.trim()?1:.5},onClick:k,children:jsxRuntime.jsx(lucideReact.Send,{className:"dark:text-white text-app-gay-400",size:18})})]}):jsxRuntime.jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 py-2",children:[jsxRuntime.jsx("span",{className:"text-sm font-medium text-black/60 dark:text-white/60 text-center",children:f?.description||"Fa\xE7a login para participar do chat"}),g&&jsxRuntime.jsx("button",{onClick:g,style:{backgroundColor:x},className:"px-4 py-2 text-white text-sm font-semibold rounded-xl transition-opacity hover:opacity-90 active:scale-95",children:f?.connectWallet||"Fazer Login"})]})})]})})]}):null}exports.ButtonWidget=I;exports.LiveChat=ie;//# sourceMappingURL=index.js.map
9
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ButtonWidget.tsx","../src/utils/cn.ts","../src/utils/socket.ts","../src/hooks/useChat.ts","../src/components/LiveChat.tsx"],"names":["ButtonWidget","label","variant","className","props","jsx","cn","classes","twMerge","clsx","socket","io","socket_default","useChat","authority","customerAuthority","messages","setMessages","useState","onlineCount","setOnlineCount","useEffect","res","msgs","prev","msg","data","message","LiveChat","isOpen","onClose","title","theme","classNames","renderMessage","renderHeader","inputValue","setInputValue","messagesEndRef","useRef","primary","background","sendMessage","scrollToBottom","handleSendMessage","handleKeyDown","e","jsxs","Fragment","X","idx","format","Send","m"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport React from 'react';\n\nexport interface ButtonWidgetProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n label: string;\n variant?: 'primary' | 'secondary';\n}\n\nexport const ButtonWidget: React.FC<ButtonWidgetProps> = ({ \n label, \n variant = 'primary', \n className = '',\n ...props \n}) => {\n const baseStyles = 'px-4 py-2 rounded-lg font-medium transition-colors';\n const variants = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700',\n secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'\n };\n\n return (\n <button \n className={`${baseStyles} ${variants[variant]} ${className}`}\n {...props}\n >\n {label}\n </button>\n );\n};\n","import type { ClassValue } from \"clsx\";\nimport { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...classes: ClassValue[]) {\n return twMerge(clsx(classes));\n}\n","import io from \"socket.io-client\";\n\nconst socket = io(\"https://beta.triadfi.co\", {\n path: \"/socket.io\",\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n randomizationFactor: 0.5,\n timeout: 5000,\n transports: [\"websocket\"],\n});\n\nexport default socket;\n","import socket from \"@/utils/socket\";\nimport { useEffect, useState } from \"react\";\n\nexport interface ChatMessage {\n authority: string;\n name: string;\n image: string;\n predictionsCount: number;\n message: string;\n timestamp: number;\n}\n\nexport function useChat({\n authority,\n customerAuthority,\n}: {\n authority: string;\n customerAuthority: string;\n}) {\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [onlineCount, setOnlineCount] = useState(0);\n\n useEffect(() => {\n if (!authority || !customerAuthority) return;\n\n if (!socket.connected) {\n socket.connect();\n }\n\n socket.emit(\"chat:join\", { authority, customerAuthority }, (res: any) => {\n if (res.error) {\n console.error(\"join error\", res.error);\n }\n });\n\n socket.off(\"chat:history\");\n socket.on(\"chat:history\", (msgs) => {\n setMessages((prev) => (prev.length ? prev : msgs));\n });\n\n socket.off(\"chat:message\");\n socket.on(\"chat:message\", (msg) => {\n setMessages((prev) => [...prev, msg]);\n });\n\n socket.off(\"chat:users\");\n socket.on(\"chat:users\", (data) => {\n setOnlineCount(data.count);\n });\n\n return () => {\n socket.off(\"chat:history\");\n socket.off(\"chat:message\");\n socket.off(\"chat:users\");\n };\n }, [authority, customerAuthority]);\n\n const sendMessage = (message: string) => {\n socket.emit(\n \"chat:message\",\n { authority, customerAuthority, message },\n (res: any) => {\n if (res.error) {\n console.error(\"send error\", res.error);\n }\n },\n );\n };\n\n return {\n messages,\n onlineCount,\n sendMessage,\n };\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { X, Send } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useChat, ChatMessage } from \"@/hooks/useChat\";\nimport { format } from \"date-fns\";\n\nexport interface LiveChatTheme {\n primaryColor?: string;\n background?: string;\n textColor?: string;\n}\n\nexport interface LiveChatClassNames {\n container?: string;\n header?: string;\n messages?: string;\n input?: string;\n button?: string;\n}\n\nexport interface LiveChatProps {\n isOpen: boolean;\n onClose: () => void;\n\n // ui\n title?: string;\n\n // customization\n theme?: LiveChatTheme;\n classNames?: LiveChatClassNames;\n\n // slots\n renderMessage?: (message: ChatMessage) => React.ReactNode;\n renderHeader?: () => React.ReactNode;\n authority: string;\n customerAuthority: string;\n}\n\nexport function LiveChat({\n isOpen,\n onClose,\n title = \"Live Chat\",\n theme,\n classNames,\n renderMessage,\n renderHeader,\n authority,\n customerAuthority,\n}: LiveChatProps) {\n const [inputValue, setInputValue] = useState(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const primary = theme?.primaryColor || \"#FF3D00\";\n const background = theme?.background || \"var(--chat-bg)\";\n const { sendMessage, onlineCount, messages } = useChat({\n authority: authority || \"random\",\n customerAuthority: customerAuthority,\n });\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n const handleSendMessage = () => {\n if (!inputValue.trim()) return;\n setInputValue(\"\");\n sendMessage(inputValue);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSendMessage();\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <>\n <style>{`\n :root {\n --chat-bg: #ffffff;\n }\n .dark {\n --chat-bg: #15181D;\n }\n `}</style>\n\n {/* Desktop */}\n <div\n onClick={(e) => e.stopPropagation()}\n className={cn(\n \"fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl\",\n classNames?.container,\n )}\n style={{\n top: \"75px\",\n width: \"340px\",\n height: \"800px\",\n maxHeight: \"calc(100vh - 90px)\",\n background,\n }}\n >\n {/* Header */}\n {renderHeader ? (\n renderHeader()\n ) : (\n <div\n className={cn(\n \"flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10\",\n classNames?.header,\n )}\n >\n <div className=\"flex items-center gap-3\">\n <h2 className=\"text-lg font-semibold text-triad-dark-100 dark:text-white\">\n {title}\n </h2>\n <div className=\"flex items-center gap-1.5\">\n <div className=\"size-2 rounded-full bg-green-500 animate-pulse\" />\n <span className=\"text-xs text-black/50 dark:text-white/50\">\n {onlineCount} online\n </span>\n </div>\n </div>\n <button onClick={onClose}>\n <X size={18} />\n </button>\n </div>\n )}\n\n {/* Messages */}\n <div\n className={cn(\n \"flex-1 overflow-y-auto px-6 py-4 space-y-4\",\n classNames?.messages,\n )}\n >\n {messages.map((message, idx) =>\n renderMessage ? (\n renderMessage(message)\n ) : (\n <div\n key={idx}\n className={`flex flex-col gap-1 ${\n message.authority === authority ? \"items-end\" : \"items-start\"\n }`}\n >\n {message.authority !== authority && (\n <span className=\"text-xs font-medium text-triad-dark-100 dark:text-white\">\n {message.name}\n </span>\n )}\n\n <div\n className={cn(\n \"max-w-[75%] rounded-2xl px-4 py-2.5\",\n message.authority === authority\n ? \"text-white rounded-br-sm\"\n : \"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm\",\n )}\n style={\n message.authority === authority\n ? { backgroundColor: primary }\n : undefined\n }\n >\n <p className=\"text-sm break-words\">{message.message}</p>\n </div>\n\n <span className=\"text-[10px] opacity-50\">\n {format(message.timestamp, \"HH:mm\")}\n </span>\n </div>\n ),\n )}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"px-6 py-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-center gap-2\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Digite sua mensagem...\"\n className={cn(\n \"flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none\",\n classNames?.input,\n )}\n />\n\n <button\n onClick={handleSendMessage}\n disabled={!inputValue.trim()}\n className={cn(\n \"flex items-center justify-center size-10 rounded-xl transition-colors\",\n classNames?.button,\n )}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n >\n <Send size={18} className=\"dark:text-white text-app-gay-400\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Mobile */}\n <div className=\"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]\">\n {/* Reaproveita mesma estrutura */}\n <div className=\"flex-1 flex flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-4 border-b\">\n <h2>{title}</h2>\n <button onClick={onClose}>\n <X />\n </button>\n </div>\n\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto px-4 py-4 space-y-4\">\n {messages.map((m, idx) => (\n <div key={idx}>{m.message}</div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"p-4 border-t flex gap-2\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n className=\"flex-1\"\n />\n <button\n className={cn(classNames?.button)}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n onClick={handleSendMessage}\n >\n <Send className=\"dark:text-white text-app-gay-400\" />\n </button>\n </div>\n </div>\n </div>\n </>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/components/ButtonWidget.tsx","../src/utils/cn.ts","../src/utils/socket.ts","../src/hooks/useChat.ts","../src/components/LiveChat.tsx"],"names":["ButtonWidget","label","variant","className","props","jsx","cn","classes","twMerge","clsx","socket","io","socket_default","useChat","authority","customerAuthority","messages","setMessages","useState","onlineCount","setOnlineCount","useEffect","res","msgs","prev","msg","data","message","LiveChat","isOpen","onClose","title","theme","classNames","renderMessage","renderHeader","fallbackMessages","onConnectWallet","inputValue","setInputValue","messagesEndRef","useRef","primary","background","sendMessage","scrollToBottom","handleSendMessage","handleKeyDown","e","jsxs","Fragment","X","idx","format","Send","m"],"mappings":"2VASO,IAAMA,CAAAA,CAA4C,CAAC,CACxD,KAAA,CAAAC,EACA,OAAA,CAAAC,CAAAA,CAAU,UACV,SAAA,CAAAC,CAAAA,CAAY,GACZ,GAAGC,CACL,IAQIC,cAAAA,CAAC,QAAA,CAAA,CACC,SAAA,CAAW,CAAA,mDAAA,EAPE,CACf,OAAA,CAAS,2CACT,SAAA,CAAW,6CACb,EAIyCH,CAAO,CAAC,IAAIC,CAAS,CAAA,CAAA,CACzD,GAAGC,CAAAA,CAEH,QAAA,CAAAH,CAAAA,CACH,ECvBG,SAASK,CAAAA,CAAAA,GAAMC,EAAuB,CAC3C,OAAOC,sBAAQC,SAAAA,CAAKF,CAAO,CAAC,CAC9B,CCJA,IAAMG,EAASC,kBAAAA,CAAG,yBAAA,CAA2B,CAC3C,IAAA,CAAM,YAAA,CACN,aAAc,IAAA,CACd,oBAAA,CAAsB,CAAA,CACtB,iBAAA,CAAmB,GAAA,CACnB,mBAAA,CAAqB,GACrB,OAAA,CAAS,GAAA,CACT,WAAY,CAAC,WAAW,CAC1B,CAAC,CAAA,CAEMC,CAAAA,CAAQF,CAAAA,CCAR,SAASG,CAAAA,CAAQ,CACtB,SAAA,CAAAC,CAAAA,CACA,kBAAAC,CACF,CAAA,CAGG,CACD,GAAM,CAACC,EAAUC,CAAW,CAAA,CAAIC,eAAwB,EAAE,CAAA,CACpD,CAACC,CAAAA,CAAaC,CAAc,EAAIF,cAAAA,CAAS,CAAC,EAEhD,OAAAG,eAAAA,CAAU,IAAM,CACd,GAAI,EAAA,CAACP,CAAAA,EAAa,CAACC,CAAAA,CAAAA,CAEnB,OAAKH,CAAAA,CAAO,SAAA,EACVA,EAAO,OAAA,EAAQ,CAGjBA,EAAO,IAAA,CAAK,WAAA,CAAa,CAAE,SAAA,CAAAE,CAAAA,CAAW,iBAAA,CAAAC,CAAkB,CAAA,CAAIO,CAAAA,EAAa,CACnEA,CAAAA,CAAI,KAAA,EACN,QAAQ,KAAA,CAAM,YAAA,CAAcA,CAAAA,CAAI,KAAK,EAEzC,CAAC,EAEDV,CAAAA,CAAO,GAAA,CAAI,cAAc,CAAA,CACzBA,CAAAA,CAAO,GAAG,cAAA,CAAiBW,CAAAA,EAAS,CAClCN,CAAAA,CAAaO,CAAAA,EAAUA,CAAAA,CAAK,OAASA,CAAAA,CAAOD,CAAK,EACnD,CAAC,CAAA,CAEDX,EAAO,GAAA,CAAI,cAAc,CAAA,CACzBA,CAAAA,CAAO,EAAA,CAAG,cAAA,CAAiBa,GAAQ,CACjCR,CAAAA,CAAaO,GAAS,CAAC,GAAGA,EAAMC,CAAG,CAAC,EACtC,CAAC,CAAA,CAEDb,CAAAA,CAAO,IAAI,YAAY,CAAA,CACvBA,EAAO,EAAA,CAAG,YAAA,CAAec,GAAS,CAChCN,CAAAA,CAAeM,EAAK,KAAK,EAC3B,CAAC,CAAA,CAEM,IAAM,CACXd,CAAAA,CAAO,GAAA,CAAI,cAAc,CAAA,CACzBA,CAAAA,CAAO,GAAA,CAAI,cAAc,CAAA,CACzBA,CAAAA,CAAO,IAAI,YAAY,EACzB,CACF,CAAA,CAAG,CAACE,EAAWC,CAAiB,CAAC,CAAA,CAc1B,CACL,QAAA,CAAAC,CAAAA,CACA,YAAAG,CAAAA,CACA,WAAA,CAfmBQ,GAAoB,CACvCf,CAAAA,CAAO,KACL,cAAA,CACA,CAAE,SAAA,CAAAE,CAAAA,CAAW,iBAAA,CAAAC,CAAAA,CAAmB,QAAAY,CAAQ,CAAA,CACvCL,GAAa,CACRA,CAAAA,CAAI,OACN,OAAA,CAAQ,KAAA,CAAM,aAAcA,CAAAA,CAAI,KAAK,EAEzC,CACF,EACF,CAMA,CACF,CC7BO,SAASM,EAAAA,CAAS,CACvB,MAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,CAAAA,CACA,KAAA,CAAAC,CAAAA,CAAQ,YACR,KAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CACA,aAAA,CAAAC,EACA,YAAA,CAAAC,CAAAA,CACA,SAAA,CAAArB,CAAAA,CACA,iBAAA,CAAAC,CAAAA,CACA,iBAAAqB,CAAAA,CACA,eAAA,CAAAC,CACF,CAAA,CAAkB,CAChB,GAAM,CAACC,CAAAA,CAAYC,CAAa,CAAA,CAAIrB,cAAAA,CAAS,EAAE,CAAA,CACzCsB,CAAAA,CAAiBC,aAAuB,IAAI,CAAA,CAC5CC,EAAUV,CAAAA,EAAO,YAAA,EAAgB,SAAA,CACjCW,CAAAA,CAAaX,CAAAA,EAAO,UAAA,EAAc,iBAElC,CAAE,WAAA,CAAAY,EAAa,WAAA,CAAAzB,CAAAA,CAAa,SAAAH,CAAS,CAAA,CAAIH,CAAAA,CAAQ,CACrD,SAAA,CAAWC,CAAAA,EAAa,OACxB,iBAAA,CAAmBC,CACrB,CAAC,CAAA,CAEK8B,CAAAA,CAAiB,IAAM,CAC3BL,CAAAA,CAAe,OAAA,EAAS,cAAA,CAAe,CAAE,QAAA,CAAU,QAAS,CAAC,EAC/D,EAEAnB,eAAAA,CAAU,IAAM,CACdwB,CAAAA,GACF,CAAA,CAAG,CAAC7B,CAAQ,CAAC,EAEb,IAAM8B,CAAAA,CAAoB,IAAM,CACzBR,CAAAA,CAAW,MAAK,GACrBC,CAAAA,CAAc,EAAE,CAAA,CAChBK,CAAAA,CAAYN,CAAU,GACxB,CAAA,CAEMS,CAAAA,CAAiBC,GAA2B,CAC5CA,CAAAA,CAAE,MAAQ,OAAA,EAAW,CAACA,CAAAA,CAAE,QAAA,GAC1BA,CAAAA,CAAE,cAAA,GACFF,CAAAA,EAAkB,EAEtB,EAEA,OAAKjB,CAAAA,CAGHoB,gBAAAC,mBAAAA,CAAA,CACE,QAAA,CAAA,CAAA7C,cAAAA,CAAC,OAAA,CAAA,CAAO,QAAA,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAA,CAAA,CAON,CAAA,CAGF4C,eAAAA,CAAC,KAAA,CAAA,CACC,OAAA,CAAUD,CAAAA,EAAMA,EAAE,eAAA,EAAgB,CAClC,SAAA,CAAW1C,CAAAA,CACT,sFAAA,CACA2B,CAAAA,EAAY,SACd,CAAA,CACA,KAAA,CAAO,CACL,GAAA,CAAK,MAAA,CACL,KAAA,CAAO,OAAA,CACP,MAAA,CAASnB,CAAAA,CAAqB,OAAA,CAAT,MAAA,CACrB,SAAA,CAAW,oBAAA,CACX,UAAA,CAAA6B,CACF,CAAA,CAGC,QAAA,CAAA,CAAAR,CAAAA,CACCA,CAAAA,EAAa,CAEbc,eAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAW3C,CAAAA,CACT,2FAAA,CACA2B,CAAAA,EAAY,MACd,CAAA,CAEA,QAAA,CAAA,CAAAgB,gBAAC,KAAA,CAAA,CAAI,SAAA,CAAU,yBAAA,CACb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,IAAA,CAAA,CAAG,SAAA,CAAU,2DAAA,CACX,QAAA,CAAA0B,CAAAA,CACH,CAAA,CACAkB,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,4BACb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,gDAAA,CAAiD,CAAA,CAChE4C,eAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,kDAAA,CACb,QAAA,CAAA,CAAA9B,CAAAA,CAAY,SAAA,CAAA,CACf,CAAA,CAAA,CACF,GACF,CAAA,CACAd,cAAAA,CAAC,QAAA,CAAA,CAAO,OAAA,CAASyB,CAAAA,CACf,QAAA,CAAAzB,cAAAA,CAAC8C,aAAAA,CAAA,CAAE,SAAA,CAAU,4BAAA,CAA6B,IAAA,CAAM,EAAA,CAAI,CAAA,CACtD,GACF,CAAA,CAIDrC,CAAAA,EACCmC,eAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAW3C,CAAAA,CACT,4CAAA,CACA2B,CAAAA,EAAY,QACd,CAAA,CAEC,QAAA,CAAA,CAAAjB,CAAAA,CAAS,GAAA,CAAI,CAACW,EAASyB,CAAAA,GACtBlB,CAAAA,CACEA,CAAAA,CAAcP,CAAO,CAAA,CAErBsB,eAAAA,CAAC,KAAA,CAAA,CAEC,SAAA,CAAW,CAAA,oBAAA,EACTtB,CAAAA,CAAQ,SAAA,GAAcb,CAAAA,CAClB,WAAA,CACA,aACN,GAEC,QAAA,CAAA,CAAAa,CAAAA,CAAQ,SAAA,GAAcb,CAAAA,EACrBT,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,yDAAA,CACb,QAAA,CAAAsB,CAAAA,CAAQ,IAAA,CACX,CAAA,CAGFtB,cAAAA,CAAC,KAAA,CAAA,CACC,UAAWC,CAAAA,CACT,qCAAA,CACAqB,CAAAA,CAAQ,SAAA,GAAcb,CAAAA,CAClB,0BAAA,CACA,8EACN,CAAA,CACA,KAAA,CACEa,CAAAA,CAAQ,SAAA,GAAcb,CAAAA,CAClB,CAAE,eAAA,CAAiB4B,CAAQ,CAAA,CAC3B,MAAA,CAGN,QAAA,CAAArC,cAAAA,CAAC,GAAA,CAAA,CAAE,SAAA,CAAU,qBAAA,CAAuB,QAAA,CAAAsB,CAAAA,CAAQ,OAAA,CAAQ,CAAA,CACtD,CAAA,CAEAtB,cAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,wBAAA,CACb,QAAA,CAAAgD,cAAAA,CAAO1B,CAAAA,CAAQ,SAAA,CAAW,OAAO,CAAA,CACpC,CAAA,CAAA,CAAA,CA/BKyB,CAgCP,CAEJ,CAAA,CACA/C,cAAAA,CAAC,KAAA,CAAA,CAAI,GAAA,CAAKmC,EAAgB,CAAA,CAAA,CAC5B,CAAA,CAGFnC,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,yDAAA,CACZ,QAAA,CAACS,CAAAA,CAmCAmC,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,yBAAA,CACb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,SACC,KAAA,CAAOiC,CAAAA,CACP,QAAA,CAAWU,CAAAA,EAAMT,CAAAA,CAAcS,CAAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAC7C,SAAA,CAAWD,CAAAA,CACX,WAAA,CAAY,wBAAA,CACZ,SAAA,CAAWzC,EACT,+FAAA,CACA2B,CAAAA,EAAY,KACd,CAAA,CACF,CAAA,CAEA5B,cAAAA,CAAC,QAAA,CAAA,CACC,OAAA,CAASyC,CAAAA,CACT,QAAA,CAAU,CAACR,CAAAA,CAAW,IAAA,EAAK,CAC3B,UAAWhC,CAAAA,CACT,uEAAA,CACA2B,CAAAA,EAAY,MACd,CAAA,CACA,KAAA,CAAO,CACL,eAAA,CAAiBK,CAAAA,CAAW,IAAA,EAAK,CAAII,CAAAA,CAAU,MAAA,CAC/C,OAAA,CAASJ,EAAW,IAAA,EAAK,CAAI,CAAA,CAAI,EACnC,CAAA,CAEA,QAAA,CAAAjC,cAAAA,CAACiD,gBAAAA,CAAA,CAAK,IAAA,CAAM,EAAA,CAAI,SAAA,CAAU,kCAAA,CAAmC,CAAA,CAC/D,GACF,CAAA,CA5DAL,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,uEAAA,CAEb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,KAAA,CAAA,CACC,SAAA,CAAU,sDAAA,CACV,KAAA,CAAO,CACL,UAAA,CAAY,CAAA,EAAGqC,CAAO,CAAA,EAAA,CACxB,CAAA,CAEA,QAAA,CAAArC,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,SAAA,CAAU,QAAA,CAAA,WAAA,CAAE,CAAA,CAC9B,CAAA,CAGA4C,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,qBAAA,CACb,UAAA5C,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,kDAAA,CACb,QAAA,CAAA+B,CAAAA,EAAkB,aAAA,EAAiB,eAAA,CACtC,CAAA,CACA/B,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,qDAAA,CACb,QAAA,CAAA+B,GAAkB,WAAA,EACjB,kEAAA,CACJ,CAAA,CAAA,CACF,CAAA,CAGCC,CAAAA,EACChC,cAAAA,CAAC,QAAA,CAAA,CACC,OAAA,CAASgC,CAAAA,CACT,KAAA,CAAO,CAAE,eAAA,CAAiBK,CAAQ,CAAA,CAClC,UAAU,6IAAA,CACX,QAAA,CAAA,mBAAA,CAED,CAAA,CAAA,CAEJ,CAAA,CA8BJ,CAAA,CAAA,CACF,CAAA,CAGArC,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,0EAAA,CAEb,QAAA,CAAA4C,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,uBAEb,QAAA,CAAA,CAAAA,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,sDAAA,CACb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,IAAA,CAAA,CAAI,QAAA,CAAA0B,CAAAA,CAAM,CAAA,CACX1B,cAAAA,CAAC,QAAA,CAAA,CAAO,OAAA,CAASyB,EACf,QAAA,CAAAzB,cAAAA,CAAC8C,aAAAA,CAAA,EAAE,CAAA,CACL,CAAA,CAAA,CACF,CAAA,CAGAF,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,4CAAA,CACZ,QAAA,CAAA,CAAAjC,CAAAA,CAAS,GAAA,CAAI,CAACuC,CAAAA,CAAGH,CAAAA,GAChB/C,cAAAA,CAAC,KAAA,CAAA,CAAe,QAAA,CAAAkD,CAAAA,CAAE,OAAA,CAAA,CAARH,CAAgB,CAC3B,CAAA,CACD/C,cAAAA,CAAC,KAAA,CAAA,CAAI,GAAA,CAAKmC,CAAAA,CAAgB,GAC5B,CAAA,CAGAnC,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,kCAAA,CACZ,QAAA,CAACS,CAAAA,CAiBAmC,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,mBAAA,CACb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,OAAA,CAAA,CACC,MAAOiC,CAAAA,CACP,QAAA,CAAWU,CAAAA,EAAMT,CAAAA,CAAcS,CAAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAC7C,SAAA,CAAWD,CAAAA,CACX,SAAA,CAAU,+FAAA,CACV,WAAA,CAAY,wBAAA,CACd,EACA1C,cAAAA,CAAC,QAAA,CAAA,CACC,SAAA,CAAWC,CAAAA,CACT,uEAAA,CACA2B,CAAAA,EAAY,MACd,CAAA,CACA,KAAA,CAAO,CACL,eAAA,CAAiBK,CAAAA,CAAW,IAAA,EAAK,CAAII,EAAU,MAAA,CAC/C,OAAA,CAASJ,CAAAA,CAAW,IAAA,EAAK,CAAI,CAAA,CAAI,EACnC,CAAA,CACA,OAAA,CAASQ,CAAAA,CAET,QAAA,CAAAzC,cAAAA,CAACiD,gBAAAA,CAAA,CACC,UAAU,kCAAA,CACV,IAAA,CAAM,EAAA,CACR,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CAxCAL,eAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,6DAAA,CACb,QAAA,CAAA,CAAA5C,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,mEACb,QAAA,CAAA+B,CAAAA,EAAkB,WAAA,EACjB,uCAAA,CACJ,CAAA,CACCC,CAAAA,EACChC,cAAAA,CAAC,QAAA,CAAA,CACC,OAAA,CAASgC,CAAAA,CACT,KAAA,CAAO,CAAE,eAAA,CAAiBK,CAAQ,EAClC,SAAA,CAAU,2GAAA,CAET,QAAA,CAAAN,CAAAA,EAAkB,aAAA,EAAiB,aAAA,CACtC,CAAA,CAAA,CAEJ,CAAA,CA4BJ,CAAA,CAAA,CACF,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CAlPkB,IAoPtB","file":"index.js","sourcesContent":["'use client';\n\nimport React from 'react';\n\nexport interface ButtonWidgetProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n label: string;\n variant?: 'primary' | 'secondary';\n}\n\nexport const ButtonWidget: React.FC<ButtonWidgetProps> = ({ \n label, \n variant = 'primary', \n className = '',\n ...props \n}) => {\n const baseStyles = 'px-4 py-2 rounded-lg font-medium transition-colors';\n const variants = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700',\n secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'\n };\n\n return (\n <button \n className={`${baseStyles} ${variants[variant]} ${className}`}\n {...props}\n >\n {label}\n </button>\n );\n};\n","import type { ClassValue } from \"clsx\";\nimport { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...classes: ClassValue[]) {\n return twMerge(clsx(classes));\n}\n","import io from \"socket.io-client\";\n\nconst socket = io(\"https://beta.triadfi.co\", {\n path: \"/socket.io\",\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n randomizationFactor: 0.5,\n timeout: 5000,\n transports: [\"websocket\"],\n});\n\nexport default socket;\n","import socket from \"@/utils/socket\";\nimport { useEffect, useState } from \"react\";\n\nexport interface ChatMessage {\n authority?: string;\n name: string;\n image: string;\n predictionsCount: number;\n message: string;\n timestamp: number;\n}\n\nexport function useChat({\n authority,\n customerAuthority,\n}: {\n authority?: string;\n customerAuthority: string;\n}) {\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [onlineCount, setOnlineCount] = useState(0);\n\n useEffect(() => {\n if (!authority || !customerAuthority) return;\n\n if (!socket.connected) {\n socket.connect();\n }\n\n socket.emit(\"chat:join\", { authority, customerAuthority }, (res: any) => {\n if (res.error) {\n console.error(\"join error\", res.error);\n }\n });\n\n socket.off(\"chat:history\");\n socket.on(\"chat:history\", (msgs) => {\n setMessages((prev) => (prev.length ? prev : msgs));\n });\n\n socket.off(\"chat:message\");\n socket.on(\"chat:message\", (msg) => {\n setMessages((prev) => [...prev, msg]);\n });\n\n socket.off(\"chat:users\");\n socket.on(\"chat:users\", (data) => {\n setOnlineCount(data.count);\n });\n\n return () => {\n socket.off(\"chat:history\");\n socket.off(\"chat:message\");\n socket.off(\"chat:users\");\n };\n }, [authority, customerAuthority]);\n\n const sendMessage = (message: string) => {\n socket.emit(\n \"chat:message\",\n { authority, customerAuthority, message },\n (res: any) => {\n if (res.error) {\n console.error(\"send error\", res.error);\n }\n },\n );\n };\n\n return {\n messages,\n onlineCount,\n sendMessage,\n };\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { X, Send } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useChat, ChatMessage } from \"@/hooks/useChat\";\nimport { format } from \"date-fns\";\n\nexport interface LiveChatTheme {\n primaryColor?: string;\n background?: string;\n textColor?: string;\n}\n\nexport interface LiveChatClassNames {\n container?: string;\n header?: string;\n messages?: string;\n input?: string;\n button?: string;\n}\n\nexport interface LiveChatProps {\n isOpen: boolean;\n onClose: () => void;\n\n // ui\n title?: string;\n\n // customization\n theme?: LiveChatTheme;\n classNames?: LiveChatClassNames;\n\n // slots\n renderMessage?: (message: ChatMessage) => React.ReactNode;\n renderHeader?: () => React.ReactNode;\n authority: string | null;\n customerAuthority: string;\n onConnectWallet?: () => void;\n fallbackMessages?: {\n connectWallet: string;\n description: string;\n };\n}\n\nexport function LiveChat({\n isOpen,\n onClose,\n title = \"Live Chat\",\n theme,\n classNames,\n renderMessage,\n renderHeader,\n authority,\n customerAuthority,\n fallbackMessages,\n onConnectWallet,\n}: LiveChatProps) {\n const [inputValue, setInputValue] = useState(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const primary = theme?.primaryColor || \"#FF3D00\";\n const background = theme?.background || \"var(--chat-bg)\";\n\n const { sendMessage, onlineCount, messages } = useChat({\n authority: authority || undefined,\n customerAuthority: customerAuthority,\n });\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n const handleSendMessage = () => {\n if (!inputValue.trim()) return;\n setInputValue(\"\");\n sendMessage(inputValue);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSendMessage();\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <>\n <style>{`\n :root {\n --chat-bg: #ffffff;\n }\n .dark {\n --chat-bg: #15181D;\n }\n `}</style>\n\n {/* Desktop */}\n <div\n onClick={(e) => e.stopPropagation()}\n className={cn(\n \"fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl\",\n classNames?.container,\n )}\n style={{\n top: \"75px\",\n width: \"340px\",\n height: !authority ? \"auto\" : \"800px\",\n maxHeight: \"calc(100vh - 90px)\",\n background,\n }}\n >\n {/* Header */}\n {renderHeader ? (\n renderHeader()\n ) : (\n <div\n className={cn(\n \"flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10\",\n classNames?.header,\n )}\n >\n <div className=\"flex items-center gap-3\">\n <h2 className=\"text-lg font-semibold text-triad-dark-100 dark:text-white\">\n {title}\n </h2>\n <div className=\"flex items-center gap-1.5\">\n <div className=\"size-2 rounded-full bg-green-500 animate-pulse\" />\n <span className=\"text-xs text-app-gray-400 dark:text-app-gray-100\">\n {onlineCount} online\n </span>\n </div>\n </div>\n <button onClick={onClose}>\n <X className=\"dark:text-white text-black\" size={18} />\n </button>\n </div>\n )}\n\n {/* Messages */}\n {authority && (\n <div\n className={cn(\n \"flex-1 overflow-y-auto px-6 py-4 space-y-4\",\n classNames?.messages,\n )}\n >\n {messages.map((message, idx) =>\n renderMessage ? (\n renderMessage(message)\n ) : (\n <div\n key={idx}\n className={`flex flex-col gap-1 ${\n message.authority === authority\n ? \"items-end\"\n : \"items-start\"\n }`}\n >\n {message.authority !== authority && (\n <span className=\"text-xs font-medium text-triad-dark-100 dark:text-white\">\n {message.name}\n </span>\n )}\n\n <div\n className={cn(\n \"max-w-[75%] rounded-2xl px-4 py-2.5\",\n message.authority === authority\n ? \"text-white rounded-br-sm\"\n : \"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm\",\n )}\n style={\n message.authority === authority\n ? { backgroundColor: primary }\n : undefined\n }\n >\n <p className=\"text-sm break-words\">{message.message}</p>\n </div>\n\n <span className=\"text-[10px] opacity-50\">\n {format(message.timestamp, \"HH:mm\")}\n </span>\n </div>\n ),\n )}\n <div ref={messagesEndRef} />\n </div>\n )}\n {/* Input */}\n <div className=\"px-6 py-4 border-t border-black/10 dark:border-white/10\">\n {!authority ? (\n <div className=\"flex flex-col items-center justify-center gap-3 py-4 px-3 text-center\">\n {/* Icon */}\n <div\n className=\"flex items-center justify-center size-12 rounded-2xl\"\n style={{\n background: `${primary}15`,\n }}\n >\n <span className=\"text-xl\">💬</span>\n </div>\n\n {/* Text */}\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-sm font-semibold text-black dark:text-white\">\n {fallbackMessages?.connectWallet || \"Entre no chat\"}\n </span>\n <span className=\"text-xs text-black/60 dark:text-white max-w-[220px]\">\n {fallbackMessages?.description ||\n \"Conecte sua carteira para participar das conversas em tempo real\"}\n </span>\n </div>\n\n {/* Button */}\n {onConnectWallet && (\n <button\n onClick={onConnectWallet}\n style={{ backgroundColor: primary }}\n className=\"mt-2 w-full max-w-[220px] px-4 py-2.5 text-white text-sm font-semibold rounded-xl transition-all hover:opacity-90 active:scale-95 shadow-sm\"\n >\n Conectar Carteira\n </button>\n )}\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Digite sua mensagem...\"\n className={cn(\n \"flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none\",\n classNames?.input,\n )}\n />\n\n <button\n onClick={handleSendMessage}\n disabled={!inputValue.trim()}\n className={cn(\n \"flex items-center justify-center size-10 rounded-xl transition-colors\",\n classNames?.button,\n )}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n >\n <Send size={18} className=\"dark:text-white text-app-gay-400\" />\n </button>\n </div>\n )}\n </div>\n </div>\n\n {/* Mobile */}\n <div className=\"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]\">\n {/* Reaproveita mesma estrutura */}\n <div className=\"flex-1 flex flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-4 border-b\">\n <h2>{title}</h2>\n <button onClick={onClose}>\n <X />\n </button>\n </div>\n\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto px-4 py-4 space-y-4\">\n {messages.map((m, idx) => (\n <div key={idx}>{m.message}</div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"p-4 border-t flex flex-col gap-2\">\n {!authority ? (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-2 py-2\">\n <span className=\"text-sm font-medium text-black/60 dark:text-white/60 text-center\">\n {fallbackMessages?.description ||\n \"Faça login para participar do chat\"}\n </span>\n {onConnectWallet && (\n <button\n onClick={onConnectWallet}\n style={{ backgroundColor: primary }}\n className=\"px-4 py-2 text-white text-sm font-semibold rounded-xl transition-opacity hover:opacity-90 active:scale-95\"\n >\n {fallbackMessages?.connectWallet || \"Fazer Login\"}\n </button>\n )}\n </div>\n ) : (\n <div className=\"flex gap-2 w-full\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n className=\"flex-1 bg-black/5 dark:bg-white/5 dark:text-white px-4 py-2.5 rounded-xl text-sm outline-none\"\n placeholder=\"Digite sua mensagem...\"\n />\n <button\n className={cn(\n \"flex items-center justify-center size-10 rounded-xl transition-colors\",\n classNames?.button,\n )}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n onClick={handleSendMessage}\n >\n <Send\n className=\"dark:text-white text-app-gay-400\"\n size={18}\n />\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n </>\n );\n}\n"]}
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useState,useRef,useEffect}from'react';import {X,Send}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import S from'socket.io-client';import {format}from'date-fns';var W=({label:s,variant:n="primary",className:p="",...m})=>jsx("button",{className:`px-4 py-2 rounded-lg font-medium transition-colors ${{primary:"bg-blue-600 text-white hover:bg-blue-700",secondary:"bg-gray-200 text-gray-800 hover:bg-gray-300"}[n]} ${p}`,...m,children:s});function d(...s){return twMerge(clsx(s))}var T=S("https://beta.triadfi.co",{path:"/socket.io",reconnection:true,reconnectionAttempts:5,reconnectionDelay:1e3,randomizationFactor:.5,timeout:5e3,transports:["websocket"]}),a=T;function w({authority:s,customerAuthority:n}){let[p,m]=useState([]),[i,u]=useState(0);return useEffect(()=>{if(!(!n))return a.connected||a.connect(),a.emit("chat:join",{authority:s,customerAuthority:n},r=>{r.error&&console.error("join error",r.error);}),a.off("chat:history"),a.on("chat:history",r=>{m(c=>c.length?c:r);}),a.off("chat:message"),a.on("chat:message",r=>{m(c=>[...c,r]);}),a.off("chat:users"),a.on("chat:users",r=>{u(r.count);}),()=>{a.off("chat:history"),a.off("chat:message"),a.off("chat:users");}},[s,n]),{messages:p,onlineCount:i,sendMessage:r=>{a.emit("chat:message",{authority:s,customerAuthority:n,message:r},c=>{c.error&&console.error("send error",c.error);});}}}function se({isOpen:s,onClose:n,title:p="Live Chat",theme:m,classNames:i,renderMessage:u,renderHeader:f,authority:r,customerAuthority:c}){let[l,g]=useState(""),x=useRef(null),h=m?.primaryColor||"#FF3D00",L=m?.background||"var(--chat-bg)",{sendMessage:R,onlineCount:D,messages:b}=w({authority:r||"random",customerAuthority:c}),z=()=>{x.current?.scrollIntoView({behavior:"smooth"});};useEffect(()=>{z();},[b]);let v=()=>{l.trim()&&(g(""),R(l));},k=t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),v());};return s?jsxs(Fragment,{children:[jsx("style",{children:`
1
+ import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {useState,useRef,useEffect}from'react';import {X,Send}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import S from'socket.io-client';import {format}from'date-fns';var I=({label:o,variant:n="primary",className:p="",...m})=>jsx("button",{className:`px-4 py-2 rounded-lg font-medium transition-colors ${{primary:"bg-blue-600 text-white hover:bg-blue-700",secondary:"bg-gray-200 text-gray-800 hover:bg-gray-300"}[n]} ${p}`,...m,children:o});function d(...o){return twMerge(clsx(o))}var T=S("https://beta.triadfi.co",{path:"/socket.io",reconnection:true,reconnectionAttempts:5,reconnectionDelay:1e3,randomizationFactor:.5,timeout:5e3,transports:["websocket"]}),s=T;function L({authority:o,customerAuthority:n}){let[p,m]=useState([]),[i,u]=useState(0);return useEffect(()=>{if(!(!o||!n))return s.connected||s.connect(),s.emit("chat:join",{authority:o,customerAuthority:n},t=>{t.error&&console.error("join error",t.error);}),s.off("chat:history"),s.on("chat:history",t=>{m(l=>l.length?l:t);}),s.off("chat:message"),s.on("chat:message",t=>{m(l=>[...l,t]);}),s.off("chat:users"),s.on("chat:users",t=>{u(t.count);}),()=>{s.off("chat:history"),s.off("chat:message"),s.off("chat:users");}},[o,n]),{messages:p,onlineCount:i,sendMessage:t=>{s.emit("chat:message",{authority:o,customerAuthority:n,message:t},l=>{l.error&&console.error("send error",l.error);});}}}function ie({isOpen:o,onClose:n,title:p="Live Chat",theme:m,classNames:i,renderMessage:u,renderHeader:h,authority:t,customerAuthority:l,fallbackMessages:f,onConnectWallet:g}){let[c,b]=useState(""),v=useRef(null),x=m?.primaryColor||"#FF3D00",M=m?.background||"var(--chat-bg)",{sendMessage:R,onlineCount:E,messages:y}=L({authority:t||void 0,customerAuthority:l}),j=()=>{v.current?.scrollIntoView({behavior:"smooth"});};useEffect(()=>{j();},[y]);let k=()=>{c.trim()&&(b(""),R(c));},C=a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),k());};return o?jsxs(Fragment,{children:[jsx("style",{children:`
2
2
  :root {
3
3
  --chat-bg: #ffffff;
4
4
  }
5
5
  .dark {
6
6
  --chat-bg: #15181D;
7
7
  }
8
- `}),jsxs("div",{onClick:t=>t.stopPropagation(),className:d("fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl",i?.container),style:{top:"75px",width:"340px",height:"800px",maxHeight:"calc(100vh - 90px)",background:L},children:[f?f():jsxs("div",{className:d("flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10",i?.header),children:[jsxs("div",{className:"flex items-center gap-3",children:[jsx("h2",{className:"text-lg font-semibold text-triad-dark-100 dark:text-white",children:p}),jsxs("div",{className:"flex items-center gap-1.5",children:[jsx("div",{className:"size-2 rounded-full bg-green-500 animate-pulse"}),jsxs("span",{className:"text-xs text-black/50 dark:text-white/50",children:[D," online"]})]})]}),jsx("button",{onClick:n,children:jsx(X,{size:18})})]}),jsxs("div",{className:d("flex-1 overflow-y-auto px-6 py-4 space-y-4",i?.messages),children:[b.map((t,y)=>u?u(t):jsxs("div",{className:`flex flex-col gap-1 ${t.authority===r?"items-end":"items-start"}`,children:[t.authority!==r&&jsx("span",{className:"text-xs font-medium text-triad-dark-100 dark:text-white",children:t.name}),jsx("div",{className:d("max-w-[75%] rounded-2xl px-4 py-2.5",t.authority===r?"text-white rounded-br-sm":"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm"),style:t.authority===r?{backgroundColor:h}:void 0,children:jsx("p",{className:"text-sm break-words",children:t.message})}),jsx("span",{className:"text-[10px] opacity-50",children:format(t.timestamp,"HH:mm")})]},y)),jsx("div",{ref:x})]}),jsx("div",{className:"px-6 py-4 border-t border-black/10 dark:border-white/10",children:jsxs("div",{className:"flex items-center gap-2",children:[jsx("input",{value:l,onChange:t=>g(t.target.value),onKeyDown:k,placeholder:"Digite sua mensagem...",className:d("flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none",i?.input)}),jsx("button",{onClick:v,disabled:!l.trim(),className:d("flex items-center justify-center size-10 rounded-xl transition-colors",i?.button),style:{backgroundColor:l.trim()?h:void 0,opacity:l.trim()?1:.5},children:jsx(Send,{size:18,className:"dark:text-white text-app-gay-400"})})]})})]}),jsx("div",{className:"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]",children:jsxs("div",{className:"flex-1 flex flex-col",children:[jsxs("div",{className:"flex items-center justify-between px-4 py-4 border-b",children:[jsx("h2",{children:p}),jsx("button",{onClick:n,children:jsx(X,{})})]}),jsxs("div",{className:"flex-1 overflow-y-auto px-4 py-4 space-y-4",children:[b.map((t,y)=>jsx("div",{children:t.message},y)),jsx("div",{ref:x})]}),jsxs("div",{className:"p-4 border-t flex gap-2",children:[jsx("input",{value:l,onChange:t=>g(t.target.value),onKeyDown:k,className:"flex-1"}),jsx("button",{className:d(i?.button),style:{backgroundColor:l.trim()?h:void 0,opacity:l.trim()?1:.5},onClick:v,children:jsx(Send,{className:"dark:text-white text-app-gay-400"})})]})]})})]}):null}export{W as ButtonWidget,se as LiveChat};//# sourceMappingURL=index.mjs.map
8
+ `}),jsxs("div",{onClick:a=>a.stopPropagation(),className:d("fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl",i?.container),style:{top:"75px",width:"340px",height:t?"800px":"auto",maxHeight:"calc(100vh - 90px)",background:M},children:[h?h():jsxs("div",{className:d("flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10",i?.header),children:[jsxs("div",{className:"flex items-center gap-3",children:[jsx("h2",{className:"text-lg font-semibold text-triad-dark-100 dark:text-white",children:p}),jsxs("div",{className:"flex items-center gap-1.5",children:[jsx("div",{className:"size-2 rounded-full bg-green-500 animate-pulse"}),jsxs("span",{className:"text-xs text-app-gray-400 dark:text-app-gray-100",children:[E," online"]})]})]}),jsx("button",{onClick:n,children:jsx(X,{className:"dark:text-white text-black",size:18})})]}),t&&jsxs("div",{className:d("flex-1 overflow-y-auto px-6 py-4 space-y-4",i?.messages),children:[y.map((a,w)=>u?u(a):jsxs("div",{className:`flex flex-col gap-1 ${a.authority===t?"items-end":"items-start"}`,children:[a.authority!==t&&jsx("span",{className:"text-xs font-medium text-triad-dark-100 dark:text-white",children:a.name}),jsx("div",{className:d("max-w-[75%] rounded-2xl px-4 py-2.5",a.authority===t?"text-white rounded-br-sm":"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm"),style:a.authority===t?{backgroundColor:x}:void 0,children:jsx("p",{className:"text-sm break-words",children:a.message})}),jsx("span",{className:"text-[10px] opacity-50",children:format(a.timestamp,"HH:mm")})]},w)),jsx("div",{ref:v})]}),jsx("div",{className:"px-6 py-4 border-t border-black/10 dark:border-white/10",children:t?jsxs("div",{className:"flex items-center gap-2",children:[jsx("input",{value:c,onChange:a=>b(a.target.value),onKeyDown:C,placeholder:"Digite sua mensagem...",className:d("flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none",i?.input)}),jsx("button",{onClick:k,disabled:!c.trim(),className:d("flex items-center justify-center size-10 rounded-xl transition-colors",i?.button),style:{backgroundColor:c.trim()?x:void 0,opacity:c.trim()?1:.5},children:jsx(Send,{size:18,className:"dark:text-white text-app-gay-400"})})]}):jsxs("div",{className:"flex flex-col items-center justify-center gap-3 py-4 px-3 text-center",children:[jsx("div",{className:"flex items-center justify-center size-12 rounded-2xl",style:{background:`${x}15`},children:jsx("span",{className:"text-xl",children:"\u{1F4AC}"})}),jsxs("div",{className:"flex flex-col gap-1",children:[jsx("span",{className:"text-sm font-semibold text-black dark:text-white",children:f?.connectWallet||"Entre no chat"}),jsx("span",{className:"text-xs text-black/60 dark:text-white max-w-[220px]",children:f?.description||"Conecte sua carteira para participar das conversas em tempo real"})]}),g&&jsx("button",{onClick:g,style:{backgroundColor:x},className:"mt-2 w-full max-w-[220px] px-4 py-2.5 text-white text-sm font-semibold rounded-xl transition-all hover:opacity-90 active:scale-95 shadow-sm",children:"Conectar Carteira"})]})})]}),jsx("div",{className:"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]",children:jsxs("div",{className:"flex-1 flex flex-col",children:[jsxs("div",{className:"flex items-center justify-between px-4 py-4 border-b",children:[jsx("h2",{children:p}),jsx("button",{onClick:n,children:jsx(X,{})})]}),jsxs("div",{className:"flex-1 overflow-y-auto px-4 py-4 space-y-4",children:[y.map((a,w)=>jsx("div",{children:a.message},w)),jsx("div",{ref:v})]}),jsx("div",{className:"p-4 border-t flex flex-col gap-2",children:t?jsxs("div",{className:"flex gap-2 w-full",children:[jsx("input",{value:c,onChange:a=>b(a.target.value),onKeyDown:C,className:"flex-1 bg-black/5 dark:bg-white/5 dark:text-white px-4 py-2.5 rounded-xl text-sm outline-none",placeholder:"Digite sua mensagem..."}),jsx("button",{className:d("flex items-center justify-center size-10 rounded-xl transition-colors",i?.button),style:{backgroundColor:c.trim()?x:void 0,opacity:c.trim()?1:.5},onClick:k,children:jsx(Send,{className:"dark:text-white text-app-gay-400",size:18})})]}):jsxs("div",{className:"flex-1 flex flex-col items-center justify-center gap-2 py-2",children:[jsx("span",{className:"text-sm font-medium text-black/60 dark:text-white/60 text-center",children:f?.description||"Fa\xE7a login para participar do chat"}),g&&jsx("button",{onClick:g,style:{backgroundColor:x},className:"px-4 py-2 text-white text-sm font-semibold rounded-xl transition-opacity hover:opacity-90 active:scale-95",children:f?.connectWallet||"Fazer Login"})]})})]})})]}):null}export{I as ButtonWidget,ie as LiveChat};//# sourceMappingURL=index.mjs.map
9
9
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ButtonWidget.tsx","../src/utils/cn.ts","../src/utils/socket.ts","../src/hooks/useChat.ts","../src/components/LiveChat.tsx"],"names":["ButtonWidget","label","variant","className","props","jsx","cn","classes","twMerge","clsx","socket","io","socket_default","useChat","authority","customerAuthority","messages","setMessages","useState","onlineCount","setOnlineCount","useEffect","res","msgs","prev","msg","data","message","LiveChat","isOpen","onClose","title","theme","classNames","renderMessage","renderHeader","inputValue","setInputValue","messagesEndRef","useRef","primary","background","sendMessage","scrollToBottom","handleSendMessage","handleKeyDown","e","jsxs","Fragment","X","idx","format","Send","m"],"mappings":"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","file":"index.mjs","sourcesContent":["'use client';\n\nimport React from 'react';\n\nexport interface ButtonWidgetProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n label: string;\n variant?: 'primary' | 'secondary';\n}\n\nexport const ButtonWidget: React.FC<ButtonWidgetProps> = ({ \n label, \n variant = 'primary', \n className = '',\n ...props \n}) => {\n const baseStyles = 'px-4 py-2 rounded-lg font-medium transition-colors';\n const variants = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700',\n secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'\n };\n\n return (\n <button \n className={`${baseStyles} ${variants[variant]} ${className}`}\n {...props}\n >\n {label}\n </button>\n );\n};\n","import type { ClassValue } from \"clsx\";\nimport { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...classes: ClassValue[]) {\n return twMerge(clsx(classes));\n}\n","import io from \"socket.io-client\";\n\nconst socket = io(\"https://beta.triadfi.co\", {\n path: \"/socket.io\",\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n randomizationFactor: 0.5,\n timeout: 5000,\n transports: [\"websocket\"],\n});\n\nexport default socket;\n","import socket from \"@/utils/socket\";\nimport { useEffect, useState } from \"react\";\n\nexport interface ChatMessage {\n authority: string;\n name: string;\n image: string;\n predictionsCount: number;\n message: string;\n timestamp: number;\n}\n\nexport function useChat({\n authority,\n customerAuthority,\n}: {\n authority: string;\n customerAuthority: string;\n}) {\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [onlineCount, setOnlineCount] = useState(0);\n\n useEffect(() => {\n if (!authority || !customerAuthority) return;\n\n if (!socket.connected) {\n socket.connect();\n }\n\n socket.emit(\"chat:join\", { authority, customerAuthority }, (res: any) => {\n if (res.error) {\n console.error(\"join error\", res.error);\n }\n });\n\n socket.off(\"chat:history\");\n socket.on(\"chat:history\", (msgs) => {\n setMessages((prev) => (prev.length ? prev : msgs));\n });\n\n socket.off(\"chat:message\");\n socket.on(\"chat:message\", (msg) => {\n setMessages((prev) => [...prev, msg]);\n });\n\n socket.off(\"chat:users\");\n socket.on(\"chat:users\", (data) => {\n setOnlineCount(data.count);\n });\n\n return () => {\n socket.off(\"chat:history\");\n socket.off(\"chat:message\");\n socket.off(\"chat:users\");\n };\n }, [authority, customerAuthority]);\n\n const sendMessage = (message: string) => {\n socket.emit(\n \"chat:message\",\n { authority, customerAuthority, message },\n (res: any) => {\n if (res.error) {\n console.error(\"send error\", res.error);\n }\n },\n );\n };\n\n return {\n messages,\n onlineCount,\n sendMessage,\n };\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { X, Send } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useChat, ChatMessage } from \"@/hooks/useChat\";\nimport { format } from \"date-fns\";\n\nexport interface LiveChatTheme {\n primaryColor?: string;\n background?: string;\n textColor?: string;\n}\n\nexport interface LiveChatClassNames {\n container?: string;\n header?: string;\n messages?: string;\n input?: string;\n button?: string;\n}\n\nexport interface LiveChatProps {\n isOpen: boolean;\n onClose: () => void;\n\n // ui\n title?: string;\n\n // customization\n theme?: LiveChatTheme;\n classNames?: LiveChatClassNames;\n\n // slots\n renderMessage?: (message: ChatMessage) => React.ReactNode;\n renderHeader?: () => React.ReactNode;\n authority: string;\n customerAuthority: string;\n}\n\nexport function LiveChat({\n isOpen,\n onClose,\n title = \"Live Chat\",\n theme,\n classNames,\n renderMessage,\n renderHeader,\n authority,\n customerAuthority,\n}: LiveChatProps) {\n const [inputValue, setInputValue] = useState(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const primary = theme?.primaryColor || \"#FF3D00\";\n const background = theme?.background || \"var(--chat-bg)\";\n const { sendMessage, onlineCount, messages } = useChat({\n authority: authority || \"random\",\n customerAuthority: customerAuthority,\n });\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n const handleSendMessage = () => {\n if (!inputValue.trim()) return;\n setInputValue(\"\");\n sendMessage(inputValue);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSendMessage();\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <>\n <style>{`\n :root {\n --chat-bg: #ffffff;\n }\n .dark {\n --chat-bg: #15181D;\n }\n `}</style>\n\n {/* Desktop */}\n <div\n onClick={(e) => e.stopPropagation()}\n className={cn(\n \"fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl\",\n classNames?.container,\n )}\n style={{\n top: \"75px\",\n width: \"340px\",\n height: \"800px\",\n maxHeight: \"calc(100vh - 90px)\",\n background,\n }}\n >\n {/* Header */}\n {renderHeader ? (\n renderHeader()\n ) : (\n <div\n className={cn(\n \"flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10\",\n classNames?.header,\n )}\n >\n <div className=\"flex items-center gap-3\">\n <h2 className=\"text-lg font-semibold text-triad-dark-100 dark:text-white\">\n {title}\n </h2>\n <div className=\"flex items-center gap-1.5\">\n <div className=\"size-2 rounded-full bg-green-500 animate-pulse\" />\n <span className=\"text-xs text-black/50 dark:text-white/50\">\n {onlineCount} online\n </span>\n </div>\n </div>\n <button onClick={onClose}>\n <X size={18} />\n </button>\n </div>\n )}\n\n {/* Messages */}\n <div\n className={cn(\n \"flex-1 overflow-y-auto px-6 py-4 space-y-4\",\n classNames?.messages,\n )}\n >\n {messages.map((message, idx) =>\n renderMessage ? (\n renderMessage(message)\n ) : (\n <div\n key={idx}\n className={`flex flex-col gap-1 ${\n message.authority === authority ? \"items-end\" : \"items-start\"\n }`}\n >\n {message.authority !== authority && (\n <span className=\"text-xs font-medium text-triad-dark-100 dark:text-white\">\n {message.name}\n </span>\n )}\n\n <div\n className={cn(\n \"max-w-[75%] rounded-2xl px-4 py-2.5\",\n message.authority === authority\n ? \"text-white rounded-br-sm\"\n : \"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm\",\n )}\n style={\n message.authority === authority\n ? { backgroundColor: primary }\n : undefined\n }\n >\n <p className=\"text-sm break-words\">{message.message}</p>\n </div>\n\n <span className=\"text-[10px] opacity-50\">\n {format(message.timestamp, \"HH:mm\")}\n </span>\n </div>\n ),\n )}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"px-6 py-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-center gap-2\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Digite sua mensagem...\"\n className={cn(\n \"flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none\",\n classNames?.input,\n )}\n />\n\n <button\n onClick={handleSendMessage}\n disabled={!inputValue.trim()}\n className={cn(\n \"flex items-center justify-center size-10 rounded-xl transition-colors\",\n classNames?.button,\n )}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n >\n <Send size={18} className=\"dark:text-white text-app-gay-400\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Mobile */}\n <div className=\"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]\">\n {/* Reaproveita mesma estrutura */}\n <div className=\"flex-1 flex flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-4 border-b\">\n <h2>{title}</h2>\n <button onClick={onClose}>\n <X />\n </button>\n </div>\n\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto px-4 py-4 space-y-4\">\n {messages.map((m, idx) => (\n <div key={idx}>{m.message}</div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"p-4 border-t flex gap-2\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n className=\"flex-1\"\n />\n <button\n className={cn(classNames?.button)}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n onClick={handleSendMessage}\n >\n <Send className=\"dark:text-white text-app-gay-400\" />\n </button>\n </div>\n </div>\n </div>\n </>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/components/ButtonWidget.tsx","../src/utils/cn.ts","../src/utils/socket.ts","../src/hooks/useChat.ts","../src/components/LiveChat.tsx"],"names":["ButtonWidget","label","variant","className","props","jsx","cn","classes","twMerge","clsx","socket","io","socket_default","useChat","authority","customerAuthority","messages","setMessages","useState","onlineCount","setOnlineCount","useEffect","res","msgs","prev","msg","data","message","LiveChat","isOpen","onClose","title","theme","classNames","renderMessage","renderHeader","fallbackMessages","onConnectWallet","inputValue","setInputValue","messagesEndRef","useRef","primary","background","sendMessage","scrollToBottom","handleSendMessage","handleKeyDown","e","jsxs","Fragment","X","idx","format","Send","m"],"mappings":"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","file":"index.mjs","sourcesContent":["'use client';\n\nimport React from 'react';\n\nexport interface ButtonWidgetProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n label: string;\n variant?: 'primary' | 'secondary';\n}\n\nexport const ButtonWidget: React.FC<ButtonWidgetProps> = ({ \n label, \n variant = 'primary', \n className = '',\n ...props \n}) => {\n const baseStyles = 'px-4 py-2 rounded-lg font-medium transition-colors';\n const variants = {\n primary: 'bg-blue-600 text-white hover:bg-blue-700',\n secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'\n };\n\n return (\n <button \n className={`${baseStyles} ${variants[variant]} ${className}`}\n {...props}\n >\n {label}\n </button>\n );\n};\n","import type { ClassValue } from \"clsx\";\nimport { clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...classes: ClassValue[]) {\n return twMerge(clsx(classes));\n}\n","import io from \"socket.io-client\";\n\nconst socket = io(\"https://beta.triadfi.co\", {\n path: \"/socket.io\",\n reconnection: true,\n reconnectionAttempts: 5,\n reconnectionDelay: 1000,\n randomizationFactor: 0.5,\n timeout: 5000,\n transports: [\"websocket\"],\n});\n\nexport default socket;\n","import socket from \"@/utils/socket\";\nimport { useEffect, useState } from \"react\";\n\nexport interface ChatMessage {\n authority?: string;\n name: string;\n image: string;\n predictionsCount: number;\n message: string;\n timestamp: number;\n}\n\nexport function useChat({\n authority,\n customerAuthority,\n}: {\n authority?: string;\n customerAuthority: string;\n}) {\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [onlineCount, setOnlineCount] = useState(0);\n\n useEffect(() => {\n if (!authority || !customerAuthority) return;\n\n if (!socket.connected) {\n socket.connect();\n }\n\n socket.emit(\"chat:join\", { authority, customerAuthority }, (res: any) => {\n if (res.error) {\n console.error(\"join error\", res.error);\n }\n });\n\n socket.off(\"chat:history\");\n socket.on(\"chat:history\", (msgs) => {\n setMessages((prev) => (prev.length ? prev : msgs));\n });\n\n socket.off(\"chat:message\");\n socket.on(\"chat:message\", (msg) => {\n setMessages((prev) => [...prev, msg]);\n });\n\n socket.off(\"chat:users\");\n socket.on(\"chat:users\", (data) => {\n setOnlineCount(data.count);\n });\n\n return () => {\n socket.off(\"chat:history\");\n socket.off(\"chat:message\");\n socket.off(\"chat:users\");\n };\n }, [authority, customerAuthority]);\n\n const sendMessage = (message: string) => {\n socket.emit(\n \"chat:message\",\n { authority, customerAuthority, message },\n (res: any) => {\n if (res.error) {\n console.error(\"send error\", res.error);\n }\n },\n );\n };\n\n return {\n messages,\n onlineCount,\n sendMessage,\n };\n}\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { X, Send } from \"lucide-react\";\nimport { cn } from \"@/utils/cn\";\nimport { useChat, ChatMessage } from \"@/hooks/useChat\";\nimport { format } from \"date-fns\";\n\nexport interface LiveChatTheme {\n primaryColor?: string;\n background?: string;\n textColor?: string;\n}\n\nexport interface LiveChatClassNames {\n container?: string;\n header?: string;\n messages?: string;\n input?: string;\n button?: string;\n}\n\nexport interface LiveChatProps {\n isOpen: boolean;\n onClose: () => void;\n\n // ui\n title?: string;\n\n // customization\n theme?: LiveChatTheme;\n classNames?: LiveChatClassNames;\n\n // slots\n renderMessage?: (message: ChatMessage) => React.ReactNode;\n renderHeader?: () => React.ReactNode;\n authority: string | null;\n customerAuthority: string;\n onConnectWallet?: () => void;\n fallbackMessages?: {\n connectWallet: string;\n description: string;\n };\n}\n\nexport function LiveChat({\n isOpen,\n onClose,\n title = \"Live Chat\",\n theme,\n classNames,\n renderMessage,\n renderHeader,\n authority,\n customerAuthority,\n fallbackMessages,\n onConnectWallet,\n}: LiveChatProps) {\n const [inputValue, setInputValue] = useState(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const primary = theme?.primaryColor || \"#FF3D00\";\n const background = theme?.background || \"var(--chat-bg)\";\n\n const { sendMessage, onlineCount, messages } = useChat({\n authority: authority || undefined,\n customerAuthority: customerAuthority,\n });\n\n const scrollToBottom = () => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n const handleSendMessage = () => {\n if (!inputValue.trim()) return;\n setInputValue(\"\");\n sendMessage(inputValue);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSendMessage();\n }\n };\n\n if (!isOpen) return null;\n\n return (\n <>\n <style>{`\n :root {\n --chat-bg: #ffffff;\n }\n .dark {\n --chat-bg: #15181D;\n }\n `}</style>\n\n {/* Desktop */}\n <div\n onClick={(e) => e.stopPropagation()}\n className={cn(\n \"fixed right-6 z-[110] hidden lg:flex flex-col overflow-hidden rounded-3xl shadow-2xl\",\n classNames?.container,\n )}\n style={{\n top: \"75px\",\n width: \"340px\",\n height: !authority ? \"auto\" : \"800px\",\n maxHeight: \"calc(100vh - 90px)\",\n background,\n }}\n >\n {/* Header */}\n {renderHeader ? (\n renderHeader()\n ) : (\n <div\n className={cn(\n \"flex items-center justify-between px-6 py-4 border-b border-black/10 dark:border-white/10\",\n classNames?.header,\n )}\n >\n <div className=\"flex items-center gap-3\">\n <h2 className=\"text-lg font-semibold text-triad-dark-100 dark:text-white\">\n {title}\n </h2>\n <div className=\"flex items-center gap-1.5\">\n <div className=\"size-2 rounded-full bg-green-500 animate-pulse\" />\n <span className=\"text-xs text-app-gray-400 dark:text-app-gray-100\">\n {onlineCount} online\n </span>\n </div>\n </div>\n <button onClick={onClose}>\n <X className=\"dark:text-white text-black\" size={18} />\n </button>\n </div>\n )}\n\n {/* Messages */}\n {authority && (\n <div\n className={cn(\n \"flex-1 overflow-y-auto px-6 py-4 space-y-4\",\n classNames?.messages,\n )}\n >\n {messages.map((message, idx) =>\n renderMessage ? (\n renderMessage(message)\n ) : (\n <div\n key={idx}\n className={`flex flex-col gap-1 ${\n message.authority === authority\n ? \"items-end\"\n : \"items-start\"\n }`}\n >\n {message.authority !== authority && (\n <span className=\"text-xs font-medium text-triad-dark-100 dark:text-white\">\n {message.name}\n </span>\n )}\n\n <div\n className={cn(\n \"max-w-[75%] rounded-2xl px-4 py-2.5\",\n message.authority === authority\n ? \"text-white rounded-br-sm\"\n : \"bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm\",\n )}\n style={\n message.authority === authority\n ? { backgroundColor: primary }\n : undefined\n }\n >\n <p className=\"text-sm break-words\">{message.message}</p>\n </div>\n\n <span className=\"text-[10px] opacity-50\">\n {format(message.timestamp, \"HH:mm\")}\n </span>\n </div>\n ),\n )}\n <div ref={messagesEndRef} />\n </div>\n )}\n {/* Input */}\n <div className=\"px-6 py-4 border-t border-black/10 dark:border-white/10\">\n {!authority ? (\n <div className=\"flex flex-col items-center justify-center gap-3 py-4 px-3 text-center\">\n {/* Icon */}\n <div\n className=\"flex items-center justify-center size-12 rounded-2xl\"\n style={{\n background: `${primary}15`,\n }}\n >\n <span className=\"text-xl\">💬</span>\n </div>\n\n {/* Text */}\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-sm font-semibold text-black dark:text-white\">\n {fallbackMessages?.connectWallet || \"Entre no chat\"}\n </span>\n <span className=\"text-xs text-black/60 dark:text-white max-w-[220px]\">\n {fallbackMessages?.description ||\n \"Conecte sua carteira para participar das conversas em tempo real\"}\n </span>\n </div>\n\n {/* Button */}\n {onConnectWallet && (\n <button\n onClick={onConnectWallet}\n style={{ backgroundColor: primary }}\n className=\"mt-2 w-full max-w-[220px] px-4 py-2.5 text-white text-sm font-semibold rounded-xl transition-all hover:opacity-90 active:scale-95 shadow-sm\"\n >\n Conectar Carteira\n </button>\n )}\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Digite sua mensagem...\"\n className={cn(\n \"flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none\",\n classNames?.input,\n )}\n />\n\n <button\n onClick={handleSendMessage}\n disabled={!inputValue.trim()}\n className={cn(\n \"flex items-center justify-center size-10 rounded-xl transition-colors\",\n classNames?.button,\n )}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n >\n <Send size={18} className=\"dark:text-white text-app-gay-400\" />\n </button>\n </div>\n )}\n </div>\n </div>\n\n {/* Mobile */}\n <div className=\"fixed inset-0 z-[110] flex flex-col lg:hidden bg-white dark:bg-[#15181D]\">\n {/* Reaproveita mesma estrutura */}\n <div className=\"flex-1 flex flex-col\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-4 border-b\">\n <h2>{title}</h2>\n <button onClick={onClose}>\n <X />\n </button>\n </div>\n\n {/* Messages */}\n <div className=\"flex-1 overflow-y-auto px-4 py-4 space-y-4\">\n {messages.map((m, idx) => (\n <div key={idx}>{m.message}</div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n\n {/* Input */}\n <div className=\"p-4 border-t flex flex-col gap-2\">\n {!authority ? (\n <div className=\"flex-1 flex flex-col items-center justify-center gap-2 py-2\">\n <span className=\"text-sm font-medium text-black/60 dark:text-white/60 text-center\">\n {fallbackMessages?.description ||\n \"Faça login para participar do chat\"}\n </span>\n {onConnectWallet && (\n <button\n onClick={onConnectWallet}\n style={{ backgroundColor: primary }}\n className=\"px-4 py-2 text-white text-sm font-semibold rounded-xl transition-opacity hover:opacity-90 active:scale-95\"\n >\n {fallbackMessages?.connectWallet || \"Fazer Login\"}\n </button>\n )}\n </div>\n ) : (\n <div className=\"flex gap-2 w-full\">\n <input\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n onKeyDown={handleKeyDown}\n className=\"flex-1 bg-black/5 dark:bg-white/5 dark:text-white px-4 py-2.5 rounded-xl text-sm outline-none\"\n placeholder=\"Digite sua mensagem...\"\n />\n <button\n className={cn(\n \"flex items-center justify-center size-10 rounded-xl transition-colors\",\n classNames?.button,\n )}\n style={{\n backgroundColor: inputValue.trim() ? primary : undefined,\n opacity: inputValue.trim() ? 1 : 0.5,\n }}\n onClick={handleSendMessage}\n >\n <Send\n className=\"dark:text-white text-app-gay-400\"\n size={18}\n />\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n </>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@triadxyz/widgets",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Shared widgets and logic for Triad Next.js whitelabels",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -34,8 +34,13 @@ export interface LiveChatProps {
34
34
  // slots
35
35
  renderMessage?: (message: ChatMessage) => React.ReactNode;
36
36
  renderHeader?: () => React.ReactNode;
37
- authority: string;
37
+ authority: string | null;
38
38
  customerAuthority: string;
39
+ onConnectWallet?: () => void;
40
+ fallbackMessages?: {
41
+ connectWallet: string;
42
+ description: string;
43
+ };
39
44
  }
40
45
 
41
46
  export function LiveChat({
@@ -48,13 +53,16 @@ export function LiveChat({
48
53
  renderHeader,
49
54
  authority,
50
55
  customerAuthority,
56
+ fallbackMessages,
57
+ onConnectWallet,
51
58
  }: LiveChatProps) {
52
59
  const [inputValue, setInputValue] = useState("");
53
60
  const messagesEndRef = useRef<HTMLDivElement>(null);
54
61
  const primary = theme?.primaryColor || "#FF3D00";
55
62
  const background = theme?.background || "var(--chat-bg)";
63
+
56
64
  const { sendMessage, onlineCount, messages } = useChat({
57
- authority: authority || "random",
65
+ authority: authority || undefined,
58
66
  customerAuthority: customerAuthority,
59
67
  });
60
68
 
@@ -102,7 +110,7 @@ export function LiveChat({
102
110
  style={{
103
111
  top: "75px",
104
112
  width: "340px",
105
- height: "800px",
113
+ height: !authority ? "auto" : "800px",
106
114
  maxHeight: "calc(100vh - 90px)",
107
115
  background,
108
116
  }}
@@ -123,94 +131,133 @@ export function LiveChat({
123
131
  </h2>
124
132
  <div className="flex items-center gap-1.5">
125
133
  <div className="size-2 rounded-full bg-green-500 animate-pulse" />
126
- <span className="text-xs text-black/50 dark:text-white/50">
134
+ <span className="text-xs text-app-gray-400 dark:text-app-gray-100">
127
135
  {onlineCount} online
128
136
  </span>
129
137
  </div>
130
138
  </div>
131
139
  <button onClick={onClose}>
132
- <X size={18} />
140
+ <X className="dark:text-white text-black" size={18} />
133
141
  </button>
134
142
  </div>
135
143
  )}
136
144
 
137
145
  {/* Messages */}
138
- <div
139
- className={cn(
140
- "flex-1 overflow-y-auto px-6 py-4 space-y-4",
141
- classNames?.messages,
142
- )}
143
- >
144
- {messages.map((message, idx) =>
145
- renderMessage ? (
146
- renderMessage(message)
147
- ) : (
148
- <div
149
- key={idx}
150
- className={`flex flex-col gap-1 ${
151
- message.authority === authority ? "items-end" : "items-start"
152
- }`}
153
- >
154
- {message.authority !== authority && (
155
- <span className="text-xs font-medium text-triad-dark-100 dark:text-white">
156
- {message.name}
157
- </span>
158
- )}
159
-
146
+ {authority && (
147
+ <div
148
+ className={cn(
149
+ "flex-1 overflow-y-auto px-6 py-4 space-y-4",
150
+ classNames?.messages,
151
+ )}
152
+ >
153
+ {messages.map((message, idx) =>
154
+ renderMessage ? (
155
+ renderMessage(message)
156
+ ) : (
160
157
  <div
161
- className={cn(
162
- "max-w-[75%] rounded-2xl px-4 py-2.5",
158
+ key={idx}
159
+ className={`flex flex-col gap-1 ${
163
160
  message.authority === authority
164
- ? "text-white rounded-br-sm"
165
- : "bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm",
166
- )}
167
- style={
168
- message.authority === authority
169
- ? { backgroundColor: primary }
170
- : undefined
171
- }
161
+ ? "items-end"
162
+ : "items-start"
163
+ }`}
172
164
  >
173
- <p className="text-sm break-words">{message.message}</p>
165
+ {message.authority !== authority && (
166
+ <span className="text-xs font-medium text-triad-dark-100 dark:text-white">
167
+ {message.name}
168
+ </span>
169
+ )}
170
+
171
+ <div
172
+ className={cn(
173
+ "max-w-[75%] rounded-2xl px-4 py-2.5",
174
+ message.authority === authority
175
+ ? "text-white rounded-br-sm"
176
+ : "bg-black/5 dark:bg-white/5 text-triad-dark-100 dark:text-white rounded-bl-sm",
177
+ )}
178
+ style={
179
+ message.authority === authority
180
+ ? { backgroundColor: primary }
181
+ : undefined
182
+ }
183
+ >
184
+ <p className="text-sm break-words">{message.message}</p>
185
+ </div>
186
+
187
+ <span className="text-[10px] opacity-50">
188
+ {format(message.timestamp, "HH:mm")}
189
+ </span>
174
190
  </div>
191
+ ),
192
+ )}
193
+ <div ref={messagesEndRef} />
194
+ </div>
195
+ )}
196
+ {/* Input */}
197
+ <div className="px-6 py-4 border-t border-black/10 dark:border-white/10">
198
+ {!authority ? (
199
+ <div className="flex flex-col items-center justify-center gap-3 py-4 px-3 text-center">
200
+ {/* Icon */}
201
+ <div
202
+ className="flex items-center justify-center size-12 rounded-2xl"
203
+ style={{
204
+ background: `${primary}15`,
205
+ }}
206
+ >
207
+ <span className="text-xl">💬</span>
208
+ </div>
175
209
 
176
- <span className="text-[10px] opacity-50">
177
- {format(message.timestamp, "HH:mm")}
210
+ {/* Text */}
211
+ <div className="flex flex-col gap-1">
212
+ <span className="text-sm font-semibold text-black dark:text-white">
213
+ {fallbackMessages?.connectWallet || "Entre no chat"}
214
+ </span>
215
+ <span className="text-xs text-black/60 dark:text-white max-w-[220px]">
216
+ {fallbackMessages?.description ||
217
+ "Conecte sua carteira para participar das conversas em tempo real"}
178
218
  </span>
179
219
  </div>
180
- ),
181
- )}
182
- <div ref={messagesEndRef} />
183
- </div>
184
220
 
185
- {/* Input */}
186
- <div className="px-6 py-4 border-t border-black/10 dark:border-white/10">
187
- <div className="flex items-center gap-2">
188
- <input
189
- value={inputValue}
190
- onChange={(e) => setInputValue(e.target.value)}
191
- onKeyDown={handleKeyDown}
192
- placeholder="Digite sua mensagem..."
193
- className={cn(
194
- "flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none",
195
- classNames?.input,
221
+ {/* Button */}
222
+ {onConnectWallet && (
223
+ <button
224
+ onClick={onConnectWallet}
225
+ style={{ backgroundColor: primary }}
226
+ className="mt-2 w-full max-w-[220px] px-4 py-2.5 text-white text-sm font-semibold rounded-xl transition-all hover:opacity-90 active:scale-95 shadow-sm"
227
+ >
228
+ Conectar Carteira
229
+ </button>
196
230
  )}
197
- />
231
+ </div>
232
+ ) : (
233
+ <div className="flex items-center gap-2">
234
+ <input
235
+ value={inputValue}
236
+ onChange={(e) => setInputValue(e.target.value)}
237
+ onKeyDown={handleKeyDown}
238
+ placeholder="Digite sua mensagem..."
239
+ className={cn(
240
+ "flex-1 px-4 py-2.5 rounded-xl bg-black/5 dark:bg-white/5 dark:text-white text-sm outline-none",
241
+ classNames?.input,
242
+ )}
243
+ />
198
244
 
199
- <button
200
- onClick={handleSendMessage}
201
- disabled={!inputValue.trim()}
202
- className={cn(
203
- "flex items-center justify-center size-10 rounded-xl transition-colors",
204
- classNames?.button,
205
- )}
206
- style={{
207
- backgroundColor: inputValue.trim() ? primary : undefined,
208
- opacity: inputValue.trim() ? 1 : 0.5,
209
- }}
210
- >
211
- <Send size={18} className="dark:text-white text-app-gay-400" />
212
- </button>
213
- </div>
245
+ <button
246
+ onClick={handleSendMessage}
247
+ disabled={!inputValue.trim()}
248
+ className={cn(
249
+ "flex items-center justify-center size-10 rounded-xl transition-colors",
250
+ classNames?.button,
251
+ )}
252
+ style={{
253
+ backgroundColor: inputValue.trim() ? primary : undefined,
254
+ opacity: inputValue.trim() ? 1 : 0.5,
255
+ }}
256
+ >
257
+ <Send size={18} className="dark:text-white text-app-gay-400" />
258
+ </button>
259
+ </div>
260
+ )}
214
261
  </div>
215
262
  </div>
216
263
 
@@ -235,23 +282,50 @@ export function LiveChat({
235
282
  </div>
236
283
 
237
284
  {/* Input */}
238
- <div className="p-4 border-t flex gap-2">
239
- <input
240
- value={inputValue}
241
- onChange={(e) => setInputValue(e.target.value)}
242
- onKeyDown={handleKeyDown}
243
- className="flex-1"
244
- />
245
- <button
246
- className={cn(classNames?.button)}
247
- style={{
248
- backgroundColor: inputValue.trim() ? primary : undefined,
249
- opacity: inputValue.trim() ? 1 : 0.5,
250
- }}
251
- onClick={handleSendMessage}
252
- >
253
- <Send className="dark:text-white text-app-gay-400" />
254
- </button>
285
+ <div className="p-4 border-t flex flex-col gap-2">
286
+ {!authority ? (
287
+ <div className="flex-1 flex flex-col items-center justify-center gap-2 py-2">
288
+ <span className="text-sm font-medium text-black/60 dark:text-white/60 text-center">
289
+ {fallbackMessages?.description ||
290
+ "Faça login para participar do chat"}
291
+ </span>
292
+ {onConnectWallet && (
293
+ <button
294
+ onClick={onConnectWallet}
295
+ style={{ backgroundColor: primary }}
296
+ className="px-4 py-2 text-white text-sm font-semibold rounded-xl transition-opacity hover:opacity-90 active:scale-95"
297
+ >
298
+ {fallbackMessages?.connectWallet || "Fazer Login"}
299
+ </button>
300
+ )}
301
+ </div>
302
+ ) : (
303
+ <div className="flex gap-2 w-full">
304
+ <input
305
+ value={inputValue}
306
+ onChange={(e) => setInputValue(e.target.value)}
307
+ onKeyDown={handleKeyDown}
308
+ className="flex-1 bg-black/5 dark:bg-white/5 dark:text-white px-4 py-2.5 rounded-xl text-sm outline-none"
309
+ placeholder="Digite sua mensagem..."
310
+ />
311
+ <button
312
+ className={cn(
313
+ "flex items-center justify-center size-10 rounded-xl transition-colors",
314
+ classNames?.button,
315
+ )}
316
+ style={{
317
+ backgroundColor: inputValue.trim() ? primary : undefined,
318
+ opacity: inputValue.trim() ? 1 : 0.5,
319
+ }}
320
+ onClick={handleSendMessage}
321
+ >
322
+ <Send
323
+ className="dark:text-white text-app-gay-400"
324
+ size={18}
325
+ />
326
+ </button>
327
+ </div>
328
+ )}
255
329
  </div>
256
330
  </div>
257
331
  </div>
@@ -2,7 +2,7 @@ import socket from "@/utils/socket";
2
2
  import { useEffect, useState } from "react";
3
3
 
4
4
  export interface ChatMessage {
5
- authority: string;
5
+ authority?: string;
6
6
  name: string;
7
7
  image: string;
8
8
  predictionsCount: number;
@@ -14,7 +14,7 @@ export function useChat({
14
14
  authority,
15
15
  customerAuthority,
16
16
  }: {
17
- authority: string;
17
+ authority?: string;
18
18
  customerAuthority: string;
19
19
  }) {
20
20
  const [messages, setMessages] = useState<ChatMessage[]>([]);