Compare commits
No commits in common. "5fbba6cb98d59f5c96c1c6d3de0baa34855ae7cf" and "b01b637a2220b8aaef6d658ede34258001f0a7d9" have entirely different histories.
5fbba6cb98
...
b01b637a22
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,11 +7,12 @@ where
|
|||
|
||||
import ClassyPrelude
|
||||
import Data.Aeson (encode)
|
||||
import Network.WebSockets qualified as WS
|
||||
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.User (User, clientToUser)
|
||||
import Types.RoomsState (HasRoomsState (..))
|
||||
import Types.UsersData (UsersData (..))
|
||||
|
||||
class (Monad m, MonadConnectedClientsRead m) => MonadBroadcast m where
|
||||
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -8,7 +8,6 @@ where
|
|||
import ClassyPrelude
|
||||
import Data.Aeson (ToJSON)
|
||||
import Types.RoomData (RoomsData)
|
||||
import Types.User (User)
|
||||
|
||||
data UsersData = UsersData
|
||||
{ roomsData :: RoomsData,
|
||||
|
@ -18,4 +17,4 @@ data UsersData = UsersData
|
|||
|
||||
instance ToJSON UsersData
|
||||
|
||||
type UsersWithoutRoom = [User]
|
||||
type UsersWithoutRoom = [Text]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
main :: IO ()
|
||||
main = putStrLn "Test suite not yet implemented"
|
|
@ -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"
|
||||
|
|
|
@ -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 (
|
||||
<div className="App">
|
||||
<Sidebar usersData={roomData}
|
||||
sendMessage={sendMessage}
|
||||
updateAndSubmitRoomName={(roomName: string) => {
|
||||
updateAndSubmitRoomName(roomName)
|
||||
setMeetingStarted(true)
|
||||
}}
|
||||
/>
|
||||
<Meeting
|
||||
conferenceData={conferenceData}
|
||||
setConferenceData={setConferenceData}
|
||||
userInfo={userInfo}
|
||||
roomName={roomName}
|
||||
updateRoomName={updateRoomName}
|
||||
submitRoomName={submitRoomName}
|
||||
meetingStarted={meetingStarted}
|
||||
setMeetingStarted={setMeetingStarted}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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[];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<HTMLInputElement> = (event) => {
|
||||
setChatInput(event.target.value);
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const onSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
||||
event.preventDefault();
|
||||
sendMessage(JSON.stringify({ content: chatInput }));
|
||||
setChatInput("")
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
{chatMesages.map(message => (
|
||||
<div className="chat-bubble"> <span>{message.sender.name}: </span> {message.content} </div>
|
||||
))
|
||||
|
||||
}
|
||||
<form onSubmit={onSubmit}>
|
||||
<input
|
||||
className="chat-input"
|
||||
placeholder="Say something funny :D"
|
||||
type="text"
|
||||
value={chatInput}
|
||||
onChange={onInput}
|
||||
/>
|
||||
<button type="submit">Send</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default Chat
|
|
@ -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 (
|
||||
<MeetingNameInput
|
||||
roomName={roomName}
|
||||
setName={updateRoomName}
|
||||
submit={startMeeting}
|
||||
currentUser={userInfo.displayName}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -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<HTMLInputElement> = (event) => {
|
||||
updateRoomName(event.target.value);
|
||||
props.setName(event.target.value);
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const onSubmit: FormEventHandler<HTMLFormElement> = (event) => {
|
||||
submitRoomName()
|
||||
setMeetingStarted(true)
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
console.log("[Rooms] MeetingName input comp");
|
||||
return (
|
||||
<div className="meeting-name-input">
|
||||
<h1>Greetings {props.currentUser}</h1>
|
||||
<form onSubmit={onSubmit}>
|
||||
<form onSubmit={props.submit}>
|
||||
<input
|
||||
placeholder="Roomname"
|
||||
type="text"
|
||||
value={roomName}
|
||||
value={props.roomName}
|
||||
onChange={onInput}
|
||||
/>
|
||||
<button type="submit">Enter the adventure</button>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<div className={`sidebar sidebar-${sidebarVisibility}`}>
|
||||
|
@ -26,14 +21,13 @@ function Sidebar(props: Props) {
|
|||
<>
|
||||
<h3>
|
||||
<a href="#" onClick={() => {
|
||||
updateAndSubmitRoomName(roomData.roomName)
|
||||
setMeetingStarted(true)
|
||||
props.updateAndSubmitRoomName(roomData.roomName)
|
||||
}}>
|
||||
{roomData.roomName}
|
||||
</a>
|
||||
</h3>
|
||||
{roomData.participants.map((participant) => (
|
||||
<div key={participant.jid}> {participant.displayName} </div>
|
||||
<div> {participant.displayName} </div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
@ -41,13 +35,12 @@ function Sidebar(props: Props) {
|
|||
</div>
|
||||
<div>
|
||||
<h3> No room</h3>
|
||||
{props.usersData.usersWithOutRoom.map((user) => (
|
||||
<div key={user.uuid}>{user.name}</div>
|
||||
{props.usersData.usersWithOutRoom.map((username) => (
|
||||
<div>{username}</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="sidebar-footer">
|
||||
<Chat sendMessage={props.sendMessage} />
|
||||
<button className="sidebar-toggle" onClick={toggleSidebarVisibility}>{sidebarToggleText}</button>
|
||||
<button onClick={toggleSidebarVisibility}>{sidebarToggleText}</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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]);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import { atom, useAtom } from "jotai";
|
||||
|
||||
const meetingStarted = atom(false)
|
||||
|
||||
const useMeetingStarted = () => useAtom(meetingStarted);
|
||||
|
||||
export default useMeetingStarted
|
|
@ -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) => {
|
||||
|
|
|
@ -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(
|
||||
<React.StrictMode>
|
||||
<Provider>
|
||||
<App />
|
||||
</Provider>
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue