diff --git a/src/App.tsx b/src/App.tsx index 564757a..70d41b2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,8 @@ -import React, { createContext, useContext, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import Chat from "./Chat/Chat"; import "./App.css"; import { LangType, Message } from "./Chat/messageTypes"; -import { MessageContainer } from "./Chat/MessageContainer"; +import { MessageDisplay } from "./Chat/MessageDisplay"; import strings from "./Intl/strings.json"; import { LangContext, LoginContext, LoginType } from "./context"; import { contentTypes, domain, endpoints, port } from "./consts"; @@ -11,19 +11,31 @@ import { Login } from "./Login/Login"; const Wrapper = (): React.ReactElement => { const [lang, setLang] = useState("en_US"); const [login, setLogin] = useState(undefined); + useEffect(() => { + document.title = login + ? `IRC logged in as ${login.username}` + : "IRC Chat"; + }, [login]); return ( +

{strings[lang].homepage.title}

+

{strings[lang].homepage.description}

+ {/* callbacks for altering the Lang/Login contexts */} { setLogin(value); }} > - { - setLang(value as LangType); - }} - /> + {login ? ( + { + setLang(value as LangType); + }} + /> + ) : ( + <> + )}
); @@ -33,6 +45,7 @@ const setNameOnServer = async (name: string) => { `http://${domain}:${port}${endpoints.user}`, { method: "POST", + mode: "cors", headers: contentTypes.json, body: JSON.stringify({ userName: name, @@ -77,23 +90,20 @@ const App = ({ } }); }; - if (!username) { - var newName = prompt(home.userNamePrompt) as string; - while (!validateName(newName)) { - console.log(newName); + // if (!username) { + // var newName = prompt(home.userNamePrompt) as string; + // while (!validateName(newName)) { + // console.log(newName); - prompt("Username invalid! Please enter again.") as string; - } - setUsername(newName); - } + // prompt("Username invalid! Please enter again.") as string; + // } + // setUsername(newName); + // } if (!login) { return <>; } else return (
-

{home.title}

-
{home.description}
-

Your name is: {username}

{messages.map((message) => { - return ; + return ; })} - {} + {}
); }; diff --git a/src/Chat/Chat.tsx b/src/Chat/Chat.tsx index 89dc036..aa19502 100644 --- a/src/Chat/Chat.tsx +++ b/src/Chat/Chat.tsx @@ -5,7 +5,7 @@ import React, { useRef, useState, } from "react"; -import { MessageContainer } from "./MessageContainer"; +import { MessageDisplay } from "./MessageDisplay"; import { Client } from "@stomp/stompjs"; import { Message, MessageType } from "./messageTypes"; import "./Chat.css"; @@ -29,7 +29,7 @@ const Chat = ({ user }: { user: string }): React.ReactElement => { console.log(messageBody); setMessages((message) => { return message.concat([ - , @@ -99,8 +99,23 @@ const Chat = ({ user }: { user: string }): React.ReactElement => { sendData(); } }); + useEffect(() => { + try { + const elem = document.querySelector(".chat-inner-wrapper"); + if (elem) { + elem.scrollTop = elem.scrollHeight; + } else { + } + } catch (err) { + console.log("error encountered"); + } + return () => {}; + }, [messages]); return ( -
+
+ + Logged in as {user} +
{messages}
@@ -108,7 +123,7 @@ const Chat = ({ user }: { user: string }): React.ReactElement => { {chatPage.sendButtonPrompt} -
+ ); }; export default Chat; diff --git a/src/Chat/MessageContainer.tsx b/src/Chat/MessageDisplay.tsx similarity index 75% rename from src/Chat/MessageContainer.tsx rename to src/Chat/MessageDisplay.tsx index e619e02..d4a6e2b 100644 --- a/src/Chat/MessageContainer.tsx +++ b/src/Chat/MessageDisplay.tsx @@ -2,7 +2,8 @@ import React, { useContext } from "react"; import { Message, MessageType } from "./messageTypes"; import { LangContext } from "../context"; import strings from "../Intl/strings.json"; -export const MessageContainer = ({ +import "./MessageDisplay.css"; +export const MessageDisplay = ({ type, fromUserId, toUserId, @@ -21,19 +22,23 @@ export const MessageContainer = ({ * This caused the return statement to fail, and the message fails to render, despite it being correctly committed to the db. * Funny clown moment 🤡 */ - + const timeString = `${ + dateTime.getHours() > 12 + ? dateTime.getHours() - 12 + : dateTime.getHours() + }:${dateTime.getMinutes()} ${dateTime.getHours() > 12 ? "PM" : "AM"}`; switch (type) { case MessageType.HELLO as MessageType: return ( -

- [{dateTime.toLocaleString()}]{" "} +

+ [{timeString}]{" "} {msgPage.joinMessage.replace("$userName", fromUserId)}

); case MessageType.MESSAGE as MessageType: return ( -

- [{dateTime.toLocaleString()}]{" "} +

+ [{timeString}]{" "} {msgPage.serverMessage .replace("$userName", fromUserId) .replace("$content", content)} @@ -46,9 +51,9 @@ export const MessageContainer = ({ default: console.error("Illegal MessageType reported!"); return ( -

- [{dateTime.toLocaleString()}] **THIS MESSAGE CANNOT BE - CORRECTLY SHOWN BECAUSE THE CLIENT ENCOUNTERED AN ERROR** +

+ [{timeString}] **THIS MESSAGE CANNOT BE CORRECTLY SHOWN + BECAUSE THE CLIENT ENCOUNTERED AN ERROR**

); } diff --git a/src/Login/Login.tsx b/src/Login/Login.tsx index 64ba5dc..6629f4c 100644 --- a/src/Login/Login.tsx +++ b/src/Login/Login.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { contentTypes, domain, endpoints, port } from "../consts"; import { LoginType } from "../context"; import { User } from "../Chat/userTypes"; +import "./Login.css"; const encrypt = (rawPasswordString: string) => { // TODO Encryption method stub return rawPasswordString; @@ -9,9 +10,10 @@ const encrypt = (rawPasswordString: string) => { export const Login = ({ setLogin, }: { - setLogin: (newLogin: LoginType) => void; + setLogin: (newLogin: LoginType | undefined) => void; }): React.ReactElement => { - const [valid, setValid] = useState(true); + const [valid, setValid] = useState(true); + const [validText, setValidText] = useState(); const registrationHandler = () => { const uname = (document.getElementById("username") as HTMLInputElement) .value; @@ -20,6 +22,7 @@ export const Login = ({ ); fetch(`http://${domain}:${port}${endpoints.user}`, { method: "POST", + mode: "cors", headers: contentTypes.json, body: JSON.stringify({ userName: uname, @@ -28,8 +31,12 @@ export const Login = ({ }), }).then((response) => { if (response.status === 400) { + // 400 Bad request console.log("Username is taken or invalid!"); - } else { + setValid(false); + setValidText("Username is taken or invalid!"); + } else if (response.status === 200) { + // 200 OK const futureDate = new Date(); futureDate.setHours(futureDate.getHours() + 2); setLogin({ @@ -37,6 +44,7 @@ export const Login = ({ lastSeen: Date.now(), validUntil: futureDate.getUTCMilliseconds(), }); + document.title = `IRC User ${uname}`; } }); }; @@ -48,16 +56,28 @@ export const Login = ({ (document.getElementById("passwd") as HTMLInputElement).value ); // async invocation of Fetch API - fetch(`http://${domain}:${port}${endpoints.user}?user=${uname}`, { + fetch(`http://${domain}:${port}${endpoints.user}?name=${uname}`, { method: "GET", + mode: "cors", }) - .then((res) => res.json()) + .then((res) => { + if (res.status === 404) { + console.log("404 not found encountered"); + throw new Error("Username does not exist"); + } else if (res.status === 200) { + console.log("200 OK"); + } + return res.json(); + }) .then((userObject) => { + if (!userObject) { + return; + } const user = userObject as User; const validLogin = passwd === user.passwordHash; if (!validLogin) { // login invalid - setValid(false); // triggers page re-render -- should refresh the page + throw new Error("Password incorrect!"); } else { // login valid const validUntilDate: Date = new Date(); @@ -67,22 +87,54 @@ export const Login = ({ lastSeen: user.lastSeen, validUntil: validUntilDate.getUTCMilliseconds(), }); + document.title = `IRC User ${uname}`; } + }) + .catch((reason: Error) => { + setValid(false); + setValidText(reason.message); }); }; return ( -
+
Login window

- {valid ? "Error in your username or password" : ""} + {valid && valid !== undefined ? "" : validText}

+
+
+
- - +
+ + +
);