#1 316 - Ability to leave chat

Samengevoegd
bronjaermin heeft 1 commits samengevoegd van feature/316_ability_to_leave_chat naar development 3 jaren geleden

+ 23
- 0
Backend/Diligent.WebAPI.Business/Services/RoomService.cs Bestand weergeven

@@ -60,5 +60,28 @@ namespace Diligent.WebAPI.Business.Services

public async Task<List<Room>> GetRoomsForSupport(string supportId) =>
await _mongoCollection.Find(k => k.CreatedBy == supportId).ToListAsync();

public async Task<bool> LeaveChatRoom(string roomId, string userId)
{
var room = await GetRoomAsync(roomId);

if (room == null)
{
return false;
}

var userConnection = room.Customers.Where(x => x.CustomerId == userId).FirstOrDefault();

if (userConnection == null)
{
return false;
}

room.Customers.Remove(userConnection);

await _mongoCollection.ReplaceOneAsync(x => x.Id == roomId, room);

return true;
}
}
}

+ 1
- 1
Backend/Diligent.WebAPI.Host/Controllers/CustomerController.cs Bestand weergeven

@@ -68,7 +68,7 @@ namespace Diligent.WebAPI.Host.Controllers
};

var result = await _customerManager.CreateAsync(customer, customerCreateDTO.Password);
await _customerManager.AddToRoleAsync(customer, "Customer");
await _customerManager.AddToRoleAsync(customer, "Support");

if (!result.Succeeded)
{

+ 7
- 0
Backend/Diligent.WebAPI.Host/DTOs/Chat/LeaveChatRoomDTO.cs Bestand weergeven

@@ -0,0 +1,7 @@
namespace Diligent.WebAPI.Host.DTOs.Chat
{
public class LeaveChatRoomDTO
{
public string ConnId { get; set; }
}
}

+ 13
- 0
Backend/Diligent.WebAPI.Host/Hubs/ChatHub.cs Bestand weergeven

@@ -1,4 +1,6 @@
using Diligent.WebAPI.Data.Entities;
using Diligent.WebAPI.Host.DTOs.Chat;
using Diligent.WebAPI.Host.Mediator.Chat.Commands;
using Diligent.WebAPI.Host.Mediator.Messages.Commands;
using MediatR;
using Microsoft.AspNetCore.Authorization;
@@ -63,5 +65,16 @@ namespace Diligent.WebAPI.Host.Hubs
await Clients.Group(userConnection.RoomId).ReceiveMessage(new ChatMessage { User = userConnection.UserId, Message = $"{userConnection.Username} has joined room", ConnId = Context.ConnectionId });
}
}

[HubMethodName("LeaveRoom")]
public async Task LeaveRoom(LeaveChatRoomDTO connection)
{
if (_connections.TryGetValue(connection.ConnId, out UserConnection room))
{
_connections.Remove(Context.ConnectionId);
await Clients.OthersInGroup(room.RoomId).ReceiveMessage(new ChatMessage { User = room.UserId, Message = $"{room.Username} has left room" });
await _mediator.Send(new RemoveUserFromGroupCommand(room.RoomId, room.UserId));
}
}
}
}

+ 16
- 0
Backend/Diligent.WebAPI.Host/Mediator/Chat/Commands/RemoveUserFromGroupCommand.cs Bestand weergeven

@@ -0,0 +1,16 @@
using MediatR;

namespace Diligent.WebAPI.Host.Mediator.Chat.Commands
{
public class RemoveUserFromGroupCommand : IRequest<Unit>
{
public string RoomId { get; }
public string UserId { get; }

public RemoveUserFromGroupCommand(string roomId, string userId)
{
RoomId = roomId;
UserId = userId;
}
}
}

+ 33
- 0
Backend/Diligent.WebAPI.Host/Mediator/Chat/Handlers/RemoveUserFromGroupHandler.cs Bestand weergeven

@@ -0,0 +1,33 @@
using Diligent.WebAPI.Business.Services;
using Diligent.WebAPI.Host.Mediator.Chat.Commands;
using MediatR;

