diff --git a/src/lib b/src/lib index cde3d62..a618eda 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit cde3d62b1c0a1c95643037ca03e95bac178118d2 +Subproject commit a618eda73268a675e0c90dace9751ad05d5e0443 diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 6b35a0c..355cce9 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -4,12 +4,16 @@ import useWebSocket, { ReadyState as WebSocketReadyState, } from "react-use-websocket"; import MessageComponent from "src/components/Message"; -import { - isCurrentlyTypingMessage, +import type { + AckMessage, + ConnectedUser, + DesiredNameMessage, TextMessage, TypingMessage, } from "src/lib/ServerMessage"; import { + isConnectedUsersMessage, + isCurrentlyTypingMessage, isIdResponseMessage, isServerMessage, isTextMessage, @@ -24,14 +28,20 @@ export default function Index(): JSX.Element { const [currentlyTyping, setCurrentlyTyping] = useState([]); const [socketUrl, setSocketUrl] = useState("wss.tobot.tk:8085/"); const [authorId, setAuthorId] = useState(""); + const [connectedUsers, setConnectedUsers] = useState([]); + const desiredNameInput = useRef(null); const messageInput = useRef(null); const messageContainer = useRef(null); - const getNickname = useCallback( + const getName = useCallback( (id: string) => { - return id === authorId ? "You" : id; + if (id === authorId) { + return "You"; + } else { + return connectedUsers.find((user) => user.id === id)?.desiredName ?? id; + } }, - [authorId] + [authorId, connectedUsers] ); function onMessage(event: MessageEvent): void { const message = JSON.parse(event.data); @@ -45,9 +55,12 @@ export default function Index(): JSX.Element { setAuthorId(message.authorId); } else if (isTextMessage(message)) { setMessageHistory([...messageHistory, message]); - console.log("scrollheight", messageContainer.current?.scrollHeight); } else if (isCurrentlyTypingMessage(message)) { setCurrentlyTyping(message.currently); + } else if (isConnectedUsersMessage(message)) { + setConnectedUsers(message.connected); + } else { + console.warn("Server sent unhandled message", message); } } @@ -59,9 +72,17 @@ export default function Index(): JSX.Element { websocket.sendJsonMessage({ type: MessageType.ACK, date: Date.now(), - }); + } as AckMessage); }, 1000); keepAliveIntervals.push(keepAliveInterval); + + if (desiredNameInput.current?.value.length) { + websocket.sendJsonMessage({ + type: MessageType.DESIRED_NAME, + date: Date.now(), + desiredName: desiredNameInput.current.value, + } as DesiredNameMessage); + } }, onClose() { clearInterval(keepAliveInterval); @@ -71,7 +92,7 @@ export default function Index(): JSX.Element { }, }); - const handleClickSendMessage = useCallback(() => { + const trySendMessage = useCallback(() => { if (!messageInput.current) { return; } @@ -93,7 +114,7 @@ export default function Index(): JSX.Element { const trySetSocketUrl = useCallback( (url: string) => { try { - console.log(new URL("wss://" + url), url); + console.debug(new URL("wss://" + url), url); setSocketUrl(url); } catch (e) { console.debug("Invalid URL"); @@ -120,7 +141,6 @@ export default function Index(): JSX.Element { setTimeout(() => (shouldResendTyping = true), 1000); } } - console.log(handleInput); const typingIndicator = useMemo(() => { if (currentlyTyping.length === 0) { @@ -136,10 +156,10 @@ export default function Index(): JSX.Element { } return ( <> - {getNickname(currentlyTyping[0]) === currentlyTyping[0] ? ( + {getName(currentlyTyping[0]) === currentlyTyping[0] ? ( currentlyTyping[0] ) : ( - {getNickname(currentlyTyping[0])} + {getName(currentlyTyping[0])} )}{" "} is typing... @@ -148,10 +168,10 @@ export default function Index(): JSX.Element { if (currentlyTyping.length < 4) { const result = currentlyTyping.map((id, idx, arr) => ( <> - {id === getNickname(id) ? ( + {id === getName(id) ? ( id ) : ( - {getNickname(id)} + {getName(id)} )} {idx + 1 === arr.length ? "" : ", "} @@ -161,7 +181,7 @@ export default function Index(): JSX.Element { return <>{result}; } return <>Several people are typing...; - }, [authorId, currentlyTyping, getNickname]); + }, [authorId, currentlyTyping, getName]); return (
@@ -185,29 +205,62 @@ export default function Index(): JSX.Element { placeholder="wss://..." onChange={(e) => trySetSocketUrl(e.target.value)} /> + + -
    - {messageHistory.map((message, idx) => ( -
  1. - -
  2. - ))} -
-
- {typingIndicator} - - - - +
+
+
    + {messageHistory.map((message, idx) => ( +
  1. + +
  2. + ))} +
+
+ {typingIndicator} + + { + if (keyEvent.key === "Enter") { + trySendMessage(); + } + }} + ref={messageInput} + /> + + +
+
+
+

Users

+
    + {connectedUsers.map(({ id }) => ( +
  1. + {getName(id)} +
  2. + ))} +
+
); diff --git a/src/styles.scss b/src/styles.scss index 887d9c8..a6a5f28 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -33,8 +33,8 @@ main { display: flex; flex-direction: column; - height: calc(100vh - 20px); - width: calc(100vw - 20px); + height: calc(100vh - 40px); + width: calc(100vw - 40px); justify-content: space-between; padding: 10px; @@ -42,45 +42,72 @@ main { font-style: italic; } - #messages-container { + #container { + min-height: 100%; + max-height: 100%; display: flex; - flex-direction: column; flex-grow: 1; - overflow-y: scroll; - overflow-anchor: none; - list-style: none; - padding-inline-start: 0; - max-width: 100%; - overflow-wrap: break-word; + #message-area { + display: flex; + flex-direction: column; + flex-grow: 80; + #messages-container { + display: flex; + flex-direction: column; + flex-grow: 1; - .message { - display: block; - text-align: left; - width: calc(100% - 2 * 5px); - padding: 5px; - white-space: pre-line; + overflow-y: scroll; + overflow-anchor: none; + list-style: none; + padding-inline-start: 0; + max-width: 100%; + overflow-wrap: break-word; - &:nth-child(even) { - background-color: #f2f2f2; + .message { + display: block; + text-align: left; + width: calc(100% - 2 * 5px); + padding: 5px; + white-space: pre-line; + + &:nth-child(even) { + background-color: #f2f2f2; + } + + > h2 { + width: 100%; + display: inline-flex; + margin: 0; + font-size: medium; + justify-content: space-between; + } + } } + #message-writing-area { + display: flex; + flex-direction: column; + justify-content: center; - > h2 { - width: 100%; - display: inline-flex; - margin: 0; - font-size: medium; - justify-content: space-between; + #message-input { + width: 80%; + } } } - } - #message-writing-area { - display: flex; - flex-direction: column; - justify-content: center; - #message-input { - width: 80%; + #user-area { + display: flex; + flex-direction: column; + flex-grow: 20; + + ol { + overflow-y: scroll; + max-height: 100%; + + > li:nth-of-type(even) { + background-color: #f2f2f2; + } + } } } }