diff --git a/backend/jitsi-rooms.cabal b/backend/jitsi-rooms.cabal index 13ee870..e789efa 100644 --- a/backend/jitsi-rooms.cabal +++ b/backend/jitsi-rooms.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.0. +-- This file has been generated from package.yaml by hpack version 0.35.1. -- -- see: https://github.com/sol/hpack @@ -35,12 +35,10 @@ library Types.Participant Types.RoomData Types.RoomsState - Types.User Types.UsersData Types.WebEnv Types.WebSocketMessages.WebSocketMessages WebServer - WebSocket.AllChat WebSocket.Messages WebSocket.MonadWebSocketSession WebSocket.Server @@ -92,3 +90,4 @@ executable jitsi-rooms-exe , warp , websockets default-language: Haskell2010 + diff --git a/backend/package.yaml b/backend/package.yaml index d35a14c..2444dbe 100644 --- a/backend/package.yaml +++ b/backend/package.yaml @@ -58,4 +58,14 @@ executables: dependencies: - jitsi-rooms +tests: + jitsi-rooms-test: + main: Spec.hs + source-dirs: test + ghc-options: + - -threaded + - -rtsopts + - -with-rtsopts=-N + dependencies: + - jitsi-rooms default-extensions: NoImplicitPrelude,OverloadedStrings,ImportQualifiedPost diff --git a/backend/src/BroadcastUserData.hs b/backend/src/BroadcastUserData.hs index bc00f48..b1a0a54 100644 --- a/backend/src/BroadcastUserData.hs +++ b/backend/src/BroadcastUserData.hs @@ -5,14 +5,15 @@ module BroadcastUserData ) where -import ClassyPrelude -import Data.Aeson (encode) -import Network.WebSockets qualified as WS -import State.ConnectedClientsState (MonadConnectedClientsRead (getConnctedClients)) -import State.RoomDataState (MonadRoomDataStateRead (getRoomDataState)) -import Types.ConnectionState (Client (..), ConnectedClients) -import Types.User (User, clientToUser) -import Types.UsersData (UsersData (..)) +import ClassyPrelude +import Data.Aeson (encode) +import qualified Network.WebSockets as WS +import State.ConnectedClientsState (MonadConnectedClientsRead (getConnctedClients)) +import State.RoomDataState (MonadRoomDataStateRead (getRoomDataState)) +import Types.AppTypes (HasConnectedClientState (..)) +import Types.ConnectionState (Client (..), ConnectedClients) +import Types.RoomsState (HasRoomsState (..)) +import Types.UsersData (UsersData (..)) class (Monad m, MonadConnectedClientsRead m) => MonadBroadcast m where broadCastToClients :: Text -> m () @@ -31,8 +32,8 @@ broadcastUserData = do getUsersWithoutRoom :: ( MonadConnectedClientsRead m ) => - m [User] -getUsersWithoutRoom = map clientToUser . filter (not . joinedRoom) <$> getConnctedClients + m [Text] +getUsersWithoutRoom = map name . filter (not . joinedRoom) <$> getConnctedClients broadCastToClientsGeneric :: ( MonadIO m, diff --git a/backend/src/Types/User.hs b/backend/src/Types/User.hs deleted file mode 100644 index f773587..0000000 --- a/backend/src/Types/User.hs +++ /dev/null @@ -1,21 +0,0 @@ -{-# LANGUAGE DeriveGeneric #-} - -module Types.User (User, clientToUser) where - -import ClassyPrelude -import Data.Aeson (FromJSON, ToJSON) -import Data.UUID (UUID) -import Types.ConnectionState qualified as C - -data User = User - { uuid :: UUID, - name :: Text - } - deriving (Generic, Show, Eq) - -clientToUser :: C.Client -> User -clientToUser C.Client {C.uuid = userUuid, C.name = userName, C.joinedRoom = _, C.conn = _} = User userUuid userName - -instance ToJSON User - -instance FromJSON User diff --git a/backend/src/Types/UsersData.hs b/backend/src/Types/UsersData.hs index fa8ad52..04ffe1a 100644 --- a/backend/src/Types/UsersData.hs +++ b/backend/src/Types/UsersData.hs @@ -5,17 +5,16 @@ module Types.UsersData ) where -import ClassyPrelude -import Data.Aeson (ToJSON) -import Types.RoomData (RoomsData) -import Types.User (User) +import ClassyPrelude +import Data.Aeson (ToJSON) +import Types.RoomData (RoomsData) data UsersData = UsersData - { roomsData :: RoomsData, + { roomsData :: RoomsData, usersWithOutRoom :: UsersWithoutRoom } deriving (Generic, Show) instance ToJSON UsersData -type UsersWithoutRoom = [User] +type UsersWithoutRoom = [Text] diff --git a/backend/src/Types/WebSocketMessages/WebSocketMessages.hs b/backend/src/Types/WebSocketMessages/WebSocketMessages.hs index 30049ba..9269cb2 100644 --- a/backend/src/Types/WebSocketMessages/WebSocketMessages.hs +++ b/backend/src/Types/WebSocketMessages/WebSocketMessages.hs @@ -1,12 +1,9 @@ {-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DuplicateRecordFields #-} module Types.WebSocketMessages.WebSocketMessages ( WebSocketMessage (..), SetClientInfo (..), JoinRoom (..), - AllChatMessageIncoming (..), - AllChatMessageOutgoing (..), ) where @@ -15,13 +12,14 @@ import Data.Aeson ( FromJSON (parseJSON), Options (sumEncoding), SumEncoding (..), - ToJSON, + decode, defaultOptions, genericParseJSON, + withObject, + (.:), ) -import Types.User (User) -data WebSocketMessage = ClientInfoMessage SetClientInfo | JoinRoomMessage JoinRoom | AllChatMessageIncomingMessage AllChatMessageIncoming +data WebSocketMessage = ClientInfoMessage SetClientInfo | JoinRoomMessage JoinRoom deriving (Generic) instance FromJSON WebSocketMessage where @@ -40,18 +38,3 @@ data JoinRoom = JoinRoom deriving (Generic, Show) instance FromJSON JoinRoom - -data AllChatMessageIncoming = AllChatMessageIncoming - { content :: Text - } - deriving (Generic, Show) - -instance FromJSON AllChatMessageIncoming - -data AllChatMessageOutgoing = AllChatMessageOutgoing - { content :: Text, - sender :: User - } - deriving (Generic, Show) - -instance ToJSON AllChatMessageOutgoing diff --git a/backend/src/WebSocket/AllChat.hs b/backend/src/WebSocket/AllChat.hs deleted file mode 100644 index fce86ef..0000000 --- a/backend/src/WebSocket/AllChat.hs +++ /dev/null @@ -1,18 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -module WebSocket.AllChat (broadCastAllChatMessage) where - -import BroadcastUserData (MonadBroadcast (..)) -import ClassyPrelude -import Data.Aeson (encode) -import Types.User (clientToUser) -import Types.WebSocketMessages.WebSocketMessages (AllChatMessageIncoming (..), AllChatMessageOutgoing (AllChatMessageOutgoing)) -import WebSocket.MonadWebSocketSession (MonadWebSocketSession (getClient)) - -broadCastAllChatMessage :: (MonadBroadcast m, MonadWebSocketSession m) => AllChatMessageIncoming -> m () -broadCastAllChatMessage AllChatMessageIncoming {content = message} = do - getClient >>= \case - Nothing -> return () - Just client -> do - let broadCastValue = AllChatMessageOutgoing message (clientToUser client) - broadCastToClients $ (decodeUtf8 . toStrict . encode) broadCastValue diff --git a/backend/src/WebSocket/MonadWebSocketSession.hs b/backend/src/WebSocket/MonadWebSocketSession.hs index 8ef1698..7893af5 100644 --- a/backend/src/WebSocket/MonadWebSocketSession.hs +++ b/backend/src/WebSocket/MonadWebSocketSession.hs @@ -15,7 +15,6 @@ import Data.Aeson import Data.UUID (UUID) import State.ConnectedClientsState ( MonadConnectedClientsModify, - MonadConnectedClientsRead (getConnctedClients), removeWSClient, ) import State.RoomDataState (MonadRoomDataStateRead) @@ -24,10 +23,9 @@ import Types.WebSocketMessages.WebSocketMessages (SetClientInfo (..)) import WebSocket.Messages import WebSocket.WSReaderTApp -class MonadConnectedClientsRead m => MonadWebSocketSession m where +class Monad m => MonadWebSocketSession m where getTypedWSMessage :: FromJSON a => m a getSesssionId :: m UUID - getClient :: m (Maybe Client) instance MonadWebSocketSession (WSApp WSEnv) where getTypedWSMessage = do @@ -38,9 +36,6 @@ instance MonadWebSocketSession (WSApp WSEnv) where sendMessage $ "Bad message: " <> pack err getTypedWSMessage getSesssionId = getClientId <$> ask - getClient = do - id' <- getSesssionId - find ((== id') . uuid) <$> getConnctedClients class (Monad m) => MonadWebSocketSessionInit m where newClient :: SetClientInfo -> m Client diff --git a/backend/src/WebSocket/WSApp.hs b/backend/src/WebSocket/WSApp.hs index aea7ad3..d2eb9f7 100644 --- a/backend/src/WebSocket/WSApp.hs +++ b/backend/src/WebSocket/WSApp.hs @@ -13,7 +13,6 @@ import Types.WebSocketMessages.WebSocketMessages ( SetClientInfo (displayName), WebSocketMessage (..), ) -import WebSocket.AllChat (broadCastAllChatMessage) import WebSocket.MonadWebSocketSession import WebSocket.WSReaderTApp @@ -36,8 +35,7 @@ wsApp = do handleWSAction :: ( MonadWebSocketSession m, - MonadConnectedClientsModify m, - MonadBroadcast m + MonadConnectedClientsModify m ) => m () handleWSAction = do @@ -47,8 +45,6 @@ handleWSAction = do joinRoom ClientInfoMessage clientInfo -> do updateClientName clientInfo - AllChatMessageIncomingMessage incomingMessage -> do - broadCastAllChatMessage incomingMessage joinRoom :: ( MonadConnectedClientsModify m, diff --git a/backend/test/Spec.hs b/backend/test/Spec.hs index e69de29..cd4753f 100644 --- a/backend/test/Spec.hs +++ b/backend/test/Spec.hs @@ -0,0 +1,2 @@ +main :: IO () +main = putStrLn "Test suite not yet implemented" diff --git a/frontend/dev-with-remote-backend.sh b/frontend/dev-with-remote-backend.sh old mode 100755 new mode 100644 diff --git a/frontend/package.json b/frontend/package.json index 5b9bf01..19a0215 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "@jitsi/react-sdk": "^1.3.0", - "jotai": "^2.0.3", "just-curry-it": "^5.3.0", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 92bf62a..5901c6c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,3 @@ -import { Provider } from "jotai"; import { useState } from "react"; import "./App.css"; import Meeting from "./components/meeting/Meeting"; @@ -10,6 +9,7 @@ import { useRoomName } from "./hooks/useRoomName"; function App() { const { userInfo, setUserInfo } = useLocalUser(); + const { roomName, updateRoomName, updateAndSubmitRoomName, submitRoomName } = useRoomName(); const { roomData, sendMessage } = useBackendData(userInfo); const { conferenceData, setConferenceData } = useConferenceData( sendMessage, @@ -23,12 +23,20 @@ function App() { return (
{ + updateAndSubmitRoomName(roomName) + setMeetingStarted(true) + }} />
); diff --git a/frontend/src/background/types/roomData.ts b/frontend/src/background/types/roomData.ts index 55579cd..02ae94d 100644 --- a/frontend/src/background/types/roomData.ts +++ b/frontend/src/background/types/roomData.ts @@ -10,13 +10,7 @@ export interface Participant { email: string; } -export interface User { - uuid: string, - name: string - -} - export interface UsersData { roomsData: RoomData[]; - usersWithOutRoom: User[]; + usersWithOutRoom: string[]; } diff --git a/frontend/src/components/chat/Chat.css b/frontend/src/components/chat/Chat.css deleted file mode 100644 index 2b530f8..0000000 --- a/frontend/src/components/chat/Chat.css +++ /dev/null @@ -1,20 +0,0 @@ -.chat-input{ -max-width: 50%; -} - - -.chat-bubble{ - background-color: #3d3d5c; - overflow-wrap: break-word; - margin-bottom: 7px; - - white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ - white-space: -pre-wrap; /* Opera 4-6 */ - white-space: -o-pre-wrap; /* Opera 7 */ - white-space: pre-wrap; /* css-3 */ - word-wrap: break-word; /* Internet Explorer 5.5+ */ - white-space: -webkit-pre-wrap; /* Newer versions of Chrome/Safari*/ - word-break: break-all; - white-space: normal; -} - diff --git a/frontend/src/components/chat/Chat.tsx b/frontend/src/components/chat/Chat.tsx deleted file mode 100644 index cc8484b..0000000 --- a/frontend/src/components/chat/Chat.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useState } from "react"; -import { FormEventHandler } from "react"; -import useAllChat from "../../hooks/useAllChat"; -import "./Chat.css" - -interface Props { - sendMessage: Function -} - - - -function Chat({ sendMessage }: Props) { - - const [chatInput, setChatInput] = useState("") - - const { chatMesages } = useAllChat() - - const onInput: React.ChangeEventHandler = (event) => { - setChatInput(event.target.value); - event.preventDefault(); - }; - - const onSubmit: FormEventHandler = (event) => { - event.preventDefault(); - sendMessage(JSON.stringify({ content: chatInput })); - setChatInput("") - } - - return ( -
- {chatMesages.map(message => ( -
{message.sender.name}: {message.content}
- )) - - } -
- - -
-
- ); - - -} - - -export default Chat diff --git a/frontend/src/components/meeting/Meeting.tsx b/frontend/src/components/meeting/Meeting.tsx index 23c2f9a..f767894 100644 --- a/frontend/src/components/meeting/Meeting.tsx +++ b/frontend/src/components/meeting/Meeting.tsx @@ -1,6 +1,5 @@ import { useCallback, useState } from "react"; import { ConferenceData } from "../../background/jitsi/eventListeners"; -import useMeetingStarted from "../../hooks/useMeetingStarted"; import { useRoomName } from "../../hooks/useRoomName"; import JitsiEntrypoint from "../jitsi/JitsiEntrypoint"; import { UserInfo } from "../jitsi/types"; @@ -10,12 +9,17 @@ interface Props { conferenceData: ConferenceData | undefined; setConferenceData: (newData: ConferenceData) => void; userInfo: UserInfo; + //@ts-ignore + roomName, updateRoomName, submitRoomName + meetingStarted: Boolean, setMeetingStarted: Function } -function Meeting({ conferenceData, setConferenceData, userInfo }: Props) { +function Meeting({ conferenceData, setConferenceData, userInfo, roomName, updateRoomName, submitRoomName, meetingStarted, setMeetingStarted }: Props) { - const [meetingStarted, setMeetingStarted] = useMeetingStarted() - const { roomName } = useRoomName() + const startMeeting = useCallback(() => { + submitRoomName(); + setMeetingStarted(true); + }, [submitRoomName, setMeetingStarted]); if (meetingStarted) { return ( @@ -31,6 +35,8 @@ function Meeting({ conferenceData, setConferenceData, userInfo }: Props) { return ( ); diff --git a/frontend/src/components/meeting/MeetingNameInput.tsx b/frontend/src/components/meeting/MeetingNameInput.tsx index 38a3531..b8aa7dd 100644 --- a/frontend/src/components/meeting/MeetingNameInput.tsx +++ b/frontend/src/components/meeting/MeetingNameInput.tsx @@ -1,35 +1,26 @@ import { FormEventHandler } from "react"; -import useMeetingStarted from "../../hooks/useMeetingStarted"; -import { useRoomName } from "../../hooks/useRoomName"; import "./MeetingNameInput.css"; function MeetingNameInput(props: { - roomName: string; currentUser: string; + roomName: string; + setName: (name: string) => void; + submit: FormEventHandler; + currentUser: string; }) { - - const { roomName, updateRoomName, updateAndSubmitRoomName, submitRoomName } = useRoomName() - const [_, setMeetingStarted] = useMeetingStarted() - const onInput: React.ChangeEventHandler = (event) => { - updateRoomName(event.target.value); + props.setName(event.target.value); event.preventDefault(); }; - const onSubmit: FormEventHandler = (event) => { - submitRoomName() - setMeetingStarted(true) - event.preventDefault(); - } - console.log("[Rooms] MeetingName input comp"); return (

Greetings {props.currentUser}

-
+ diff --git a/frontend/src/components/sidebar/Sidebar.css b/frontend/src/components/sidebar/Sidebar.css index 435e1f0..964b43e 100644 --- a/frontend/src/components/sidebar/Sidebar.css +++ b/frontend/src/components/sidebar/Sidebar.css @@ -25,11 +25,7 @@ max-width: 220px; } -.sidebar-hidden { - width: 0; -} - -.sidebar-hidden > .sidebar-footer > .sidebar-toggle { +.sidebar-hidden > .sidebar-footer { position: absolute; bottom: 0; } diff --git a/frontend/src/components/sidebar/Sidebar.tsx b/frontend/src/components/sidebar/Sidebar.tsx index 251ad88..17d5414 100644 --- a/frontend/src/components/sidebar/Sidebar.tsx +++ b/frontend/src/components/sidebar/Sidebar.tsx @@ -2,20 +2,15 @@ import SidebarHeader from "./SidebarHeader"; import useSidebarVisibility from "./useSidebarVisibility"; import "./Sidebar.css"; import { UsersData } from "../../background/types/roomData"; -import useMeetingStarted from "../../hooks/useMeetingStarted"; -import { useRoomName } from "../../hooks/useRoomName"; -import Chat from "../chat/Chat"; interface Props { usersData: UsersData; - sendMessage: Function + updateAndSubmitRoomName: Function } function Sidebar(props: Props) { const { sidebarVisibility, toggleSidebarVisibility, sidebarToggleText } = useSidebarVisibility(); - const [_, setMeetingStarted] = useMeetingStarted() - const { updateAndSubmitRoomName: updateAndSubmitRoomName } = useRoomName(); return (
@@ -26,14 +21,13 @@ function Sidebar(props: Props) { <>

{ - updateAndSubmitRoomName(roomData.roomName) - setMeetingStarted(true) + props.updateAndSubmitRoomName(roomData.roomName) }}> {roomData.roomName}

{roomData.participants.map((participant) => ( -
{participant.displayName}
+
{participant.displayName}
))} ); @@ -41,13 +35,12 @@ function Sidebar(props: Props) {

No room

- {props.usersData.usersWithOutRoom.map((user) => ( -
{user.name}
+ {props.usersData.usersWithOutRoom.map((username) => ( +
{username}
))}
- - +
); diff --git a/frontend/src/hooks/useAllChat.tsx b/frontend/src/hooks/useAllChat.tsx deleted file mode 100644 index d75d202..0000000 --- a/frontend/src/hooks/useAllChat.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { atom, useAtom } from "jotai"; -import { atomWithReducer, useReducerAtom } from 'jotai/utils' -import { User } from "../background/types/roomData"; - -interface ChatMessage { - content: string - sender: User - -} - -export const allChatMessagesAtom = atomWithReducer([], (list: ChatMessage[], item: ChatMessage) => list.concat(item)) - - -const useAllChat = () => { - const [chatMessages, addChatMessage] = useAtom(allChatMessagesAtom) - - - return { chatMesages: chatMessages, addChatMessage } - - - -} - - -export default useAllChat - - diff --git a/frontend/src/hooks/useBackendData.ts b/frontend/src/hooks/useBackendData.ts index 3231f4b..4befc80 100644 --- a/frontend/src/hooks/useBackendData.ts +++ b/frontend/src/hooks/useBackendData.ts @@ -1,6 +1,5 @@ import { useEffect } from "react"; import { UserInfo } from "../components/jitsi/types"; -import useAllChat from "./useAllChat"; import useRoomData from "./useRoomData"; import useWebSocketConnection from "./useWebSocketConnection"; @@ -11,15 +10,12 @@ function useBackendData(userInfo: UserInfo) { const { roomData, setRoomData } = useRoomData(); - const { chatMesages, addChatMessage } = useAllChat() - useEffect(() => { onMessage((messageString) => { console.log("[Rooms] message from ws", messageString); const messageObject = JSON.parse(messageString); !!messageObject.roomsData && setRoomData(messageObject); - !!messageObject.content && addChatMessage(messageObject); return disconnect; }); }, [onMessage, setRoomData, disconnect]); diff --git a/frontend/src/hooks/useMeetingStarted.ts b/frontend/src/hooks/useMeetingStarted.ts deleted file mode 100644 index 2187ec7..0000000 --- a/frontend/src/hooks/useMeetingStarted.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { atom, useAtom } from "jotai"; - -const meetingStarted = atom(false) - -const useMeetingStarted = () => useAtom(meetingStarted); - -export default useMeetingStarted diff --git a/frontend/src/hooks/useRoomName.ts b/frontend/src/hooks/useRoomName.ts index dfdc685..1639237 100644 --- a/frontend/src/hooks/useRoomName.ts +++ b/frontend/src/hooks/useRoomName.ts @@ -1,10 +1,7 @@ -import { atom, useAtom } from "jotai"; import { useCallback, useState } from "react"; -const roomNameAtom = atom(getRoomNameFromUrl()) - function useRoomName() { - const [roomName, setRoomName] = useAtom(roomNameAtom) + const [roomName, setRoomName] = useState(() => getRoomNameFromUrl()); const updateRoomName = useCallback( (newName: string) => { diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 2ed612a..791f139 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,4 +1,3 @@ -import { Provider } from 'jotai' import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' @@ -6,8 +5,6 @@ import './index.css' ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( - - - + , ) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index b3b1a74..08008e3 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -543,11 +543,6 @@ is-core-module@^2.9.0: dependencies: has "^1.0.3" -jotai@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/jotai/-/jotai-2.0.3.tgz#3b67cda9f6d5feb70a14db0b842a9873aacda8b5" - integrity sha512-MMjhSPAL3RoeZD9WbObufRT2quThEAEknHHridf2ma8Ml7ZVQmUiHk0ssdbR3F0h3kcwhYqSGJ59OjhPge7RRg== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"