namespace Diligent.WebAPI.Host.Mediator.Chat.Handlers
{
public class RemoveUserFromGroupHandler : IRequestHandler<RemoveUserFromGroupCommand, Unit>
{
private readonly RoomService _roomService;

public RemoveUserFromGroupHandler(RoomService roomService)
{
_roomService = roomService;
}

public async Task<Unit> Handle(RemoveUserFromGroupCommand request, CancellationToken cancellationToken)
{
if (request == null)
{
throw new BadHttpRequestException("Object cannot be null");
}

var result = await _roomService.LeaveChatRoom(request.RoomId, request.UserId);

if (!result)
{
throw new Exception("Problem with deleting user from group");
}

return new Unit();
}
}
}

+ 57
- 26
Frontend/src/components/ChatWindow.js Bestand weergeven

@@ -5,11 +5,11 @@ import { useSelector, useDispatch } from "react-redux";
import { chatActions } from "../store/chat-slice";

const ChatWindow = ({ room }) => {
const messagesEndRef = useRef(null)
const messagesEndRef = useRef(null);

const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
}
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};

const [message, setMessage] = useState("");
const { user } = useContext(UserContext);
@@ -23,9 +23,24 @@ const ChatWindow = ({ room }) => {
dispatch(chatActions.setMessages(room.messages));
}, [dispatch, room.messages]);

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

const leftRoomHandler = async () => {
const userToFetch = connections.filter(
(conn) => conn.userId === user.id && conn.roomId === activeRoom.id
);

console.log(userToFetch[0].connId, user.id, activeRoom.id);

await connection.invoke("LeaveRoom", {
connId: userToFetch[0].connId,
});
dispatch(
chatActions.leaveRoom({ roomId: activeRoom.id, customerId: user.id })
);
};

const onSendMessageToGroupHandler = async () => {
const userToFetch = connections.filter(
@@ -38,38 +53,54 @@ const ChatWindow = ({ room }) => {
connId: userToFetch[0].connId,
});

setMessage('')
setMessage("");
};

return (
<div className="px-3 bg-light-transparent rounded h-100 d-flex flex-column">
<div style={{ height: "80px" }}>
<h2 className="py-3 m-0">{room.name}</h2>
<h2 className="py-1 m-0">{room.name}</h2>
<button
onClick={leftRoomHandler}
style={{
border: 0,
backgroundColor: "transparent",
padding: 0,
margin: 0,
textDecoration: "underline",
}}
>
Leave Room
</button>
</div>

<div className="messages p-3 border d-flex flex-column-reverse">
{/* mapirane poruke */}

{messages.map((n, index) => (
<div
key={index}
className={
n.senderId === user.id
? "d-flex flex-column align-items-end"
: "d-flex flex-column align-items-start"
}
>
<p
className={`p-2 px-4 mb-0 rounded message ${
n.senderId !== user.id ? "bg-primary text-light" : "bg-light text-dark"
}`}
{messages
.map((n, index) => (
<div
key={index}
className={
n.senderId === user.id
? "d-flex flex-column align-items-end"
: "d-flex flex-column align-items-start"
}
>
{/* {n.message} */}
{n.content}
</p>
<p className="text-muted small m-0 p-0 mb-4">{n.username}</p>
</div>
)).reverse()}
<p
className={`p-2 px-4 mb-0 rounded message ${
n.senderId !== user.id
? "bg-primary text-light"
: "bg-light text-dark"
}`}
>
{/* {n.message} */}
{n.content}
</p>
<p className="text-muted small m-0 p-0 mb-4">{n.username}</p>
</div>
))
.reverse()}
<div ref={messagesEndRef} />
</div>


+ 11
- 0
Frontend/src/store/chat-slice.js Bestand weergeven

@@ -89,6 +89,17 @@ const chatSlice = createSlice({
setMessages: (state, action) => {
state.messages = action.payload;
},
leaveRoom: (state, action) => {
state.activeRoom = null;

const room = state.rooms.find(
(room) => room.id === action.payload.roomId
);

room.customers = room.customers.filter(
(customer) => customer.customerId !== action.payload.customerId
);
},
},
extraReducers: (builder) => {
// Fetch chat rooms

Laden…
Annuleren
Opslaan