1
Fork 0

Rudimentary usernames

This commit is contained in:
Tobias Berger 2022-01-21 13:50:41 +00:00 committed by Tobias Berger
parent 07d23d7efa
commit f743c4680c
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
3 changed files with 149 additions and 69 deletions

@ -1 +1 @@
Subproject commit cde3d62b1c0a1c95643037ca03e95bac178118d2
Subproject commit a618eda73268a675e0c90dace9751ad05d5e0443

View file

@ -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<string[]>([]);
const [socketUrl, setSocketUrl] = useState("wss.tobot.tk:8085/");
const [authorId, setAuthorId] = useState("");
const [connectedUsers, setConnectedUsers] = useState<ConnectedUser[]>([]);
const desiredNameInput = useRef<HTMLInputElement>(null);
const messageInput = useRef<HTMLInputElement>(null);
const messageContainer = useRef<HTMLOListElement>(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<string>): 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]
) : (
<span className="nickname">{getNickname(currentlyTyping[0])}</span>
<span className="nickname">{getName(currentlyTyping[0])}</span>
)}{" "}
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
) : (
<span className="nickname">{getNickname(id)}</span>
<span className="nickname">{getName(id)}</span>
)}
{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 (
<main>
@ -185,29 +205,62 @@ export default function Index(): JSX.Element {
placeholder="wss://..."
onChange={(e) => trySetSocketUrl(e.target.value)}
/>
<label htmlFor="desired-name-input">Name:</label>
<input
ref={desiredNameInput}
id="desired-name-input"
type="text"
placeholder="..."
/>
</header>
<ol ref={messageContainer} id="messages-container">
{messageHistory.map((message, idx) => (
<li className="message" key={idx}>
<MessageComponent
message={message}
authorNickname={getNickname(message.author)}
/>
</li>
))}
</ol>
<div id="message-writing-area">
<span id="typing-indicators">{typingIndicator}</span>
<span>
<input
type="text"
placeholder="Type here..."
id="message-input"
onInput={handleInput}
ref={messageInput}
/>
<button onClick={handleClickSendMessage}>Send</button>
</span>
<div id="container">
<section id="message-area">
<ol ref={messageContainer} id="messages-container">
{messageHistory.map((message, idx) => (
<li className="message" key={idx}>
<MessageComponent
message={message}
authorNickname={getName(message.author)}
/>
</li>
))}
</ol>
<div id="message-writing-area">
<span id="typing-indicators">{typingIndicator}</span>
<span>
<input
type="text"
placeholder="Type here..."
id="message-input"
onInput={handleInput}
onKeyPress={(keyEvent) => {
if (keyEvent.key === "Enter") {
trySendMessage();
}
}}
ref={messageInput}
/>
<button onClick={trySendMessage}>Send</button>
</span>
</div>
</section>
<section id="user-area">
<h2>Users</h2>
<ol>
{connectedUsers.map(({ id }) => (
<li
className={
"user" +
(currentlyTyping.includes(id) ? " typing" : "") +
(getName(id) !== id ? " nickname" : "")
}
key={id}
>
{getName(id)}
</li>
))}
</ol>
</section>
</div>
</main>
);

View file

@ -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;
}
}
}
}
}