npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@vserifsaglam/chat-react-client

v1.0.5

Published

Frontend library to easliy connect to the chat

Readme

Chat React Client

A React library for integratin with the Chat Backend API

NPM JavaScript Style Guide

Features

  • 🔒 Secure authentication with JWT tokens
  • 🔄 Real-time chat functionality with WebSocket
  • 📁 File uploads and attachments
  • 📱 Responsive design
  • 🧩 Modular architecture with React hooks
  • 📝 TypeScript support
  • 🔁 Automatic reconnection and fallback mechanisms
  • 📋 Message queue for handling failed sends
  • 📄 Pagination support for message history
  • 🔔 Unread message indicators
  • 🔄 Conversation and message management hooks for simplified integration

Installation

npm install --save chat-react-client
# or
yarn add chat-react-client

Quick Start

Wrap your application with the ChatClient component to provide authentication and API access:

import React from 'react';
import { ChatClient, ConnectionType } from 'chat-react-client';

const App = () => {
  return (
    <ChatClient
      token="your_jwt_token"
      baseUrl="https://api.example.com"
      connectionOptions={{
        connectionType: ConnectionType.WebSocket,
        autoReconnect: true
      }}
    >
      <YourChatComponent />
    </ChatClient>
  );
};

// Example with long polling only
const AppWithLongPolling = () => {
  return (
    <ChatClient
      token="your_jwt_token"
      baseUrl="https://api.example.com"
      connectionOptions={{
        connectionType: ConnectionType.LongPolling,
        onlyLongpolling: true,
        autoReconnect: true
      }}
    >
      <YourChatComponent />
    </ChatClient>
  );
};

export default App;

The connectionOptions prop allows you to configure the realtime connection:

  • connectionType: Select the connection type (WebSocket or LongPolling)
  • autoReconnect: Automatically reconnect if the connection is lost
  • onlyLongpolling: Force the connection to use long polling only (no WebSocket)

Hooks

useConversationManagement

A higher-level hook for managing conversations, including conversation selection and state management:

import React from 'react';
import { useConversationManagement } from 'chat-react-client';

const ConversationsManager = () => {
  const {
    conversations,
    conversationsLoading,
    selectedConversationId,
    selectedConversation,
    handleSelectConversation,
    getConversations
  } = useConversationManagement();

  if (conversationsLoading) return <div>Loading conversations...</div>;

  return (
    <div className="chat-container">
      <div className="conversations-list">
        {conversations.map(conversation => (
          <div
            key={conversation.id}
            className={`conversation ${selectedConversationId === conversation.id ? 'selected' : ''}`}
            onClick={() => handleSelectConversation(conversation)}
          >
            <h3>{conversation.user.name}</h3>
            <p>{conversation.lastMessage?.content}</p>
            {conversation.unreadCount > 0 && (
              <span className="unread-badge">{conversation.unreadCount}</span>
            )}
          </div>
        ))}
      </div>

      {selectedConversation && (
        <div className="conversation-details">
          <h2>Chat with {selectedConversation.user.name}</h2>
          <MessagePanel conversationId={selectedConversationId} />
        </div>
      )}
    </div>
  );
};

useMessageManagement

A higher-level hook for managing messages in a conversation, including pagination, file uploads, and real-time updates:

import React, { useState, useRef } from 'react';
import { useMessageManagement } from 'chat-react-client';

