jotai & allchat

This commit is contained in:
qvalentin 2023-04-08 15:58:11 +02:00
parent cf1c7625be
commit 5fbba6cb98
16 changed files with 172 additions and 37 deletions

0
frontend/dev-with-remote-backend.sh Normal file → Executable file
View File

View File

@ -10,6 +10,7 @@
},
"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"

View File

@ -1,3 +1,4 @@
import { Provider } from "jotai";
import { useState } from "react";
import "./App.css";
import Meeting from "./components/meeting/Meeting";
@ -9,7 +10,6 @@ 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,20 +23,12 @@ function App() {
return (
<div className="App">
<Sidebar usersData={roomData}
updateAndSubmitRoomName={(roomName: string) => {
updateAndSubmitRoomName(roomName)
setMeetingStarted(true)
}}
sendMessage={sendMessage}
/>
<Meeting
conferenceData={conferenceData}
setConferenceData={setConferenceData}
userInfo={userInfo}
roomName={roomName}
updateRoomName={updateRoomName}
submitRoomName={submitRoomName}
meetingStarted={meetingStarted}
setMeetingStarted={setMeetingStarted}
/>
</div>
);

View File

@ -10,7 +10,13 @@ export interface Participant {
email: string;
}
export interface User {
uuid: string,
name: string
}
export interface UsersData {
roomsData: RoomData[];
usersWithOutRoom: string[];
usersWithOutRoom: User[];
}

View File

@ -0,0 +1,20 @@
.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;
}

View File

@ -0,0 +1,53 @@
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

View File

@ -1,5 +1,6 @@
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";
@ -9,17 +10,12 @@ 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, roomName, updateRoomName, submitRoomName, meetingStarted, setMeetingStarted }: Props) {
function Meeting({ conferenceData, setConferenceData, userInfo }: Props) {
const startMeeting = useCallback(() => {
submitRoomName();
setMeetingStarted(true);
}, [submitRoomName, setMeetingStarted]);
const [meetingStarted, setMeetingStarted] = useMeetingStarted()
const { roomName } = useRoomName()
if (meetingStarted) {
return (
@ -35,8 +31,6 @@ function Meeting({ conferenceData, setConferenceData, userInfo, roomName, update
return (
<MeetingNameInput
roomName={roomName}
setName={updateRoomName}
submit={startMeeting}
currentUser={userInfo.displayName}
/>
);

View File

@ -1,26 +1,35 @@
import { FormEventHandler } from "react";
import useMeetingStarted from "../../hooks/useMeetingStarted";
import { useRoomName } from "../../hooks/useRoomName";
import "./MeetingNameInput.css";
function MeetingNameInput(props: {
roomName: string;
setName: (name: string) => void;
submit: FormEventHandler;
currentUser: string;
roomName: string; currentUser: string;
}) {
const { roomName, updateRoomName, updateAndSubmitRoomName, submitRoomName } = useRoomName()
const [_, setMeetingStarted] = useMeetingStarted()
const onInput: React.ChangeEventHandler<HTMLInputElement> = (event) => {
props.setName(event.target.value);
updateRoomName(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={props.submit}>
<form onSubmit={onSubmit}>
<input
placeholder="Roomname"
type="text"
value={props.roomName}
value={roomName}
onChange={onInput}
/>
<button type="submit">Enter the adventure</button>

View File

@ -25,7 +25,11 @@
max-width: 220px;
}
.sidebar-hidden > .sidebar-footer {
.sidebar-hidden {
width: 0;
}
.sidebar-hidden > .sidebar-footer > .sidebar-toggle {
position: absolute;
bottom: 0;
}

View File

@ -2,15 +2,20 @@ 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;
updateAndSubmitRoomName: Function
sendMessage: Function
}
function Sidebar(props: Props) {
const { sidebarVisibility, toggleSidebarVisibility, sidebarToggleText } =
useSidebarVisibility();
const [_, setMeetingStarted] = useMeetingStarted()
const { updateAndSubmitRoomName: updateAndSubmitRoomName } = useRoomName();
return (
<div className={`sidebar sidebar-${sidebarVisibility}`}>
@ -21,13 +26,14 @@ function Sidebar(props: Props) {
<>
<h3>
<a href="#" onClick={() => {
props.updateAndSubmitRoomName(roomData.roomName)
updateAndSubmitRoomName(roomData.roomName)
setMeetingStarted(true)
}}>
{roomData.roomName}
</a>
</h3>
{roomData.participants.map((participant) => (
<div> {participant.displayName} </div>
<div key={participant.jid}> {participant.displayName} </div>
))}
</>
);
@ -35,12 +41,13 @@ function Sidebar(props: Props) {
</div>
<div>
<h3> No room</h3>
{props.usersData.usersWithOutRoom.map((username) => (
<div>{username}</div>
{props.usersData.usersWithOutRoom.map((user) => (
<div key={user.uuid}>{user.name}</div>
))}
</div>
<div className="sidebar-footer">
<button onClick={toggleSidebarVisibility}>{sidebarToggleText}</button>
<Chat sendMessage={props.sendMessage} />
<button className="sidebar-toggle" onClick={toggleSidebarVisibility}>{sidebarToggleText}</button>
</div>
</div>
);

View File

@ -0,0 +1,27 @@
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

View File

@ -1,5 +1,6 @@
import { useEffect } from "react";
import { UserInfo } from "../components/jitsi/types";
import useAllChat from "./useAllChat";
import useRoomData from "./useRoomData";
import useWebSocketConnection from "./useWebSocketConnection";
@ -10,12 +11,15 @@ 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]);

View File

@ -0,0 +1,7 @@
import { atom, useAtom } from "jotai";
const meetingStarted = atom(false)
const useMeetingStarted = () => useAtom(meetingStarted);
export default useMeetingStarted

View File

@ -1,7 +1,10 @@
import { atom, useAtom } from "jotai";
import { useCallback, useState } from "react";
const roomNameAtom = atom(getRoomNameFromUrl())
function useRoomName() {
const [roomName, setRoomName] = useState(() => getRoomNameFromUrl());
const [roomName, setRoomName] = useAtom(roomNameAtom)
const updateRoomName = useCallback(
(newName: string) => {

View File

@ -1,3 +1,4 @@
import { Provider } from 'jotai'
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
@ -5,6 +6,8 @@ import './index.css'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<Provider>
<App />
</Provider>
</React.StrictMode>,
)

View File

@ -543,6 +543,11 @@ 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"