| } | } | ||||
| }, [user, dispatch, loadedNotification]); | }, [user, dispatch, loadedNotification]); | ||||
| // Maybe don't work | |||||
| useEffect(() => { | useEffect(() => { | ||||
| user !== null && user.roles.includes("Support") | user !== null && user.roles.includes("Support") | ||||
| ? dispatch(fetchSupportRoomsAsync(user.id)) | ? dispatch(fetchSupportRoomsAsync(user.id)) | ||||
| : user !== null && dispatch(fetchChatRoomsAsync(user.id)); | : user !== null && dispatch(fetchChatRoomsAsync(user.id)); | ||||
| dispatch(fetchRequestsAsync()); | dispatch(fetchRequestsAsync()); | ||||
| }, [dispatch]); | |||||
| }, [dispatch,user]); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (requests && rooms) { | if (requests && rooms) { | ||||
| connection.on("ReceiveMessage", (data) => { | connection.on("ReceiveMessage", (data) => { | ||||
| // When user enter room first time after login, generated Context.ConnectionId will be saved in redux | // When user enter room first time after login, generated Context.ConnectionId will be saved in redux | ||||
| if (data.connId) { | if (data.connId) { | ||||
| dispatch( | |||||
| chatActions.saveContextId({ connId: data.connId, userId: user.id }) | |||||
| ); | |||||
| setChatMessage(data); | |||||
| dispatch( | |||||
| chatActions.saveContextId({ connId: data.connId, userId: user.id }) | |||||
| ); | |||||
| if(user.id !== data.userId){ | |||||
| setChatMessage(data); | |||||
| } | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| }; | }; | ||||
| // Maybe don't work | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (myConnection) { | if (myConnection) { | ||||
| myConnection.on("ReceiveMessage", (data) => { | myConnection.on("ReceiveMessage", (data) => { | ||||
| } | } | ||||
| }, [myConnection, dispatch]); | }, [myConnection, dispatch]); | ||||
| // Maybe don't work | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (chatMessage && activeRoom.id === chatMessage.roomId) { | if (chatMessage && activeRoom.id === chatMessage.roomId) { | ||||
| dispatch( | dispatch( | ||||
| } | } | ||||
| }, [chatMessage, dispatch]); | }, [chatMessage, dispatch]); | ||||
| // Maybe don't work | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (notificationRoom && activeRoom) { | if (notificationRoom && activeRoom) { | ||||
| if (notificationRoom === activeRoom.id) { | if (notificationRoom === activeRoom.id) { | ||||
| > | > | ||||
| <button | <button | ||||
| className="text-start w-100 py-2 px-3 btn btn-light h-100" | className="text-start w-100 py-2 px-3 btn btn-light h-100" | ||||
| // onClick={showRoomMessagesHandler.bind(this, room)} | |||||
| > | > | ||||
| {room.name} | {room.name} | ||||
| </button> | </button> | ||||
| )} | )} | ||||
| <button | <button | ||||
| className="text-start w-100 py-2 px-3 btn btn-light h-100" | className="text-start w-100 py-2 px-3 btn btn-light h-100" | ||||
| // onClick={showRoomMessagesHandler.bind(this, n)} | |||||
| > | > | ||||
| {n.name} | {n.name} | ||||
| </button> | </button> |
| import { chatActions } from "../store/chat-slice"; | import { chatActions } from "../store/chat-slice"; | ||||
| import { BsCircleFill } from "react-icons/bs"; | import { BsCircleFill } from "react-icons/bs"; | ||||
| import TypingBar from "./TypingBar"; | import TypingBar from "./TypingBar"; | ||||
| import { fetchChatRoomsAsync } from "../store/chat-slice"; | |||||
| import { fetchChatRoomsAsync,fetchSupportRoomsAsync } from "../store/chat-slice"; | |||||
| import { fetchRequestsAsync } from "../store/request-slice"; | |||||
| import { getDate, getMonth } from "../Helpers"; | import { getDate, getMonth } from "../Helpers"; | ||||
| const ChatWindow = ({ room }) => { | const ChatWindow = ({ room }) => { | ||||
| }; | }; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| // dispatch(chatActions.setMessages(room.messages)); | |||||
| if (user) { | |||||
| dispatch(fetchChatRoomsAsync(user.id)); | |||||
| } | |||||
| user !== null && user.roles.includes("Support") | |||||
| ? dispatch(fetchSupportRoomsAsync(user.id)) | |||||
| : user !== null && dispatch(fetchChatRoomsAsync(user.id)); | |||||
| dispatch(fetchRequestsAsync()); | |||||
| }, [dispatch, room, user]); | }, [dispatch, room, user]); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| return minutes < 10 ? "0" + minutes : minutes; | return minutes < 10 ? "0" + minutes : minutes; | ||||
| }; | }; | ||||
| const calculatesHours = (createdAt) => { | |||||
| const date = getDate(createdAt); | |||||
| const hours = date.getHours(); | |||||
| return hours < 10 ? "0" + hours : hours; | |||||
| } | |||||
| return ( | return ( | ||||
| <div className="p-2 position-relative bg-main rounded h-100 d-flex flex-column"> | <div className="p-2 position-relative bg-main rounded h-100 d-flex flex-column"> | ||||
| <div className="p-2 px-3 pt-3 position-relative bg-light rounded h-100 d-flex flex-column"> | <div className="p-2 px-3 pt-3 position-relative bg-light rounded h-100 d-flex flex-column"> | ||||
| > | > | ||||
| <div style={{ display: "flex", flexDirection: "column" }}> | <div style={{ display: "flex", flexDirection: "column" }}> | ||||
| {n.content} | {n.content} | ||||
| {n.senderId !== undefined ? ( | {n.senderId !== undefined ? ( | ||||
| <div style={{ fontSize: 12, alignSelf: "flex-end" }}> | <div style={{ fontSize: 12, alignSelf: "flex-end" }}> | ||||
| {getDate(n.createdAtUtc).getHours().toString()}: | |||||
| {calculatesHours(n.createdAtUtc)}: | |||||
| {calculateMinutes(n.createdAtUtc)} | {calculateMinutes(n.createdAtUtc)} | ||||
| </div> | </div> | ||||
| ) : ( | ) : ( | ||||
| variant="outline-secondary" | variant="outline-secondary" | ||||
| id="button-addon2" | id="button-addon2" | ||||
| type="submit" | type="submit" | ||||
| disabled={message.length === 0} | |||||
| > | > | ||||
| Send | Send | ||||
| </Button> | </Button> |
| > | > | ||||
| <Form.Control value={password} onChange={e => setPassword(e.target.value)} type="password" className={`bg-dark responsive-input text-light ${err.password ? 'border-danger' : ''}`} placeholder="Enter your password..." /> | <Form.Control value={password} onChange={e => setPassword(e.target.value)} type="password" className={`bg-dark responsive-input text-light ${err.password ? 'border-danger' : ''}`} placeholder="Enter your password..." /> | ||||
| </FloatingLabel> | </FloatingLabel> | ||||
| <Link className='text-light my-3' to='/'>Forgott password? Click here</Link><br></br> | |||||
| <input type='submit' className='btn py-2 mt-4 w-100 btn-main text-dark' value={'log in'} /> | <input type='submit' className='btn py-2 mt-4 w-100 btn-main text-dark' value={'log in'} /> | ||||
| <p className='text-light m-0 p-0 py-3'>or</p> | <p className='text-light m-0 p-0 py-3'>or</p> | ||||
| <p className='text-light m-0 p-0'>No account yet?</p> | <p className='text-light m-0 p-0'>No account yet?</p> |
| connection.start().then(fulfilled, rejected); | connection.start().then(fulfilled, rejected); | ||||
| } | } | ||||
| // Maybe don't work | |||||
| useEffect(() => { | useEffect(() => { | ||||
| connect(); | connect(); | ||||
| }, []); | }, []); |
| <p className="text-muted p-0 m-0 py-3 pb-4 text-start"> | <p className="text-muted p-0 m-0 py-3 pb-4 text-start"> | ||||
| Please enter your valid credentials | Please enter your valid credentials | ||||
| </p> | </p> | ||||
| <div style={{width:"570px"}} className='text-start alert alert-danger'> | |||||
| {error && | {error && | ||||
| error.map((n) => n.trim().length > 0 && | error.map((n) => n.trim().length > 0 && | ||||
| " " +n.trim()+"." | |||||
| <div style={{width:"570px"}} className='text-start alert alert-danger py-1'> | |||||
| {" " +n.trim()+"."} | |||||
| </div> | |||||
| )} | )} | ||||
| </div> | |||||
| <FormGroup as={Row}> | <FormGroup as={Row}> | ||||
| <Col md="6" className="pe-1"> | <Col md="6" className="pe-1"> | ||||
| <FloatingLabel label="First Name" className="mb-3"> | <FloatingLabel label="First Name" className="mb-3"> |
| import React, { useContext } from "react"; | import React, { useContext } from "react"; | ||||
| import { FiBell, FiUser, FiMessageSquare, FiLogOut } from "react-icons/fi"; | |||||
| import { FiMessageSquare, FiLogOut } from "react-icons/fi"; | |||||
| import { UserContext } from "../contexts/userContext"; | import { UserContext } from "../contexts/userContext"; | ||||
| import { useDispatch } from "react-redux"; | import { useDispatch } from "react-redux"; | ||||
| import { chatActions } from "../store/chat-slice"; | import { chatActions } from "../store/chat-slice"; |
| <Typography className="text-light" id="transition-modal-title" variant="h5" component="h2"> | <Typography className="text-light" id="transition-modal-title" variant="h5" component="h2"> | ||||
| Are you sure you want to send a request? | Are you sure you want to send a request? | ||||
| </Typography> | </Typography> | ||||
| <Typography className="text-light" id="transition-modal-description" sx={{ mt: 2 }}> | |||||
| Duis mollis, est non commodo luctus, nisi erat porttitor ligula. | |||||
| <Typography className="text-light py-3" id="transition-modal-description" sx={{ mt: 2 }}> | |||||
| </Typography> | </Typography> | ||||
| <div style={{marginTop: '2rem', display: 'flex', justifyContent: 'right'}}> | <div style={{marginTop: '2rem', display: 'flex', justifyContent: 'right'}}> | ||||
| <button className="btn-main text-light w-50 btn" style={{marginLeft: '0.5rem'}} onClick={handleClose}>Close</button> | <button className="btn-main text-light w-50 btn" style={{marginLeft: '0.5rem'}} onClick={handleClose}>Close</button> |
| background: url('/public/background.jpg'); | background: url('/public/background.jpg'); | ||||
| } | } | ||||
| .overlay{ | .overlay{ | ||||
| height: 575px; | |||||
| height: 100%; | |||||
| background-color: rgba(255,255,255,0.9); | background-color: rgba(255,255,255,0.9); | ||||
| overflow-y: scroll; | overflow-y: scroll; | ||||
| } | } |
| import React from 'react' | |||||
| import React, { useEffect } from 'react' | |||||
| import { Container } from 'react-bootstrap' | import { Container } from 'react-bootstrap' | ||||
| import MainContainer from '../components/MainContainer' | import MainContainer from '../components/MainContainer' | ||||
| import MiddleContainer from '../components/MiddleContainer' | import MiddleContainer from '../components/MiddleContainer' |
| }, | }, | ||||
| // New message sent from user | // New message sent from user | ||||
| newMessage: (state, action) => { | newMessage: (state, action) => { | ||||
| // if (action.payload.changedRoom) { | |||||
| // state.messages = []; | |||||
| // } else { | |||||
| // state.messages = [...state.messages, action.payload]; | |||||
| // } | |||||
| console.log(action.payload); | console.log(action.payload); | ||||
| const room = state.rooms.find((r) => r.id === action.payload.room); | const room = state.rooms.find((r) => r.id === action.payload.room); | ||||
| room.messages.push(action.payload.message); | room.messages.push(action.payload.message); | ||||
| } | } | ||||
| }, | }, | ||||
| setTrackedRoom: (state, action) => { | setTrackedRoom: (state, action) => { | ||||
| console.log(action.payload) | |||||
| state.trackedRoom = state.rooms.find((r) => r.id === action.payload); | state.trackedRoom = state.rooms.find((r) => r.id === action.payload); | ||||
| }, | }, | ||||
| }, | }, | ||||
| }); | }); | ||||
| builder.addCase(fetchSupportRoomsAsync.fulfilled, (state, action) => { | builder.addCase(fetchSupportRoomsAsync.fulfilled, (state, action) => { | ||||
| state.rooms = action.payload; | state.rooms = action.payload; | ||||
| state.status = "idle"; | |||||
| state.status = "fetchRoomsFulfilled idle"; | |||||
| state.error = null; | state.error = null; | ||||
| }); | }); | ||||
| builder.addCase(fetchSupportRoomsAsync.rejected, (state, action) => { | builder.addCase(fetchSupportRoomsAsync.rejected, (state, action) => { |