const MessagePanel = ({ conversationId, receiverId }) => {
  const [messageText, setMessageText] = useState('');
  const [file, setFile] = useState(null);
  const messagesEndRef = useRef(null);

  const {
    messages,
    messagesLoading,
    fileLoading,
    uploadProgress,
    uploadFile,
    handleSendMessage,
    handleSendFileMessage,
    loadMoreMessages,
    hasMore
  } = useMessageManagement(conversationId);

  const handleSend = async () => {
    if (!messageText.trim()) return;

    const success = await handleSendMessage(messageText, receiverId);
    if (success) {
      setMessageText('');
    }
  };

  const handleFileUpload = async (e) => {
    const selectedFile = e.target.files[0];
    if (!selectedFile) return;

    setFile(selectedFile);
    const fileId = await uploadFile(selectedFile);

    if (fileId) {
      await handleSendFileMessage(`Sent a file: ${selectedFile.name}`, fileId, receiverId);
      setFile(null);
    }
  };

  return (
    <div className="message-panel">
      {hasMore && (
        <button
          onClick={loadMoreMessages}
          disabled={messagesLoading}
          className="load-more-button"
        >
          {messagesLoading ? 'Loading...' : 'Load Previous Messages'}
        </button>
      )}

      <div className="messages-container">
        {messages.map(message => (
          <div key={message.id} className={`message ${message.is_mine ? 'mine' : 'theirs'}`}>
            <p>{message.content}</p>
            {message.attachments?.length > 0 && (
              <div className="attachments">
                {message.attachments.map(attachment => (
                  <a key={attachment.id} href={attachment.url} target="_blank" rel="noopener noreferrer">
                    {attachment.filename}
                  </a>
                ))}
              </div>
            )}
            <small>{new Date(message.timestamp).toLocaleString()}</small>
          </div>
        ))}
        <div ref={messagesEndRef} />
      </div>

      <div className="message-input">
        {fileLoading && (
          <div className="upload-progress">
            <div className="progress-bar" style={{ width: `${uploadProgress}%` }}></div>
            <span>{uploadProgress}%</span>
          </div>
        )}

        <input
          type="text"
          value={messageText}
          onChange={e => setMessageText(e.target.value)}
          placeholder="Type a message..."
        />
        <input type="file" onChange={handleFileUpload} />
        <button onClick={handleSend} disabled={messagesLoading || fileLoading}>Send</button>
      </div>
    </div>
  );
};

useConversations

Access and manage conversations:

import React, { useEffect } from 'react';
import { useConversations } from 'chat-react-client';

const ConversationsList = () => {
  const {
    conversations,
    loading,
    error,
    getConversations,
    archiveConversation,
    unarchiveConversation,
    deleteConversation
  } = useConversations();

  useEffect(() => {
    getConversations();
  }, [getConversations]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      {conversations.map(conversation => (
        <div key={conversation.id}>
          <h3>{conversation.user.name}</h3>
          <p>{conversation.lastMessage?.content}</p>
          <button onClick={() => archiveConversation(conversation.id)}>
            Archive
          </button>
        </div>
      ))}
    </div>
  );
};

useMessages

Send and receive messages:

import React, { useState, useEffect } from 'react';
import { useMessages } from 'chat-react-client';

const ChatMessages = ({ conversationId }) => {
  const [messageText, setMessageText] = useState('');
  const {
    messages,
    loading,
    sendMessage,
    getMessages,
    markConversationAsRead
  } = useMessages(conversationId);

  useEffect(() => {
    if (conversationId) {
      getMessages();
      markConversationAsRead();
    }
  }, [conversationId, getMessages, markConversationAsRead]);

  const handleSend = async () => {
    if (!messageText.trim()) return;

    await sendMessage({
      receiver_client_id: 'recipient_id',
      content: messageText
    });

    setMessageText('');
  };

  return (
    <div>
      <div className="messages-container">
        {messages.map(message => (
          <div key={message.id} className="message">
            <p>{message.content}</p>
            <small>{new Date(message.timestamp).toLocaleString()}</small>
          </div>
        ))}
      </div>

      <div className="message-input">
        <input
          type="text"
          value={messageText}
          onChange={e => setMessageText(e.target.value)}
          placeholder="Type a message..."
        />
        <button onClick={handleSend} disabled={loading}>Send</button>
      </div>
    </div>
  );
};

useFiles

Upload files and attachments:

import React, { useState } from 'react';
import { useFiles, useMessages } from 'chat-react-client';

const FileUploader = ({ conversationId }) => {
  const { uploadFile, uploadProgress, loading } = useFiles();
  const { sendMessage } = useMessages(conversationId);
  const [file, setFile] = useState(null);

  const handleFileChange = (e) => {
    setFile(e.target.files[0]);
  };

  const handleUpload = async () => {
    if (!file) return;

    const response = await uploadFile(file);

    if (response) {
      // Send a message with the file attachment
      await sendMessage({
        receiver_client_id: 'recipient_id',
        content: 'I sent you a file',
        attachments: [response.file_id]
      });
    }
  };

  return (
    <div>
      <input type="file" onChange={handleFileChange} />

      {file && (
        <>
          <div className="progress-bar">
            <div
              className="progress"
              style={{ width: `${uploadProgress}%` }}
            ></div>
          </div>
          <button onClick={handleUpload} disabled={loading}>
            Upload and Send
          </button>
        </>
      )}
    </div>
  );
};

