Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any way to for the receiver to receive when the sender is typing? #240

Open
jonny-dungeons opened this issue Jul 16, 2024 · 2 comments
Open

Comments

@jonny-dungeons
Copy link

In a scenario where you have 2 users chatting is there any way for the receiver to know when the sender is typing using your hook?

@jonny-dungeons
Copy link
Author

Anybody using this hook library? If so I'd like to know if there is a way for sender to emit/broadcast to receiver. This would help me build the typing indicator that lets receiver see that user is typing.

@Mark-Elliott5
Copy link

You need a server in the middle to relay messages to other Websocket connections. Use webRTC if you want a peer to peer connection.

Here's a barebones example that sends a 'typing' indicator to the server, which then relays that back to other connected clients, which then displays who is typing within the same component (a chat application would need to be more fleshed out in reality). The component only sends when e.target.value.length changes from 0 to 1 or 1 to 0, to stop unnecessary messages:

Component:

import useWebSocket from 'react-use-websocket';
import { useRef } from 'react';

interface ITypingIndication {
  action: 'typing';
  typing: boolean;
}

interface ITypingMessage {
  type: 'typing';
  typing: boolean;
  user: string;
}

function MessageForm() {
  const { sendMessage, readyState, lastMessage } = useWebSocket(`wss://${window.location.host}/chat`);
  
  const typingMessage: ITypingMessage = (() => {
    try {
      return JSON.parse(lastMessage);
    } catch (e) {
      return { type: 'typing', typing: false, user: ''}
    }
  })();
  
  const lastTypingSent = useRef(false);

  const handleTyping: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => {
    if (readyState !== 1) {
      return;
    }
    const typing = !!e.target.value;
    if (lastTypingSent.current === typing) {
      return;
    }
    const data: ITypingIndication = {
      action: 'typing',
      typing,
    };
    lastTypingSent.current = typing;
    sendMessage(JSON.stringify(data));
  };
  
  return (
    <>
       {lastMessage.type === "typing" && lastMessage.typing && (
          <span>{lastMessage.username} is typing...</span>
        )}
      <textarea onChange={handleTyping} />
    </>
  )
}

Server (express handler):

import WebSocket from 'ws';
import { INext, IReq, IRes } from '../types/express';

type UserAction = ITypingIndicator // | (other types of user actions messages)

interface ITypingMessage {
  type: 'typing';
  typing: boolean;
  user: string;
}

const sockets = [];

function websocketHandler(ws: WebSocket, req: IReq, next: INext) {
  sockets.push(ws);
  
  ws.on('message', (msg: WebSocket.RawData) => {
    if (!req.user) {
      return;
    }
    const data: UserActions = JSON.parse(msg.toString());
    const { action } = data;
    if (action === 'typing') {
      try {
        const { username } = req.user;
        const typingMessage: ITypingMessage = {
          type: 'typing',
          typing,
          username,
        };
        const jsonString = JSON.stringify(typingMessage);
        sockets.forEach((ws) => ws.send(jsonString));
    } catch (error) {
        console.log(error);
    }
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants