npm package: @quickly-desk/sdk
Description: SDK para integração fácil do Quickly Desk em aplicações React e React Native
Latest version: 0.0.3

# Quickly Desk SDK

SDK for easy integration of Quickly Desk in React and React Native applications.

## Installation

```bash
npm install @quickly-desk/sdk
# or
yarn add @quickly-desk/sdk
```

## Usage

### React (Web)

```tsx
import React, { useMemo } from "react";
import {
  QuicklyDeskProvider,
  useCustomerAuth,
  useChatsWithWebSocket,
} from "@quickly-desk/sdk";

function App() {
  const config = useMemo(
    () => ({
      publicKey: "your-public-key",
      customerReference: "unique-customer-id",
      customerName: "Customer Name",
      metadata: {
        phone: "11999999999",
        // other optional metadata
      },
    }),
    []
  );

  return (
    <QuicklyDeskProvider config={config}>
      <YourApp />
    </QuicklyDeskProvider>
  );
}
```

function YourApp() {
const { loading, error, signOut } = useCustomerAuth();
const { chats, messages, sendMessage, createChat } = useChatsWithWebSocket();

// Use the hooks as needed
return <div>...</div>;
}

````

### React Native

```tsx
import React, { useMemo } from "react";
import {
  QuicklyDeskProvider,
  useCustomerAuth,
  useChatsWithWebSocket,
} from "@quickly-desk/sdk";

function App() {
  const config = useMemo(
    () => ({
      publicKey: "your-public-key",
      customerReference: "unique-customer-id",
      customerName: "Customer Name",
      metadata: {
        phone: "11999999999",
      },
    }),
    []
  );

  return (
    <QuicklyDeskProvider config={config}>
      <YourApp />
    </QuicklyDeskProvider>
  );
}
````

## Features

- **No caching**: The SDK always authenticates when the provider is executed
- **Automatic token refresh**: Tokens are automatically refreshed when expired
- **Request queue**: Failed requests are queued and retried after token refresh
- **WebSocket support**: Real-time chat functionality with WebSocket connections

## API

### Hooks

#### `useCustomerAuth()`

Hook for managing customer authentication.

```tsx
const { loading, error, signOut } = useCustomerAuth();
```

- `loading`: Loading state during authentication (boolean)
- `error`: Error message if authentication fails (string | null)
- `signOut()`: Function to sign out manually

#### `useChatsWithWebSocket()`

**Main hook** for managing chats and messages. Automatically manages the WebSocket connection based on the component lifecycle.

**Features**:
- ✅ Automatically connects to WebSocket when the component mounts
- ✅ Waits for the WebSocket connection to be ready before loading chats
- ✅ Automatically calls `loadChats()` after connecting
- ✅ Automatically disconnects when the component unmounts (if it's the last component using it)
- ✅ Uses reference counting to keep the connection alive during screen navigation
- ✅ Protection against race conditions and multiple calls
- ✅ Robust error and timeout handling
- ✅ Can be used in multiple components simultaneously

```tsx
const {
  chats,
  currentChat,
  messages,
  staffPresence,
  typingStatus,
  ws,
  loading,
  sendMessageLoading,
  createChatLoading,
  loadChats,
  loadChatHistory,
  sendMessage,
  createChat,
} = useChatsWithWebSocket();
```

**Returned properties**:
- `chats`: List of chats (Chat[])
- `currentChat`: Currently selected chat (Chat | null)
- `messages`: Messages of the current chat (ChatMessage[])
- `staffPresence`: Staff members currently viewing chats (`string[]`, each entry is `"staffId:chatId"`)
- `typingStatus`: Typing status per chat (`{ [id_chat: string]: { [id_user: string]: string } }`)
- `ws`: WebSocket connection (WebSocket | null)
- `loading`: Loading state (boolean)
- `sendMessageLoading`: Message sending state (boolean)
- `createChatLoading`: Chat creation state (boolean)
- `loadChats()`: Loads the chat list
- `loadChatHistory(id_chat)`: Loads a specific chat's history
- `sendMessage(id_chat, content)`: Sends a message
- `createChat()`: Creates a new chat

**Usage examples**:

```tsx
// Chat list screen
function ChatsListScreen() {
  const { chats, loading, loadChats, createChat } = useChatsWithWebSocket();
  
  // WebSocket connects automatically on mount
  // loadChats() is called automatically after connection
  // WebSocket disconnects automatically on unmount
  
  const onRefresh = async () => {
    await loadChats(); // Can be called manually for refresh
  };
  
  return (
    <FlatList
      data={chats}
      renderItem={({ item }) => <ChatListItem chat={item} />}
      onRefresh={onRefresh}
      refreshing={loading}
    />
  );
}