API Reference

ChatClient

The main component that provides authentication and API access.

Props:

  • token (string): JWT token for authentication
  • baseUrl (string): Base URL of the Chat API
  • connectionOptions (ConnectionOptions): Options for the realtime connection
  • children (ReactNode): Child components

ConnectionOptions

Options for configuring the realtime connection:

  • connectionType (ConnectionType): The type of connection to use (WebSocket or LongPolling)
  • autoReconnect (boolean): Whether to automatically reconnect if the connection is lost
  • reconnectAttempts (number): Maximum number of reconnection attempts
  • reconnectDelay (number): Delay between reconnection attempts in milliseconds
  • onlyLongpolling (boolean): Force the connection to use long polling only (no WebSocket)

User

Interface representing a user in the chat system:

  • id (string): Unique identifier for the user
  • name (string): Display name of the user
  • avatar (string): URL to the user's avatar image
  • is_admin (boolean): Whether the user is an admin
  • attributes (Record<string, any>): Additional attributes for the user
  • file_storage_provider (string): The storage provider for the user's files
  • owner_client_id (string): The client ID of the user's owner

Conversation

Interface representing a conversation:

  • id (string): Unique identifier for the conversation
  • status (string): Status of the conversation (e.g., "answered")
  • user (User): The user participating in the conversation
  • lastMessage (LastMessage): The last message in the conversation
  • unreadCount (number): Number of unread messages in the conversation

ConversationDetails

Interface representing detailed information about a conversation:

  • conversation_uid (string): Unique identifier for the conversation
  • user_message_count (number): Number of messages sent by the user
  • user_attachment_count (number): Number of attachments sent by the user
  • user_attachments (Attachment[]): List of attachments sent by the user
  • participants (User[]): List of participants in the conversation

useConversations

Hook for managing conversations.

Returns:

  • conversations (Conversation[]): List of conversations
  • loading (boolean): Loading state
  • error (Error | null): Error state
  • getConversations(archived?: boolean, clientId?: string): Get conversations
  • deleteConversation(conversationUid: string): Delete a conversation
  • archiveConversation(conversationUid: string): Archive a conversation
  • unarchiveConversation(conversationUid: string): Unarchive a conversation
  • getConversationDetails(conversationUid: string): Get conversation details
  • searchConversation(conversationUid: string, term: string): Search messages in a conversation

useMessages

Hook for managing messages.

Parameters:

  • conversationUid (string, optional): ID of the conversation

Returns:

  • messages (Message[]): List of messages
  • pagination (MessagesPagination): Pagination information
  • loading (boolean): Loading state
  • error (Error | null): Error state
  • getMessages(conversationId?: string, page?: number, pageSize?: number): Get messages
  • markMessageAsRead(messageId: number): Mark a message as read
  • sendMessage(message: SendMessageRequest): Send a message
  • markConversationAsRead(conversationId?: string): Mark all messages in a conversation as read
  • updateMessage(messageId: number, update: UpdateMessageRequest): Update a message
  • deleteMessage(messageId: number): Delete a message

useFiles

Hook for managing file uploads.

Returns:

  • loading (boolean): Loading state
  • error (Error | null): Error state
  • uploadProgress (number): Upload progress (0-100)
  • uploadFile(file: File): Upload a file

useConnection

Hook for managing the realtime connection.

Returns:

  • status (ConnectionStatus): Current connection status
  • isConnected (boolean): Whether the connection is active
  • isConnecting (boolean): Whether the connection is in progress
  • hasError (boolean): Whether the connection has an error
  • connect(): Connect to the server
  • disconnect(): Disconnect from the server
  • sendMessage(message: SendMessageRequest, maxAttempts?: number): Send a message with retry support

useRealtime

Hook for subscribing to realtime events.

Parameters:

  • eventType (EventType): The event type to subscribe to

Returns:

  • event (RealtimeEvent | null): The latest event
  • clearEvent(): Clear the current event

useMessageSentEvents

