npm package: @leve.ai/chat
Description: Sistema de chat multiplataforma com suporte a WebSocket para Web e React Native
Author: Leve.ai
Latest version: 1.0.35

# @leve.ai/chat

Sistema de chat multiplataforma com suporte a WebSocket para **Web** e **React Native**.

## 📦 Instalação

```bash
npm install @leve.ai/chat @leve.ai/socket-client
# ou
yarn add @leve.ai/chat @leve.ai/socket-client
# ou
pnpm add @leve.ai/chat @leve.ai/socket-client
```

## 🚀 Uso

### Web (React, Next.js, Vite, etc.)

```tsx
import { ChatWidget } from '@leve.ai/chat/web'
import { ChatProvider } from '@leve.ai/chat/shared'
// O CSS é importado automaticamente!

function App() {
  return (
    <ChatProvider
      user={{ id: 'user123', name: 'João' }}
      socketUrl="https://seu-servidor.com"
      socketApiKey="sua-api-key"
      socketNamespace="chat"
      autoShowOnMessage={true}
    >
      <YourApp />
      <ChatWidget
        theme={{
          primaryColor: '#3b82f6' // Personalize a cor primária!
        }}
      />
    </ChatProvider>
  )
}
```

> **Nota sobre estilos:** Os estilos são importados automaticamente quando você importa os componentes. Se houver problemas de conflito de CSS, veja o [Guia de Isolamento de CSS](./CSS_ISOLATION.md).
>
> **Personalização de cores:** Você pode customizar as cores do chat usando a prop `theme`. Veja mais detalhes na [seção de Personalização de Cores](#-personalização-de-cores).

### React Native (Expo, RN CLI)

```tsx
import { ChatWidget } from '@leve.ai/chat/native'
import { ChatProvider } from '@leve.ai/chat/shared'

function App() {
  return (
    <ChatProvider
      user={{ id: 'user123', name: 'João' }}
      socketUrl="https://seu-servidor.com"
      socketApiKey="sua-api-key"
      socketNamespace="chat"
      autoShowOnMessage={true}
    >
      <YourApp />
      <ChatWidget />
    </ChatProvider>
  )
}
```

> **✨ Metro Bundler Compatível:** A partir da v1.0.9, a biblioteca funciona nativamente com Metro bundler sem necessidade de configuração adicional. Para mais detalhes, veja [METRO_COMPATIBILITY.md](./METRO_COMPATIBILITY.md).

### Apenas Hooks/Lógica (UI Customizado)

```tsx
import { useChat, useOrderRooms } from '@leve.ai/chat/shared'

function CustomChatUI() {
  const { messages, sendMessage } = useChat()
  const { openOrderChat } = useOrderRooms({
    orderIds: ['order1', 'order2'],
    enabled: true
  })

  // Criar seu próprio UI
  return (
    <div>
      {messages.map(msg => (
        <div key={msg.id}>{msg.content}</div>
      ))}
    </div>
  )
}
```

## 📚 API Reference

### ChatProvider

Provider principal do sistema de chat.

**Props:**
- `children: ReactNode` - Componentes filhos
- `autoShowOnMessage?: boolean` - Mostrar widget automaticamente ao receber mensagem (default: `true`)

```tsx
<ChatProvider autoShowOnMessage={false}>
  {/* seu app */}
</ChatProvider>
```

### useChat()

Hook principal para gerenciar o chat.

**Retorno:**
```typescript
{
  // Estado
  messages: Message[]
  currentRoom: string | null
  isConnected: boolean
  connectionStatus: ConnectionStatus
  isWidgetVisible: boolean
  unreadCount: number
  users: User[]
  isLoading: boolean
  error: string | null
  rooms: ChatRoom[]
  currentView: 'rooms' | 'chat'

  // Ações
  sendMessage: (content: string, type?: MessageType) => Promise<void>
  markAsRead: (messageId: string) => void
  markAllAsRead: () => void
  clearMessages: () => void
  joinRoom: (roomId: string) => Promise<void>
  leaveRoom: () => void
  showWidget: () => void
  hideWidget: () => void
  toggleWidget: () => void

  // Gerenciamento de Salas
  addRoom: (room: ChatRoom) => void
  removeRoom: (roomId: string) => void
  updateRoom: (roomId: string, updates: Partial<ChatRoom>) => void

  // Socket
  socket: Socket | null
  authenticated: boolean
  subscribe: (channel: string) => void
  unsubscribe: (channel: string) => void
}
```

**Exemplo:**
```tsx
const { messages, sendMessage, isConnected } = useChat()

const handleSend = async () => {
  await sendMessage('Olá!', MessageType.TEXT)
}
```

### useOrderRooms(options)

Hook para gerenciar múltiplas salas de pedidos.

**Params:**
```typescript
{
  orderIds: string[]        // IDs dos pedidos
  enabled?: boolean         // Ativar auto-subscribe (default: true)
}
```

**Retorno:**
```typescript
{
  subscribeToOrderRooms: (orderIds: string[]) => void
  unsubscribeFromOrderRooms: () => void
  openOrderChat: (orderId: string) => Promise<void>
  getOrderRoomId: (orderId: string) => string
  subscribedRooms: string[]
  getOrderUnreadCount: (orderId: string) => number
  getTotalUnreadCount: () => number
  getAllOrdersUnreadCount: () => Record<string, number>
}
```

**Exemplo:**
```tsx
const {
  openOrderChat,
  getOrderUnreadCount
} = useOrderRooms({
  orderIds: orders.map(o => o.id),
  enabled: true
})

// Abrir chat de pedido específico
const handleOpenChat = (orderId: string) => {
  openOrderChat(orderId)
}

// Pegar contador de não lidas
const unread = getOrderUnreadCount('order123')
```

### useChatWidget()

Hook simplificado para controle do widget.

**Retorno:**
```typescript
{
  isVisible: boolean
  unreadCount: number
  isConnected: boolean
  isLoading: boolean
  currentRoom: string | null
  showWidget: () => void
  hideWidget: () => void
  toggleWidget: () => void
  hasUnreadMessages: boolean
}
```

**Exemplo:**
```tsx
function HeaderChatButton() {
  const { showWidget, unreadCount, hasUnreadMessages } = useChatWidget()

  return (
    <button onClick={showWidget} className="relative">
      <MessageCircle />
      {hasUnreadMessages && (
        <span className="badge">{unreadCount}</span>
      )}
    </button>
  )
}
```

## 🎨 Componentes

### Web Components

#### ChatWidget
Widget completo de chat com todas as funcionalidades.

**Props:**
- `position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'` - Posição do widget (default: `'bottom-right'`)
- `maxHeight?: number` - Altura máxima em pixels (default: `500`)
- `maxWidth?: number` - Largura máxima em pixels (default: `380`)
- `zIndex?: number` - z-index do widget (default: `9999`)
- `className?: string` - Classes CSS adicionais
- `widgetClassName?: string` - Classes CSS para o container do widget
- `theme?: ChatTheme` - Objeto de personalização de cores (veja [Personalização de Cores](#-personalização-de-cores))

```tsx
import { ChatWidget } from '@leve.ai/chat/web'

<ChatWidget
  position="bottom-right"
  maxHeight={600}
  maxWidth={400}
  zIndex={10000}
/>
```

##### 🎨 Personalização de Cores

O ChatWidget aceita uma prop `theme` para customizar as cores primárias:

**Props do theme:**
- `primaryColor?: string` - Cor primária principal (default: `'#fa5534'`)
- `primaryColorHover?: string` - Cor ao passar o mouse (default: `'#e04829'`)
- `primaryColorLight?: string` - Cor primária mais clara (default: `'rgba(250, 85, 52, 0.9)'`)

```tsx
<ChatWidget
  theme={{
    primaryColor: '#3b82f6',      // Azul
    primaryColorHover: '#2563eb', // Azul escuro
    primaryColorLight: 'rgba(59, 130, 246, 0.9)'
  }}
/>
```

**Exemplos de temas:**

```tsx
// Tema Verde
<ChatWidget
  theme={{
    primaryColor: '#10b981',
    primaryColorHover: '#059669',
    primaryColorLight: 'rgba(16, 185, 129, 0.9)'
  }}
/>

// Tema Roxo
<ChatWidget
  theme={{
    primaryColor: '#8b5cf6',
    primaryColorHover: '#7c3aed',
    primaryColorLight: 'rgba(139, 92, 246, 0.9)'
  }}
/>

// Tema usando cores da sua marca
<ChatWidget
  theme={{
    primaryColor: '#ff6b35',
    primaryColorHover: '#ff5722',
    primaryColorLight: 'rgba(255, 107, 53, 0.9)'
  }}
/>
```

As cores serão aplicadas em:
- Botão flutuante do chat
- Header do widget
- Bolhas de mensagens enviadas
- Botão de enviar
- Ícones e destaques

#### ChatMessages
Apenas a área de mensagens.

```tsx
import { ChatMessages } from '@leve.ai/chat/web'

<ChatMessages />
```

#### ChatInput
Apenas o input de envio.

```tsx
import { ChatInput } from '@leve.ai/chat/web'

<ChatInput />
```

#### ChatRoomsList
Apenas a lista de salas.

```tsx
import { ChatRoomsList } from '@leve.ai/chat/web'

<ChatRoomsList />
```

### React Native Components

Mesmos componentes, porém adaptados para React Native:

```tsx
import {
  ChatWidget,
  ChatMessages,
  ChatInput,
  ChatRoomsList
} from '@leve.ai/chat/native'
```

## 🔧 TypeScript

Todos os tipos são exportados do `/shared`:

```tsx
import type {
  Message,
  ChatRoom,
  User,
  MessageType,
  ConnectionStatus,
  ChatState,
  ChatContextType,
  ChatTheme,
  ChatWidgetProps
} from '@leve.ai/chat/shared'
```

**Tipo ChatTheme:**
```typescript
interface ChatTheme {
  primaryColor?: string
  primaryColorHover?: string
  primaryColorLight?: string
}
```

## 🎯 Casos de Uso

### Chat em Página de Pedidos

```tsx
import { useOrderRooms } from '@leve.ai/chat/shared'

function OrdersPage() {
  const { data: orders } = useOrders()

  const {
    openOrderChat,
    getAllOrdersUnreadCount
  } = useOrderRooms({
    orderIds: orders?.map(o => o.id) || [],
    enabled: !!orders
  })

  const unreadByOrder = getAllOrdersUnreadCount()

  return (
    <div>
      {orders?.map(order => (
        <div key={order.id}>
          <h3>{order.id}</h3>
          <button onClick={() => openOrderChat(order.id)}>
            Chat {unreadByOrder[order.id] > 0 && `(${unreadByOrder[order.id]})`}
          </button>
        </div>
      ))}
    </div>
  )
}
```

### Botão de Chat no Header

```tsx
import { useChatWidget } from '@leve.ai/chat/shared'

function Header() {
  const { showWidget, unreadCount, hasUnreadMessages } = useChatWidget()

  return (
    <header>
      <button onClick={showWidget} className="relative">
        <MessageCircle />
        {hasUnreadMessages && (
          <span className="absolute -top-1 -right-1 bg-red-500 text-white rounded-full px-1.5 py-0.5 text-xs">
            {unreadCount}
          </span>
        )}
      </button>
    </header>
  )
}
```

### UI Totalmente Customizado

```tsx
import { useChat } from '@leve.ai/chat/shared'

function MyCustomChat() {
  const { messages, sendMessage, currentRoom } = useChat()

  return (
    <div className="my-custom-chat">
      <div className="messages">
        {messages.map(msg => (
          <div key={msg.id} className="message">
            <span>{msg.senderName}:</span>
            <span>{msg.content}</span>
          </div>
        ))}
      </div>
      <input
        onKeyPress={(e) => {
          if (e.key === 'Enter') {
            sendMessage(e.currentTarget.value)
            e.currentTarget.value = ''
          }
        }}
      />
    </div>
  )
}
```

## 📦 Estrutura de Imports

```
@leve.ai/chat
├── /web          → Componentes Web (TailwindCSS)
├── /native       → Componentes React Native (StyleSheet)
└── /shared       → Hooks, Context, Types (compartilhados)
```

**Tree-shaking:** Apenas o código importado será incluído no bundle final.

## ⚙️ Configuração

### 🎨 Estilos e CSS

O chat usa Tailwind CSS com **prefixo `lv-`** e **isolamento de estilos** para evitar conflitos com seu projeto.

**Todas as classes são prefixadas automaticamente:**
- `flex` → `lv-flex`
- `bg-primary` → `lv-bg-primary`
- `text-white` → `lv-text-white`

**Problemas com estilos?** Veja o guia completo:
- 📖 [Guia de Isolamento de CSS](./CSS_ISOLATION.md)
- 📖 [Documentação Completa de Estilos](./STYLING.md)

### Web (TailwindCSS)

Se estiver usando TailwindCSS no seu projeto, você pode:

**Opção 1:** Ignorar o pacote no seu Tailwind (recomendado)
```js
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "!./node_modules/@leve.ai/**/*", // ← Ignora o pacote
  ],
}
```

**Opção 2:** Incluir o pacote (não recomendado)
```js
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "./node_modules/@leve.ai/chat/dist/web/**/*.{js,mjs}"
  ],
}
```

### React Native (Ícones)

Instale os ícones para React Native:

```bash
npm install lucide-react-native
```

## 🔗 Peer Dependencies

- `react`: ^18.0.0 || ^19.0.0
- `react-dom`: ^18.0.0 || ^19.0.0 (Web only)
- `react-native`: >=0.70.0 (Native only)
- `@leve.ai/socket-client`: ^1.0.0

## 📄 Licença

MIT © Leve.ai

## 🔧 Desenvolvimento

Para desenvolver e testar a biblioteca localmente, veja o [Guia de Desenvolvimento](./DEVELOPMENT.md).

**Quick Start:**
```bash
# Link para testes locais
npm run link:bun  # ou link:yarn / link:npm

# Build com watch mode
npm run build:watch

# Usar helper script
./dev-link.sh link bun
```

## 🤝 Contribuindo

Contribuições são bem-vindas! Por favor, abra uma issue ou PR.

## 📮 Suporte

- 📧 Email: suporte@leve.ai
- 📖 Docs: https://docs.leve.ai
- 🐛 Issues: https://github.com/leveai/chat/issues