| @@ -80,7 +80,7 @@ namespace Diligent.WebAPI.Business.Services | |||
| if (notification == null) | |||
| { | |||
| return false; | |||
| return true; | |||
| } | |||
| user.Notifications.Remove(notification); | |||
| @@ -1,4 +1,6 @@ | |||
| using Diligent.WebAPI.Host.Mediator.Notifications.Queries; | |||
| using Diligent.WebAPI.Host.DTOs.Notification; | |||
| using Diligent.WebAPI.Host.Mediator.Notifications.Commands; | |||
| using Diligent.WebAPI.Host.Mediator.Notifications.Queries; | |||
| using MediatR; | |||
| using Microsoft.AspNetCore.Mvc; | |||
| @@ -19,5 +21,9 @@ namespace Diligent.WebAPI.Host.Controllers | |||
| [HttpGet("{id}")] | |||
| public async Task<IActionResult> GetNotifications([FromRoute] string id) => | |||
| Ok(await _mediator.Send(new GetNotificationsQuery(id))); | |||
| [HttpPost] | |||
| public async Task<IActionResult> ReadNotifications([FromBody] NotificationDeleteDTO userConnection) => | |||
| Ok(await _mediator.Send(new DeleteNotificationCommand(userConnection))); | |||
| } | |||
| } | |||
| @@ -22,17 +22,6 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| _mediator = mediator; | |||
| } | |||
| //public override Task OnDisconnectedAsync(Exception? exception) | |||
| //{ | |||
| // if (_connections.TryGetValue(Context.ConnectionId, out UserConnection room)) | |||
| // { | |||
| // _connections.Remove(Context.ConnectionId); | |||
| // Clients.Group(room.RoomId).ReceiveMessage(new ChatMessage { User = room.UserId, Message = $"{room.UserId} has left room" }); | |||
| // } | |||
| // return base.OnDisconnectedAsync(exception); | |||
| //} | |||
| [HubMethodName("SendMessageToGroup")] | |||
| [AuthorizationHubFilter(Roles = "Customer,Support")] | |||
| public async Task SendMessageToGroup(ChatMessage message) | |||
| @@ -41,8 +30,7 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| // All other users will receive notification | |||
| if (_connections.TryGetValue(message.ConnId, out UserConnection room)) | |||
| { | |||
| await Clients.Group(room.RoomId).ReceiveMessage(new ChatMessage { User = room.UserId, Message = message.Message }); | |||
| await Clients.OthersInGroup(room.RoomId).ReceiveNotifications(room.UserId, room.RoomId); | |||
| await Clients.Group(room.RoomId).ReceiveMessage(new ChatMessage { UserId = room.UserId, User = room.UserId, Message = message.Message, RoomId = room.RoomId }); | |||
| await _mediator.Send(new AddMessageCommand(room.RoomId, new Message { Content = message.Message, SenderId = message.UserId, Username = room.Username })); | |||
| // Find other users in room and save notification in database | |||
| @@ -53,6 +41,8 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| await _mediator.Send(new AddNotificationCommand(new NotificationSaveDTO { RoomId = room.RoomId, ReceiverId = conn.Value.UserId })); | |||
| } | |||
| } | |||
| await Clients.OthersInGroup(room.RoomId).ReceiveNotifications(room.UserId, room.RoomId); | |||
| } | |||
| } | |||
| @@ -69,7 +59,7 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| { | |||
| await Groups.AddToGroupAsync(Context.ConnectionId, userConnection.RoomId); | |||
| _connections[Context.ConnectionId] = userConnection; | |||
| await Clients.Group(userConnection.RoomId).ReceiveMessage(new ChatMessage { User = userConnection.UserId, Message = $"{userConnection.Username} has joined room", ConnId = Context.ConnectionId }); | |||
| await Clients.Group(userConnection.RoomId).ReceiveMessage(new ChatMessage { UserId = userConnection.UserId, User = userConnection.UserId, RoomId = userConnection.RoomId, Message = $"{userConnection.Username} has joined room", ConnId = Context.ConnectionId }); | |||
| } | |||
| else | |||
| { | |||
| @@ -83,8 +73,9 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| { | |||
| if (_connections.TryGetValue(connection.ConnId, out UserConnection room)) | |||
| { | |||
| // Find user connection in connections dictionary and delete it | |||
| _connections.Remove(Context.ConnectionId); | |||
| await Clients.OthersInGroup(room.RoomId).ReceiveMessage(new ChatMessage { User = room.UserId, Message = $"{room.Username} has left room" }); | |||
| await Clients.OthersInGroup(room.RoomId).ReceiveMessage(new ChatMessage { UserId = room.UserId, User = room.UserId, Message = $"{room.Username} has left room", RoomId = room.RoomId }); | |||
| await _mediator.Send(new RemoveUserFromGroupCommand(room.RoomId, room.UserId)); | |||
| } | |||
| } | |||
| @@ -93,12 +84,9 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| 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 }); | |||
| } | |||
| } | |||
| @@ -10,5 +10,6 @@ | |||
| // Context.ConnectionId generated by SignalR | |||
| public string ConnId { get; set; } | |||
| public string RoomId { get; set; } | |||
| } | |||
| } | |||
| @@ -30,15 +30,7 @@ namespace Diligent.WebAPI.Host.Hubs | |||
| { | |||
| IDs.Remove(s.ConnId); | |||
| var msg = new StatusMessage { Id = s.Id, M = "unsubscription" }; | |||
| //breakpoint here ! | |||
| await Clients.Others.SendAsync("Notify", msg); | |||
| } | |||
| //public override async Task OnDisconnectedAsync(Exception exception, string id) | |||
| //{ | |||
| // IDs.Remove(id); | |||
| // var msg = new StatusMessage { Id = id, M = "unsubscription" }; | |||
| // await Clients.Others.SendAsync("Notify", msg); | |||
| // await base(); | |||
| //} | |||
| } | |||
| } | |||
| @@ -7,22 +7,24 @@ import { FaSignInAlt } from "react-icons/fa"; | |||
| import { GiSandsOfTime } from "react-icons/gi"; | |||
| import { CgEnter } from "react-icons/cg"; | |||
| import Dialog from "./UI/Dialog"; | |||
| import { chatActions, fetchChatRoomsAsync,fetchSupportRoomsAsync } from "../store/chat-slice"; | |||
| import { | |||
| chatActions, | |||
| fetchChatRoomsAsync, | |||
| fetchSupportRoomsAsync, | |||
| } from "../store/chat-slice"; | |||
| import { createChatRoomAsync } from "../store/chat-slice"; | |||
| import { createJoinRequestAsync, requestActions } from "../store/request-slice"; | |||
| import { fetchRequestsAsync } from "../store/request-slice"; | |||
| import { HubConnectionBuilder } from "@microsoft/signalr"; | |||
| import { loadNotifications } from "../store/chat-slice"; | |||
| import { readNotificationsAsync } from "../store/chat-slice"; | |||
| // Ovde ce biti dostupne grupe i razgovori | |||
| const ChatList = () => { | |||
| const [createChat, setCreateChat] = useState(false); | |||
| // naziv chata koji ce biti dodan | |||
| const [chatName, setChatName] = useState(""); | |||
| // grupe kojima je korisnik poslao zahtev za ulazak | |||
| const [requestedRooms, setRequestedRooms] = useState([]); | |||
| // chats from redux | |||
| const { rooms, status, error, notifications } = useSelector( | |||
| const { rooms, status: chatStatus, error, notifications, activeRoom } = useSelector( | |||
| (state) => state.chat | |||
| ); | |||
| const { | |||
| @@ -30,12 +32,12 @@ const ChatList = () => { | |||
| status: requestsStatus, | |||
| requests, | |||
| } = useSelector((state) => state.requests); | |||
| // show modal | |||
| const [showModal, setShowModal] = useState(false); | |||
| const [loadedNotification, setLoadedNotification] = useState(false); | |||
| const { user } = useContext(UserContext); | |||
| // const [connection, setConnection] = useState(); | |||
| // const [messages, setMessages] = useState([]); | |||
| const [myConnection, setMyConnection] = useState(null); | |||
| const [chatMessage, setChatMessage] = useState(null); | |||
| const [notificationRoom, setNotificationRoom] = useState(null); | |||
| const dispatch = useDispatch(); | |||
| useEffect(() => { | |||
| @@ -45,11 +47,13 @@ const ChatList = () => { | |||
| } | |||
| }, [user, dispatch, loadedNotification]); | |||
| // Maybe don't work | |||
| useEffect(() => { | |||
| (user !== null && user.roles.includes('Support')) ? dispatch(fetchSupportRoomsAsync(user.id)): | |||
| (user !== null && dispatch(fetchChatRoomsAsync(user.id))) | |||
| user !== null && user.roles.includes("Support") | |||
| ? dispatch(fetchSupportRoomsAsync(user.id)) | |||
| : user !== null && dispatch(fetchChatRoomsAsync(user.id)); | |||
| dispatch(fetchRequestsAsync()); | |||
| }, [dispatch]); | |||
| }, [dispatch, user]); | |||
| useEffect(() => { | |||
| if (requests && rooms) { | |||
| @@ -77,7 +81,9 @@ const ChatList = () => { | |||
| const joinRoom = async (n) => { | |||
| try { | |||
| const connection = new HubConnectionBuilder() | |||
| .withUrl("http://localhost:5116/chatHub",{accessTokenFactory:() => user.token}) | |||
| .withUrl("http://localhost:5116/chatHub", { | |||
| accessTokenFactory: () => user.token, | |||
| }) | |||
| .withAutomaticReconnect() | |||
| .build(); | |||
| @@ -87,34 +93,25 @@ const ChatList = () => { | |||
| dispatch( | |||
| chatActions.saveContextId({ connId: data.connId, userId: user.id }) | |||
| ); | |||
| setChatMessage(data); | |||
| } | |||
| // Every new received message will be stored in redux | |||
| dispatch( | |||
| chatActions.newMessage({ | |||
| content: data.message, | |||
| createdAtUtc: new Date(), | |||
| deletedAtUtc: null, | |||
| id: null, | |||
| senderId: user.id, | |||
| updatedAtUtc: null, | |||
| username: user.username, | |||
| }) | |||
| ); | |||
| }); | |||
| connection.on("ViewTyping", (data) =>{ | |||
| dispatch(chatActions.addTyping(data)); | |||
| }) | |||
| connection.on("ViewTyping", (data) => { | |||
| dispatch(chatActions.addTyping(data)); | |||
| }); | |||
| connection.on("ReceiveNotifications", (userId, roomId) => { | |||
| if (user.id !== userId) dispatch(chatActions.addNotification(roomId)); | |||
| if (user.id !== userId) { | |||
| dispatch(chatActions.addNotification(roomId)); | |||
| setNotificationRoom(roomId); | |||
| } | |||
| }); | |||
| // When user changed room, array with messages from previous room will be deleted from redux | |||
| dispatch(chatActions.newMessage({ changedRoom: true })); | |||
| connection.onclose((e) => { | |||
| // setConnection(); | |||
| // setMessages([]); | |||
| // On close connection | |||
| }); | |||
| await connection.start(); | |||
| @@ -125,12 +122,57 @@ const ChatList = () => { | |||
| }); | |||
| dispatch(chatActions.setRoom(n)); | |||
| dispatch(chatActions.setConnection(connection)); | |||
| // setConnection({ connection }); | |||
| setMyConnection(connection); | |||
| } catch (e) { | |||
| console.log(e); | |||
| } | |||
| }; | |||
| // Maybe don't work | |||
| useEffect(() => { | |||
| if (myConnection) { | |||
| myConnection.on("ReceiveMessage", (data) => { | |||
| // When user enter room first time after login, generated Context.ConnectionId will be saved in redux | |||
| if (data.connId) { | |||
| dispatch( | |||
| chatActions.saveContextId({ connId: data.connId, userId: user.id }) | |||
| ); | |||
| } | |||
| setChatMessage(data); | |||
| }); | |||
| } | |||
| }, [myConnection, dispatch, user]); | |||
| // Maybe don't work | |||
| useEffect(() => { | |||
| if (chatMessage && activeRoom.id === chatMessage.roomId) { | |||
| dispatch( | |||
| chatActions.newMessage({ | |||
| content: chatMessage.message, | |||
| createdAtUtc: new Date(), | |||
| deletedAtUtc: null, | |||
| id: null, | |||
| senderId: user.id, | |||
| updatedAtUtc: null, | |||
| username: user.username, | |||
| }) | |||
| ); | |||
| } | |||
| }, [chatMessage, dispatch, user, activeRoom]); | |||
| // Maybe don't work | |||
| useEffect(() => { | |||
| if (notificationRoom && activeRoom) { | |||
| if (notificationRoom === activeRoom.id) { | |||
| dispatch(chatActions.readNotifications(activeRoom.id)); | |||
| dispatch( | |||
| readNotificationsAsync({ userId: user.id, roomId: activeRoom.id }) | |||
| ); | |||
| } | |||
| } | |||
| setNotificationRoom(null); | |||
| }, [notificationRoom, activeRoom, dispatch, user]); | |||
| const openModal = (n) => { | |||
| setShowModal(true); | |||
| dispatch(requestActions.chooseRoom(n)); | |||
| @@ -178,24 +220,24 @@ const ChatList = () => { | |||
| } | |||
| } | |||
| } | |||
| return ( | |||
| user !== null && user.roles.includes('Support') ? | |||
| return user !== null && user.roles.includes("Support") ? ( | |||
| <div> | |||
| {rooms.map((room, index) => ( | |||
| <div | |||
| className="border-bottom d-flex" | |||
| key={index} | |||
| onClick={() => joinRoom(room)} | |||
| > | |||
| <button | |||
| className="text-start w-100 py-3 px-3 btn btn-light h-100" | |||
| onClick={showRoomMessagesHandler.bind(this, room)} | |||
| > | |||
| <button | |||
| className="text-start w-100 py-3 px-3 btn btn-light h-100" | |||
| onClick={showRoomMessagesHandler.bind(this, room)} | |||
| > | |||
| {room.name} | |||
| </button> | |||
| {room.name} | |||
| </button> | |||
| </div> | |||
| ))} | |||
| </div>: | |||
| </div> | |||
| ) : ( | |||
| <div> | |||
| {acceptedRequests.length > 0 && ( | |||
| <div> | |||
| @@ -309,8 +351,8 @@ const ChatList = () => { | |||
| )} | |||
| {/* ovo ce biti zamenjeno konkretnim podacima */} | |||
| {(!error && requestedRooms && status === "pendingFetchRooms") || | |||
| status === "pendingAddRoom" ? ( | |||
| {(!error && requestedRooms && chatStatus === "pendingFetchRooms") || | |||
| chatStatus === "pendingAddRoom" ? ( | |||
| <p>Loading</p> | |||
| ) : ( | |||
| getView() | |||
| @@ -3,20 +3,15 @@ import { Button, Form, FormControl, InputGroup } from "react-bootstrap"; | |||
| import { UserContext } from "../contexts/userContext"; | |||
| import { useSelector, useDispatch } from "react-redux"; | |||
| import { chatActions } from "../store/chat-slice"; | |||
| import { BsCircleFill } from 'react-icons/bs' | |||
| import { BsCircleFill } from "react-icons/bs"; | |||
| import TypingBar from "./TypingBar"; | |||
| const ChatWindow = ({ room }) => { | |||
| const messagesEndRef = useRef(null); | |||
| const scrollToBottom = () => { | |||
| messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); | |||
| }; | |||
| 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); | |||
| @@ -26,17 +21,11 @@ const ChatWindow = ({ room }) => { | |||
| dispatch(chatActions.setMessages(room.messages)); | |||
| }, [dispatch, room.messages]); | |||
| 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, | |||
| }); | |||
| @@ -62,23 +51,19 @@ const ChatWindow = ({ room }) => { | |||
| const status = useSelector((s) => s.status); | |||
| const { activeUsers } = status; | |||
| const messageOnChangeHandler = async (e) =>{ | |||
| setMessage(e.target.value) | |||
| 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 | |||
| roomId: activeRoom.id, | |||
| }); | |||
| } | |||
| }; | |||
| return ( | |||
| <div className="px-3 bg-light-transparent rounded h-100 d-flex flex-column"> | |||
| @@ -100,7 +85,6 @@ const ChatWindow = ({ room }) => { | |||
| <div className="messages p-3 border d-flex flex-column-reverse"> | |||
| {/* mapirane poruke */} | |||
| {messages | |||
| .map((n, index) => ( | |||
| <div | |||
| @@ -139,9 +123,12 @@ const ChatWindow = ({ room }) => { | |||
| <div ref={messagesEndRef} /> | |||
| </div> | |||
| <TypingBar id={activeRoom.id}/> | |||
| <TypingBar id={activeRoom.id} /> | |||
| <Form style={{ height: "80px" }} className="d-flex align-items-center"> | |||
| <Form | |||
| style={{ height: "80px" }} | |||
| className="d-flex align-items-center" | |||
| > | |||
| <InputGroup className="mb-3"> | |||
| <FormControl | |||
| placeholder="Enter your messagge..." | |||
| @@ -2,7 +2,6 @@ import React from "react"; | |||
| import { FiCheckCircle, FiXCircle } from "react-icons/fi"; | |||
| import styles from "./CustomerRequest.module.css"; | |||
| import requestService from "../../services/requestService"; | |||
| // import { HubConnectionBuilder } from "@microsoft/signalr"; | |||
| export default function CustomerRequest({ customer, requestHandled }) { | |||
| const onAcceptRequestHandler = () => { | |||
| @@ -13,31 +12,10 @@ export default function CustomerRequest({ customer, requestHandled }) { | |||
| }) | |||
| .then((res) => { | |||
| requestHandled(res); | |||
| // Joining in room | |||
| // joinRoom({ userId: customer.senderId, roomId: customer.roomId }); | |||
| }) | |||
| .catch((e) => console.log(e)); | |||
| }; | |||
| // const joinRoom = async (joiningCredentials) => { | |||
| // try { | |||
| // const connection = new HubConnectionBuilder() | |||
| // .withUrl("http://localhost:5116/chatHub") | |||
| // .withAutomaticReconnect() | |||
| // .build(); | |||
| // connection.on("ReceiveMessage", (data) => { | |||
| // console.log("CUSTOMER REQUEST", data); | |||
| // }); | |||
| // await connection.start(); | |||
| // await connection.invoke("JoinRoom", joiningCredentials); | |||
| // } catch (e) { | |||
| // console.log(e); | |||
| // } | |||
| // }; | |||
| const onRejectRequestHandler = () => { | |||
| requestService | |||
| .rejectCustomerRequest({ | |||
| @@ -2,17 +2,13 @@ import React from "react"; | |||
| import Activity from "./Activity"; | |||
| import ChatList from "./ChatList"; | |||
| import Requests from "./Requests/Requests"; | |||
| import { useContext, useEffect, useState } from "react"; | |||
| import { useContext, useEffect } from "react"; | |||
| import { HubConnectionBuilder } from "@microsoft/signalr"; | |||
| import { UserContext } from "../contexts/userContext"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { statusActions } from "../store/status-slice"; | |||
| const MiddleContainer = ({ showTerm }) => { | |||
| // const [conn, setConn] = useState(''); | |||
| // window.addEventListener('beforeunload', ()=>{ | |||
| // }) | |||
| const { user } = useContext(UserContext); | |||
| const dispatch = useDispatch(); | |||
| @@ -24,11 +20,6 @@ const MiddleContainer = ({ showTerm }) => { | |||
| .build(); | |||
| dispatch(statusActions.setStatusConn(connection)); | |||
| // setConn(connection) | |||
| // connection.onclose(() => { | |||
| // connection.send("Unsubscribe", user.id); | |||
| // }); | |||
| connection.on("Notify", (data) => { | |||
| if (data.m === "subscription") { | |||
| @@ -51,6 +42,7 @@ const MiddleContainer = ({ showTerm }) => { | |||
| connection.start().then(fulfilled, rejected); | |||
| } | |||
| // Maybe don't work | |||
| useEffect(() => { | |||
| connect(); | |||
| }, []); | |||
| @@ -28,7 +28,6 @@ const RegisterForm = () => { | |||
| navigate("/main"); | |||
| }) | |||
| .catch((err) => { | |||
| // console.log(err) | |||
| setError(err.response.data.message.split(".")); | |||
| }); | |||
| }; | |||
| @@ -12,8 +12,6 @@ const SideNavbar = () => { | |||
| const logOutHandler = () => { | |||
| if (window.confirm("Are you sure?")) { | |||
| // ovde ce ici logika za logovanje | |||
| // uklanjanje iz state-a i slicno | |||
| dispatch(chatActions.deleteActiveRoom()); | |||
| logOut(); | |||
| } | |||
| @@ -24,7 +22,6 @@ const SideNavbar = () => { | |||
| <Link | |||
| to={'/main'} | |||
| className="btn btn-white w-100 button-block button-block-flex-column" | |||
| // onClick={() => onClickHandler("notifications")} | |||
| > | |||
| <FiBell className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">feed</h5> | |||
| @@ -33,7 +30,6 @@ const SideNavbar = () => { | |||
| <Link | |||
| to={'/chats'} | |||
| className="btn btn-white button-block mt-4 w-100 button-block-flex-column" | |||
| // onClick={() => onClickHandler("chats")} | |||
| > | |||
| <FiMessageSquare className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">chat</h5> | |||
| @@ -43,7 +39,6 @@ const SideNavbar = () => { | |||
| <Link | |||
| to={'/requests'} | |||
| className="btn btn-white button-block mt-4 w-100 button-block-flex-column" | |||
| // onClick={() => onClickHandler("requests")} | |||
| > | |||
| <FaArrowAltCircleRight className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">Requests</h5> | |||
| @@ -16,7 +16,7 @@ const TypingBar = ({id}) => { | |||
| return () => clearTimeout(timeout) | |||
| }, 2500) | |||
| }, [rerender]); | |||
| }, [rerender, dispatch]); | |||
| return ( | |||
| <div className='text-dark'> | |||
| @@ -1,5 +1,4 @@ | |||
| import React, { useState } from "react"; | |||
| // import { useSelector, useDispatch } from "react-redux"; | |||
| import Accordion from "@mui/material/Accordion"; | |||
| import AccordionSummary from "@mui/material/AccordionSummary"; | |||
| @@ -15,7 +15,6 @@ export const UserProvider = (props) => { | |||
| window.addEventListener("beforeunload", () => { | |||
| // that means the user probably shut the browser down without loging out | |||
| if (localStorage.getItem("activeOnes")) { | |||
| // status.connection.stop(); | |||
| disconnect(); | |||
| } | |||
| }); | |||
| @@ -43,7 +42,6 @@ export const UserProvider = (props) => { | |||
| connId: status.connection.connectionId, | |||
| }) | |||
| .then(() => console.log("bye")); | |||
| // connection.stop(); | |||
| }; | |||
| const rejected = () => { | |||
| @@ -8,6 +8,8 @@ const responseBody = (response) => response.data; | |||
| const methods = { | |||
| loadNotifications: (userId) => | |||
| axios.get(`/Notification/${userId}`).then(responseBody), | |||
| readNotifications: (payload) => | |||
| axios.post("/Notification", payload).then(responseBody), | |||
| }; | |||
| export default methods; | |||
| export default methods; | |||
| @@ -7,15 +7,11 @@ const initialState = { | |||
| rooms: [], | |||
| activeRoom: null, | |||
| error: null, | |||
| // Hub connection | |||
| connection: null, | |||
| // List of room messages | |||
| messages: [], | |||
| // All active user connections to rooms | |||
| connections: [], | |||
| // Notifications | |||
| notifications: [], | |||
| typings: [] | |||
| typings: [], | |||
| }; | |||
| export const fetchChatRoomsAsync = createAsyncThunk( | |||
| @@ -31,14 +27,14 @@ export const fetchChatRoomsAsync = createAsyncThunk( | |||
| export const fetchSupportRoomsAsync = createAsyncThunk( | |||
| "chat/fetchSupportRooms", | |||
| async (payload,thunkAPI) => { | |||
| try{ | |||
| async (payload, thunkAPI) => { | |||
| try { | |||
| return await chatService.getSupportRooms(payload); | |||
| }catch(error){ | |||
| return thunkAPI.rejectWithValue({error}) | |||
| } catch (error) { | |||
| return thunkAPI.rejectWithValue({ error }); | |||
| } | |||
| } | |||
| ) | |||
| ); | |||
| export const createChatRoomAsync = createAsyncThunk( | |||
| "chat/createChatRoomAsync", | |||
| @@ -62,6 +58,17 @@ export const loadNotifications = createAsyncThunk( | |||
| } | |||
| ); | |||
| export const readNotificationsAsync = createAsyncThunk( | |||
| "chat/deleteNotificationsAsync", | |||
| async (payload, thunkAPI) => { | |||
| try { | |||
| return await notificationService.readNotifications(payload); | |||
| } catch (error) { | |||
| return thunkAPI.rejectWithValue({ error }); | |||
| } | |||
| } | |||
| ); | |||
| const chatSlice = createSlice({ | |||
| name: "chat", | |||
| initialState, | |||
| @@ -157,16 +164,22 @@ const chatSlice = createSlice({ | |||
| ); | |||
| }, | |||
| addTyping: (state, action) => { | |||
| if(!state.typings.some(n => n.message === action.payload.message && n.roomId === action.payload.roomId)) | |||
| 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') | |||
| 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); | |||
| 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 | |||
| @@ -233,6 +246,20 @@ const chatSlice = createSlice({ | |||
| state.status = "idle"; | |||
| state.error = action.payload; | |||
| }); | |||
| // Read notifications | |||
| builder.addCase(readNotificationsAsync.pending, (state) => { | |||
| state.status = "pendingReadingNotifications"; | |||
| state.error = null; | |||
| }); | |||
| builder.addCase(readNotificationsAsync.fulfilled, (state) => { | |||
| state.status = "idle"; | |||
| state.error = null; | |||
| }); | |||
| builder.addCase(readNotificationsAsync.rejected, (state, action) => { | |||
| state.status = "idle"; | |||
| state.error = action.payload; | |||
| }); | |||
| }, | |||
| }); | |||
| @@ -4,7 +4,6 @@ const initialState = { | |||
| activeUsers: localStorage.getItem("activeOnes") | |||
| ? JSON.parse(localStorage.getItem("activeOnes")) | |||
| : [], | |||
| //maybe needed later | |||
| connection: '' | |||
| }; | |||