Hook for subscribing to message sent events.

Returns:

  • event (RealtimeEvent | null): The latest message sent event
  • clearEvent(): Clear the current event

useMessageEditedEvents

Hook for subscribing to message edited events.

Returns:

  • event (RealtimeEvent | null): The latest message edited event
  • clearEvent(): Clear the current event

useMessageDeletedEvents

Hook for subscribing to message deleted events.

Returns:

  • event (RealtimeEvent | null): The latest message deleted event
  • clearEvent(): Clear the current event

useConversationManagement

Hook for managing conversations with selection state.

Returns:

  • conversations (Conversation[]): List of conversations
  • conversationsLoading (boolean): Loading state for conversations
  • selectedConversationId (string): ID of the currently selected conversation
  • selectedConversation (Conversation | undefined): The currently selected conversation object
  • handleSelectConversation(conversation: Conversation): Function to select a conversation
  • getConversations(): Function to load conversations

useMessageManagement

Hook for managing messages in a conversation with pagination and file handling.

Parameters:

  • selectedConversationId (string): ID of the conversation to manage messages for

Returns:

  • messages (Message[]): List of messages in the conversation
  • messagesLoading (boolean): Loading state for messages
  • fileLoading (boolean): Loading state for file uploads
  • uploadProgress (number): Upload progress percentage (0-100)
  • uploadFile(file: File): Function to upload a file
  • handleSendMessage(content: string, receiverId: string): Function to send a text message
  • handleSendFileMessage(content: string, fileId: number, receiverId: string): Function to send a message with a file attachment
  • getMessages(conversationId?: string, page?: number): Function to get messages for a conversation
  • loadMoreMessages(): Function to load more messages (pagination)
  • hasMore (boolean): Whether there are more messages to load

useAllMessageEvents

Hook for subscribing to all message events.

Returns:

  • messageSent (RealtimeEvent | null): The latest message sent event
  • messageEdited (RealtimeEvent | null): The latest message edited event
  • messageDeleted (RealtimeEvent | null): The latest message deleted event
  • clearEvents(): Clear all events

Realtime Examples

Connection Management

import React, { useEffect } from 'react';
import { useConnection, ConnectionStatus } from 'chat-react-client';

const ConnectionStatusComponent = () => {
  const { status, isConnected, connect, disconnect } = useConnection();

  useEffect(() => {
    // Connect when the component mounts
    connect();

    // Disconnect when the component unmounts
    return () => {
      disconnect();
    };
  }, [connect, disconnect]);

  return (
    <div>
      <div>Connection Status: {status}</div>
      <button onClick={connect} disabled={isConnected}>
        Connect
      </button>
      <button onClick={disconnect} disabled={!isConnected}>
        Disconnect
      </button>
    </div>
  );
};

### Event Listening

```tsx
import React, { useEffect, useState } from 'react';
import { useAllMessageEvents } from 'chat-react-client';

const MessageEventListener = () => {
  const [messages, setMessages] = useState([]);
  const {
    messageSent,
    messageEdited,
    messageDeleted,
    clearEvents
  } = useAllMessageEvents();

  // Handle new message
  useEffect(() => {
    if (messageSent) {
      setMessages(prevMessages => [...prevMessages, messageSent.data]);
      clearEvents();
    }
  }, [messageSent, clearEvents]);

  // Handle edited message
  useEffect(() => {
    if (messageEdited) {
      setMessages(prevMessages =>
        prevMessages.map(msg =>
          msg.id === messageEdited.data.msg_id
            ? { ...msg, content: messageEdited.data.new_content }
            : msg
        )
      );
      clearEvents();
    }
  }, [messageEdited, clearEvents]);

  // Handle deleted message
  useEffect(() => {
    if (messageDeleted) {
      setMessages(prevMessages =>
        prevMessages.filter(msg => msg.id !== messageDeleted.data.msg_id)
      );
      clearEvents();
    }
  }, [messageDeleted, clearEvents]);

  return (
    <div>
      <h3>Messages</h3>
      <ul>
        {messages.map(msg => (
          <li key={msg.id}>{msg.content}</li>
        ))}
      </ul>
    </div>
  );
};

Complete Example

For a complete example of how to use the library, see the example directory.

License

MIT © vahit