#6 Chat typing status

Спојено
merisahm споји(ла) 1 комит(е) из feature/315_chat_typing_status у development пре 3 година

+ 14
- 0
Backend/Diligent.WebAPI.Host/Hubs/ChatHub.cs Прегледај датотеку

@@ -88,5 +88,19 @@ namespace Diligent.WebAPI.Host.Hubs
await _mediator.Send(new RemoveUserFromGroupCommand(room.RoomId, room.UserId));
}
}

[HubMethodName("SeeWhoIsTyping")]
public async Task SeeWhoIsTyping(TypingInvokeMessage message)
{
// Find user's room and send message to everyone
//if (_connections.TryGetValue(Context.ConnectionId, out UserConnection room))
if (_connections.TryGetValue(message.ConnId, out UserConnection room))
{
// send the typing info to all in group except the caller
// viewtyping(username + "is typing") // message, roomId
//await Clients.GroupExcept(message.RoomId, Context.ConnectionId).ViewTyping(new TypingMessage { RoomId = room.RoomId, Message = message.Message });
await Clients.GroupExcept(message.RoomId, message.ConnId).ViewTyping(new TypingMessage { RoomId = room.RoomId, Message = message.Message });
}
}
}
}

+ 1
- 0
Backend/Diligent.WebAPI.Host/Hubs/IChatClient.cs Прегледај датотеку

@@ -5,5 +5,6 @@
Task ReceiveMessage(ChatMessage message);

Task ReceiveNotifications(string userId, string roomId);
Task ViewTyping(TypingMessage message);
}
}

+ 14
- 0
Backend/Diligent.WebAPI.Host/Hubs/TypingMessage.cs Прегледај датотеку

@@ -0,0 +1,14 @@
namespace Diligent.WebAPI.Host.Hubs
{
public class TypingInvokeMessage
{
public string ConnId { get; set; }
public string RoomId { get; set; }
public string Message { get; set; }
}
public class TypingMessage
{
public string Message { get; set; }
public string RoomId { get; set; }
}
}

+ 5
- 5
Backend/Diligent.WebAPI.Host/Hubs/UserConnection.cs Прегледај датотеку

@@ -1,13 +1,13 @@
namespace Diligent.WebAPI.Host.Hubs
{
public class UserConnection
public class UserStatus
{
// UserId in hub
public string UserId { get; set; }

// Username in hub
public string Mode { get; set; }
}
public class UserConnection : UserStatus
{
public string Username { get; set; }

// RoomId in hub
public string RoomId { get; set; }
}

+ 5
- 0
Frontend/src/components/ChatList.js Прегледај датотеку

@@ -100,6 +100,11 @@ const ChatList = () => {
})
);
});

connection.on("ViewTyping", (data) =>{
dispatch(chatActions.addTyping(data));
})
connection.on("ReceiveNotifications", (userId, roomId) => {
if (user.id !== userId) dispatch(chatActions.addNotification(roomId));
});

+ 23
- 1
Frontend/src/components/ChatWindow.js Прегледај датотеку

@@ -4,6 +4,7 @@ import { UserContext } from "../contexts/userContext";
import { useSelector, useDispatch } from "react-redux";
import { chatActions } from "../store/chat-slice";
import { BsCircleFill } from 'react-icons/bs'
import TypingBar from "./TypingBar";

const ChatWindow = ({ room }) => {
const messagesEndRef = useRef(null);
@@ -15,6 +16,7 @@ const ChatWindow = ({ room }) => {
const [message, setMessage] = useState("");
const { user } = useContext(UserContext);
const connection = useSelector((state) => state.chat.connection);
const { typings } = useSelector((s) => s.chat)
const connections = useSelector((state) => state.chat.connections);
const activeRoom = useSelector((state) => state.chat.activeRoom);
const messages = useSelector((state) => state.chat.messages);
@@ -60,6 +62,24 @@ const ChatWindow = ({ room }) => {
const status = useSelector((s) => s.status);
const { activeUsers } = status;

const messageOnChangeHandler = async (e) =>{
setMessage(e.target.value)
const userToFetch = connections.filter(
(conn) => conn.userId === user.id && conn.roomId === activeRoom.id
);

// console.log(userToFetch[0].connId)
// console.log(room.id)
await connection.send("SeeWhoIsTyping", {
message: `${user.username} is typing...`,
connId: userToFetch[0].connId,
roomId: activeRoom.id
});
}


return (
<div className="px-3 bg-light-transparent rounded h-100 d-flex flex-column">
<div style={{ height: "80px" }}>
@@ -119,13 +139,15 @@ const ChatWindow = ({ room }) => {
<div ref={messagesEndRef} />
</div>

<TypingBar id={activeRoom.id}/>

<Form style={{ height: "80px" }} className="d-flex align-items-center">
<InputGroup className="mb-3">
<FormControl
placeholder="Enter your messagge..."
aria-label="Enter your messagge..."
aria-describedby="basic-addon2"
onChange={(e) => setMessage(e.target.value)}
onChange={(e) => messageOnChangeHandler(e)}
/>

<Button

+ 28
- 0
Frontend/src/components/TypingBar.js Прегледај датотеку

@@ -0,0 +1,28 @@
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { chatActions } from '../store/chat-slice';

const TypingBar = ({id}) => {
const [rerender, setRerender] = useState(false)

const dispatch = useDispatch();
const {typings} = useSelector(s => s.chat)
// On componentDidMount set the timer
useEffect(() => {
const timeout = setTimeout(() => {
dispatch(chatActions.removeTyping());
setRerender(!rerender)
return () => clearTimeout(timeout)
}, 2500)
}, [rerender]);

return (
<div className='text-dark'>
{typings.filter(n => n.roomId === id).length > 1 ? <p className='p-0 m-0 text-start w-100 text-muted pt-1'>2 or more users are typing</p> : typings.map(n=> n.roomId === id ? <p key={n.message} className='p-0 m-0 text-start w-100 text-muted pt-1'>{n.message}</p> : '')}
</div>
)
}

export default TypingBar

+ 12
- 0
Frontend/src/store/chat-slice.js Прегледај датотеку

@@ -15,6 +15,7 @@ const initialState = {
connections: [],
// Notifications
notifications: [],
typings: []
};

export const fetchChatRoomsAsync = createAsyncThunk(
@@ -144,6 +145,17 @@ const chatSlice = createSlice({
(customer) => customer.customerId !== action.payload.customerId
);
},
addTyping: (state, action) => {
if(!state.typings.some(n => n.message === action.payload.message && n.roomId === action.payload.roomId))
state.typings = [...state.typings, action.payload];
else console.log('ima vec')
},
removeTyping: (state, action) => {
if(state.typings.length >= 1){
let f = state.typings[0]
state.typings = state.typings.filter(n => n.message !== f.message);
}
}
},
extraReducers: (builder) => {
// Fetch chat rooms

Loading…
Откажи
Сачувај