| @@ -24,9 +24,13 @@ const ChatList = () => { | |||
| const [createChat, setCreateChat] = useState(false); | |||
| const [chatName, setChatName] = useState(""); | |||
| const [requestedRooms, setRequestedRooms] = useState([]); | |||
| const { rooms, status: chatStatus, error, notifications, activeRoom } = useSelector( | |||
| (state) => state.chat | |||
| ); | |||
| const { | |||
| rooms, | |||
| status: chatStatus, | |||
| error, | |||
| notifications, | |||
| activeRoom, | |||
| } = useSelector((state) => state.chat); | |||
| const { | |||
| chosenRoom, | |||
| status: requestsStatus, | |||
| @@ -93,7 +97,7 @@ const ChatList = () => { | |||
| dispatch( | |||
| chatActions.saveContextId({ connId: data.connId, userId: user.id }) | |||
| ); | |||
| console.log("Join room",data) | |||
| console.log("Join room", data); | |||
| setChatMessage(data); | |||
| } | |||
| }); | |||
| @@ -139,7 +143,7 @@ const ChatList = () => { | |||
| chatActions.saveContextId({ connId: data.connId, userId: user.id }) | |||
| ); | |||
| } | |||
| console.log("Send group message",data) | |||
| console.log("Send group message", data); | |||
| setChatMessage(data); | |||
| }); | |||
| } | |||
| @@ -157,7 +161,7 @@ const ChatList = () => { | |||
| senderId: chatMessage.userId, | |||
| updatedAtUtc: null, | |||
| username: user.username, | |||
| isAccessMessage: chatMessage.isAccessMessage | |||
| isAccessMessage: chatMessage.isAccessMessage, | |||
| }) | |||
| ); | |||
| } | |||
| @@ -227,12 +231,12 @@ const ChatList = () => { | |||
| <div> | |||
| {rooms.map((room, index) => ( | |||
| <div | |||
| className="border-bottom d-flex" | |||
| className="border-bottom roomsBtn d-flex bg-light" | |||
| key={index} | |||
| onClick={() => joinRoom(room)} | |||
| > | |||
| <button | |||
| className="text-start w-100 py-3 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} | |||
| @@ -244,29 +248,22 @@ const ChatList = () => { | |||
| <div> | |||
| {acceptedRequests.length > 0 && ( | |||
| <div> | |||
| <h1>Accepted</h1> | |||
| <h5 className="text-start w-100 ps-3 text-light py-2 pt-3"> | |||
| Accepted Rooms | |||
| </h5> | |||
| {acceptedRequests.map((n, index) => ( | |||
| <div | |||
| className="border-bottom d-flex" | |||
| className="border-bottom roomsBtn d-flex bg-light" | |||
| key={index} | |||
| onClick={() => joinRoom(n)} | |||
| > | |||
| {notificationCounter(n) && ( | |||
| <div className="h-100 d-flex align-items-center justify-content-center"> | |||
| <span | |||
| style={{ | |||
| padding: "0.5rem 1rem", | |||
| backgroundColor: "red", | |||
| borderRadius: "50%", | |||
| color: "white", | |||
| }} | |||
| > | |||
| {notificationCounter(n)} | |||
| </span> | |||
| <div className="notification rounded-circle my-auto ms-3"> | |||
| {notificationCounter(n)} | |||
| </div> | |||
| )} | |||
| <button | |||
| className="text-start w-100 py-3 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} | |||
| @@ -280,10 +277,15 @@ const ChatList = () => { | |||
| )} | |||
| {pendingRequests.length > 0 && ( | |||
| <div> | |||
| <h1>Pending</h1> | |||
| <h5 className="text-start w-100 ps-3 text-light py-2 pt-3"> | |||
| Pending Requests | |||
| </h5> | |||
| {pendingRequests.map((n, index) => ( | |||
| <div className="border-bottom d-flex" key={index}> | |||
| <button className="text-start w-100 py-3 px-3 btn btn-light h-100"> | |||
| <div | |||
| className="border-bottom roomsBtn bg-light d-flex" | |||
| key={index} | |||
| > | |||
| <button className="text-start w-100 py-2 px-3 btn btn-light h-100"> | |||
| {n.name} | |||
| </button> | |||
| <button className="btn btn-light"> | |||
| @@ -295,13 +297,19 @@ const ChatList = () => { | |||
| )} | |||
| {availableRequests.length > 0 && ( | |||
| <div> | |||
| <h1>Available</h1> | |||
| <h5 className="text-start w-100 ps-3 text-light py-2 pt-3"> | |||
| Available Rooms | |||
| </h5> | |||
| {availableRequests.map((n, index) => ( | |||
| <div className="border-bottom d-flex" key={index}> | |||
| <button className="text-start w-100 py-3 px-3 btn btn-light h-100"> | |||
| <div | |||
| onClick={(e) => openModal(n)} | |||
| className="border-bottom roomsBtn bg-light d-flex" | |||
| key={index} | |||
| > | |||
| <button className="text-start w-100 py-2 px-3 btn btn-light h-100"> | |||
| {n.name} | |||
| </button> | |||
| <button className="btn btn-light" onClick={(e) => openModal(n)}> | |||
| <button className="btn btn-light"> | |||
| <FaSignInAlt /> | |||
| </button> | |||
| </div> | |||
| @@ -319,17 +327,17 @@ const ChatList = () => { | |||
| open={showModal} | |||
| acceptHandler={dialogHandler} | |||
| /> | |||
| <div className=" h-100-auto-overflow"> | |||
| <div className="bg-light w-100 mb-3 border-bottom d-flex justify-content-between align-items-center"> | |||
| <h3 className="p-0 m-0 py-3 text-center w-50 fw-light text-muted"> | |||
| Chat | |||
| </h3> | |||
| <div className="p-0 h-100-auto-overflow"> | |||
| <div className="pe-4 bg-transparent w-100 mb-3 p-0 border-bottom border-light d-flex justify-content-between align-items-center"> | |||
| <h4 className="p-0 m-0 py-3 w-100 text-start ps-3 text-light bg-transparent"> | |||
| Chat Rooms | |||
| </h4> | |||
| {user?.roles[0] === "Support" && ( | |||
| <button | |||
| className="btn btn-light" | |||
| className="btn p-0 m-0 btn-light pt-0 mt-0 px-3 pb-2 pt-1" | |||
| onClick={(e) => setCreateChat(true)} | |||
| > | |||
| <FiPlus /> | |||
| <FiPlus className="m-0 p-0" /> | |||
| </button> | |||
| )} | |||
| </div> | |||
| @@ -356,7 +364,9 @@ const ChatList = () => { | |||
| {/* ovo ce biti zamenjeno konkretnim podacima */} | |||
| {(!error && requestedRooms && chatStatus === "pendingFetchRooms") || | |||
| chatStatus === "pendingAddRoom" ? ( | |||
| <p>Loading</p> | |||
| <div className="spinner-border mt-3" role="status"> | |||
| <span className="visually-hidden">Loading...</span> | |||
| </div> | |||
| ) : ( | |||
| getView() | |||
| )} | |||
| @@ -68,24 +68,20 @@ const ChatWindow = ({ room }) => { | |||
| }; | |||
| return ( | |||
| <div className="px-3 bg-light-transparent rounded h-100 d-flex flex-column"> | |||
| <div style={{ height: "80px" }}> | |||
| <h2 className="py-1 m-0">{room.name}</h2> | |||
| <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 style={{ height: "60px" }}> | |||
| <h2 className="p-0 m-0">{room.name}</h2> | |||
| <button | |||
| onClick={leftRoomHandler} | |||
| style={{ | |||
| border: 0, | |||
| backgroundColor: "transparent", | |||
| padding: 0, | |||
| margin: 0, | |||
| textDecoration: "underline", | |||
| }} | |||
| className='btn btn-danger mb-2 leave-btn' | |||
| > | |||
| Leave Room | |||
| </button> | |||
| </div> | |||
| <div className="messages p-3 border d-flex flex-column-reverse"> | |||
| <div className="messages bg-white border "> | |||
| <div className="overlay p-3 px-4 d-flex flex-column-reverse"> | |||
| {/* mapirane poruke */} | |||
| {user && | |||
| messages | |||
| @@ -103,9 +99,11 @@ const ChatWindow = ({ room }) => { | |||
| {console.log("Message", n, "User id", user.id)} | |||
| <p | |||
| className={`p-2 px-4 mb-0 rounded message ${ | |||
| n.senderId !== user.id | |||
| ? "bg-primary text-light" | |||
| : "bg-light text-dark" | |||
| n.isAccessMessage === true | |||
| ? "text-muted small" | |||
| : n.senderId !== user.id | |||
| ? "bg-main-primary text-light chatMsg" | |||
| : "bg-light text-dark chatMsg" | |||
| }`} | |||
| > | |||
| {n.content} | |||
| @@ -120,12 +118,12 @@ const ChatWindow = ({ room }) => { | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {n.isAccessMessage !== true && n.username} | |||
| {n.isAccessMessage !== true && n.senderId !== user?.id && n.username} | |||
| </p> | |||
| </div> | |||
| )) | |||
| .reverse()} | |||
| <div ref={messagesEndRef} /> | |||
| <div ref={messagesEndRef} /></div> | |||
| </div> | |||
| <TypingBar id={activeRoom.id} /> | |||
| @@ -155,6 +153,7 @@ const ChatWindow = ({ room }) => { | |||
| </InputGroup> | |||
| </Form> | |||
| </div> | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -34,6 +34,7 @@ export default function CustomerRequest({ customer, requestHandled }) { | |||
| className={styles.greenIcon} | |||
| onClick={onAcceptRequestHandler} | |||
| /> | |||
| <span className="px-1"></span> | |||
| <FiXCircle | |||
| className={styles.redIcon} | |||
| onClick={onRejectRequestHandler} | |||
| @@ -1,17 +1,28 @@ | |||
| import React from 'react' | |||
| import { useSelector } from 'react-redux'; | |||
| import ChatWindow from './ChatWindow'; | |||
| import React from "react"; | |||
| import { useSelector } from "react-redux"; | |||
| import ChatWindow from "./ChatWindow"; | |||
| const MainContainer = ({showTerm}) => { | |||
| const MainContainer = ({ showTerm }) => { | |||
| const { activeRoom } = useSelector((state) => state.chat); | |||
| return ( | |||
| <div className='h-100-auto-overflow p-3 w-100'> | |||
| {showTerm === 'chats' && activeRoom !== null ? <ChatWindow room={activeRoom} /> : ''} | |||
| {showTerm === 'empty' && ''} | |||
| <div className="h-100-auto-overflow w-100"> | |||
| {showTerm === "chats" || showTerm === "requests" ? ( | |||
| activeRoom !== null ? ( | |||
| <ChatWindow room={activeRoom} /> | |||
| ) : ( | |||
| <div className="w-100 h-100 ps-2 bg-main"> | |||
| <div className="w-100 h-100 text-main bg-light d-flex justify-content-center align-items-center"> | |||
| <h1 className="display-6">{showTerm === "chats" && "Please choose a chat room."}</h1> | |||
| </div> | |||
| </div> | |||
| ) | |||
| ) : ( | |||
| "" | |||
| )} | |||
| {showTerm === "empty" && ""} | |||
| </div> | |||
| ) | |||
| } | |||
| ); | |||
| }; | |||
| export default MainContainer | |||
| export default MainContainer; | |||
| @@ -48,7 +48,7 @@ const MiddleContainer = ({ showTerm }) => { | |||
| }, []); | |||
| return ( | |||
| <div className="w-25 mh-100-vh px-3 bg-light"> | |||
| <div className="w-25 mh-100-vh px-2 pe-0 bg-main"> | |||
| {showTerm === "chats" && <ChatList />} | |||
| {showTerm === "notifications" && <Activity />} | |||
| {showTerm === "requests" && <Requests />} | |||
| @@ -44,10 +44,12 @@ const RegisterForm = () => { | |||
| <p className="text-muted p-0 m-0 py-3 pb-4 text-start"> | |||
| Please enter your valid credentials | |||
| </p> | |||
| <div style={{width:"570px"}} className='text-start alert alert-danger'> | |||
| {error && | |||
| error.map((n) => | |||
| <p key={n} className="text-light bg-dark d-block p-0 m-0">{n.trim()}</p> | |||
| error.map((n) => n.trim().length > 0 && | |||
| " " +n.trim()+"." | |||
| )} | |||
| </div> | |||
| <FormGroup as={Row}> | |||
| <Col md="6" className="pe-1"> | |||
| <FloatingLabel label="First Name" className="mb-3"> | |||
| @@ -21,12 +21,14 @@ export default function Requests() { | |||
| }; | |||
| return status === "pendingFetchRoomsForWhichRequestExist" ? ( | |||
| <p>Loading...</p> | |||
| <div className="spinner-border" role="status"> | |||
| <span className="visually-hidden">Loading...</span> | |||
| </div> | |||
| ) : ( | |||
| <div className={styles.container}> | |||
| <h3 className="p-0 m-0 py-3 text-center w-50 fw-light text-muted"> | |||
| <div className=" h-100-auto-overflow"> | |||
| <h4 className="p-0 m-0 py-3 w-100 text-start ps-3 text-light border-bottom border-light mb-2 bg-transparent"> | |||
| Requests | |||
| </h3> | |||
| </h4> | |||
| <div className={styles.requestContainer}> | |||
| {roomsForWhichRequestExist && | |||
| roomsForWhichRequestExist.length > 0 && | |||
| @@ -19,17 +19,11 @@ const SideNavbar = () => { | |||
| return ( | |||
| <div className="min-vh-100 bg-white border-right px-1 d-flex flex-column pt-5"> | |||
| <Link | |||
| to={'/main'} | |||
| className="btn btn-white w-100 button-block button-block-flex-column" | |||
| > | |||
| <FiBell className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">feed</h5> | |||
| </Link> | |||
| <Link | |||
| to={'/chats'} | |||
| className="btn btn-white button-block mt-4 w-100 button-block-flex-column" | |||
| className="btn btn-white button-block w-100 pb-2 button-block-flex-column" | |||
| > | |||
| <FiMessageSquare className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">chat</h5> | |||
| @@ -38,23 +32,14 @@ const SideNavbar = () => { | |||
| (user && user.roles.includes('Support') === true) && | |||
| <Link | |||
| to={'/requests'} | |||
| className="btn btn-white button-block mt-4 w-100 button-block-flex-column" | |||
| className="btn btn-white button-block w-100 button-block-flex-column" | |||
| > | |||
| <FaArrowAltCircleRight className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">Requests</h5> | |||
| </Link> | |||
| } | |||
| {user && ( | |||
| <Link | |||
| to={'/profile'} | |||
| className="btn btn-white button-block mt-4 w-100 button-block-flex-column" | |||
| > | |||
| <FiUser className="icon-fs" /> | |||
| <h5 className="small text-muted text-center fw-light">profile</h5> | |||
| </Link> | |||
| )} | |||
| <button | |||
| className="btn btn-white button-block mt-4 w-100 button-block-flex-column" | |||
| className="btn btn-white button-block w-100 button-block-flex-column" | |||
| onClick={logOutHandler} | |||
| > | |||
| <FiLogOut className="icon-fs" /> | |||
| @@ -36,7 +36,7 @@ const CustomAccordition = ({ room, onEmptyRoom }) => { | |||
| }; | |||
| return ( | |||
| <Accordion style={{ marginTop: 10 }} expanded={expanded}> | |||
| <Accordion style={{ marginTop: 5 }} expanded={expanded}> | |||
| <AccordionSummary | |||
| expandIcon={<ExpandMoreIcon />} | |||
| aria-controls="panel1a-content" | |||
| @@ -12,7 +12,7 @@ body { | |||
| } | |||
| /* ======================================= root vars */ | |||
| :root { | |||
| --main-bg: linear-gradient(45deg,#00c9ff, #92fe9d); | |||
| --main-bg: linear-gradient(0deg,#00c9ff, #92fe9d); | |||
| --main: #00c9ff; | |||
| --secondary: #92fe9d; | |||
| @@ -23,8 +23,14 @@ body { | |||
| .bg-main{ | |||
| background: var(--main-bg) !important; | |||
| } | |||
| .bg-main-primary{ | |||
| background: var(--main) !important; | |||
| } | |||
| .bg-light-transparent{ | |||
| background: rgba(255,255,255,0.75); | |||
| background-size: cover; | |||
| background-position: center; | |||
| } | |||
| /* ======================================= heights & widths */ | |||
| .h-100-auto-overflow{ | |||
| @@ -46,9 +52,18 @@ body { | |||
| .btn-main{ | |||
| background-color: var(--main) !important; | |||
| } | |||
| .leave-btn{ | |||
| position: absolute; | |||
| right: 3rem; | |||
| top: 1.25rem; | |||
| } | |||
| .button-block{ | |||
| height: 50px; | |||
| width: 50px; | |||
| margin-bottom: 20px !important; | |||
| } | |||
| button.button-block{ | |||
| margin-top: 10px; | |||
| } | |||
| .button-block-flex-column{ | |||
| display: flex; | |||
| @@ -56,6 +71,14 @@ body { | |||
| justify-content: center; | |||
| align-items: center; | |||
| } | |||
| .roomsBtn{ | |||
| transition: 0.35s; | |||
| } | |||
| .roomsBtn:hover{ | |||
| transition: 0.35s; | |||
| padding: 0 20px; | |||
| transform: scale(1.1); | |||
| } | |||
| /* ======================================= flex */ | |||
| .flex-center{ | |||
| display: flex; | |||
| @@ -88,9 +111,13 @@ input[type=submit]{ | |||
| font-size: 1.25rem !important; | |||
| text-transform: uppercase; | |||
| } | |||
| .messages{ | |||
| height: calc(100% - 160px); | |||
| height: calc(100% - 130px); | |||
| background: url('/public/background.jpg'); | |||
| } | |||
| .overlay{ | |||
| height: 575px; | |||
| background-color: rgba(255,255,255,0.9); | |||
| overflow-y: scroll; | |||
| } | |||
| /* ======================================= overrides */ | |||
| @@ -101,3 +128,19 @@ input[type=submit]{ | |||
| .message{ | |||
| max-width: 70%; | |||
| } | |||
| .notification{ | |||
| height: 30px; | |||
| width: 45px; | |||
| display: flex;justify-content: center;align-items: center; | |||
| color: white; | |||
| background-color: crimson; | |||
| border-radius: 50%; | |||
| font-size: 0.8rem; | |||
| } | |||
| .text-main{ | |||
| color:var(--main) !important; | |||
| font-weight: 900; | |||
| } | |||
| .chatMsg{ | |||
| font-size: 1.25rem; | |||
| } | |||
| @@ -9,8 +9,8 @@ const MainScreen = () => { | |||
| return ( | |||
| <Container fluid className='m-0 p-0 min-vh-100 bg-main d-flex justify-content-start'> | |||
| <SideNavbar/> | |||
| <MiddleContainer showTerm={'notifications'}/> | |||
| <MainContainer showTerm={'notifications'}/> | |||
| <MiddleContainer showTerm={'chats'}/> | |||
| <MainContainer showTerm={'chats'}/> | |||
| </Container> | |||
| ) | |||
| } | |||
| @@ -9,7 +9,7 @@ const RequestScreen = () => { | |||
| <Container fluid className='m-0 p-0 min-vh-100 bg-main d-flex justify-content-start'> | |||
| <SideNavbar/> | |||
| <MiddleContainer showTerm={'requests'}/> | |||
| <MainContainer showTerm={'empty'}/> | |||
| <MainContainer showTerm={'requests'}/> | |||
| </Container> | |||
| ) | |||
| } | |||