// Individual chat screen
function ChatScreen({ id_chat }: { id_chat: string }) {
  const { messages, loadChatHistory, sendMessage, loading } = useChatsWithWebSocket();
  
  // Can use the same hook - WebSocket connection is shared
  // No need to manage the connection manually
  
  useEffect(() => {
    if (id_chat) {
      loadChatHistory(id_chat);
    }
  }, [id_chat, loadChatHistory]);
  
  return (
    <View>
      <FlatList data={messages} renderItem={({ item }) => <MessageBubble message={item} />} />
      <MessageInput onSend={(content) => sendMessage(id_chat, content)} />
    </View>
  );
}
```


## Types

```typescript
interface Chat {
  id_chat: string;
  id_tenant: string;
  id_customer: string;
  created_at?: string;
  updated_at?: string;
  customer_name?: string;
  last_message?: string | null;
  last_message_time?: string | null;
  unread_count?: number;
}

interface ChatMessage {
  id_chat_message: number;
  id_chat: string;
  sender: string;
  id_sender: string;
  read: boolean;
  content: string;
  created_at?: string;
}
```

## Configuration

### SDKConfig

```typescript
interface SDKConfig {
  apiUrl?: string; // API URL (optional)
  wsUrl?: string; // WebSocket URL (optional)
  publicKey: string; // Public key (required)
  customerReference: string; // Unique customer ID (required)
  customerName: string; // Customer name (required)
  metadata?: Record<string, any>; // Optional metadata
}
```

## Authentication Flow

The SDK automatically:

1. Authenticates when the provider is executed (calls `/auth/customer`)
2. Stores the token in memory (no persistent storage)
3. Refreshes the token automatically when it expires
4. Queues failed requests during token refresh and retries them after refresh

## Edge Cases and Behaviors

### Limits and Validations

- **Maximum message size:** 5000 characters
- **Maximum request queue size:** 50 requests
- **Queue timeout:** 30 seconds
- **WebSocket connection timeout:** 10 seconds (default)
- **Maximum WebSocket retry attempts:** 3 attempts
- **Maximum processed messages in memory:** 100 IDs

### Automatic Behaviors

1. **WebSocket reconnection:** The SDK automatically reconnects if the connection closes unexpectedly (code !== 1000)
2. **Duplicate prevention:** Duplicate messages are automatically ignored using a Set of processed IDs
3. **Message validation:** All WebSocket messages are validated before being processed
4. **Automatic retry:** WebSocket attempts to reconnect up to 3 times with exponential backoff (1s, 2s, 4s, max 10s)
5. **Resource cleanup:** All timeouts and listeners are properly cleaned up when components unmount

### Error Handling

The SDK classifies errors into specific types:

- `NetworkError`: Network connection errors
- `TimeoutError`: Request or connection timeouts
- `AuthenticationError`: Authentication errors
- `ValidationError`: Input validation errors

### Multiple Components

You can use `useChatsWithWebSocket` in multiple components simultaneously:

- The WebSocket connection is shared between all components
- A reference counter manages when to connect/disconnect
- The connection only closes when the last component unsubscribes

### Screen Navigation

- When navigating from the chat list to a specific chat, the WebSocket connection is kept alive
- When leaving the list screen, the connection closes automatically
- Messages keep arriving even when not on the list screen (if another component is using it)

## Troubleshooting

For common problems and solutions, see [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).

## License

MIT