sync misc fmt changes

This commit is contained in:
Zhongheng Liu 2024-01-24 22:49:50 +02:00
commit 4df2355001
No known key found for this signature in database
11 changed files with 216 additions and 134 deletions

View file

@ -1,6 +1,6 @@
body { body {
background-color: black; background-color: black;
color: #00FF33; color: #00FF33;
margin: 1%; margin: 1%;
min-height: 100vh; min-height: 100vh;
} }

View file

@ -67,29 +67,10 @@ const App = ({
}: { }: {
changeLang: (value: string) => void; changeLang: (value: string) => void;
}): React.ReactElement => { }): React.ReactElement => {
const [username, setUsername] = useState<string>();
const [messages, setMessages] = useState<Message[]>([]); const [messages, setMessages] = useState<Message[]>([]);
const login = useContext(LoginContext); const login = useContext(LoginContext);
const lang = useContext(LangContext); const lang = useContext(LangContext);
const home = strings[lang].homepage; const home = strings[lang].homepage;
// TODO refine setName logic -- move to Login handler
const setNamePrompt = () => {
var newName = prompt(home.userNamePrompt) as string;
while (!validateName(newName)) {
console.log(newName);
prompt("Username invalid! Please enter again.") as string;
}
setNameOnServer(newName).then((value) => {
if (!value.success) {
alert(value.reason);
return true;
} else {
setUsername(newName);
return false;
}
});
};
if (!login) { if (!login) {
return <></>; return <></>;
} else } else
@ -116,8 +97,8 @@ const App = ({
}) })
.then((responseBody: { success: boolean }) => { .then((responseBody: { success: boolean }) => {
if (responseBody.success) { if (responseBody.success) {
setUsername(newUsername as string); // TODO Put new username response true handler method stub
} else { } else {
console.error( console.error(
"Server POST message failed." "Server POST message failed."
); );

View file

@ -1,15 +1,17 @@
.chat-inner-wrapper { .chat-inner-wrapper {
height: 50vh; height: 50vh;
overflow-y:scroll; overflow-y: scroll;
/* overflow-wrap: normal; */ /* overflow-wrap: normal; */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.entry-box { .entry-box {
margin-top: 5px; margin-top: 5px;
} }
.chat { .chat {
/* min-height: 80vh; */ /* min-height: 80vh; */
position: relative; position: relative;
} }

View file

@ -125,7 +125,10 @@ const Chat = ({ user }: { user: string }): React.ReactElement => {
return ( return (
<fieldset className="chat"> <fieldset className="chat">
<legend> <legend>
Logged in as <b>{user}</b> {chatPage.window.title.replaceAll(
"$userName",
user
)}
</legend> </legend>
<div className="chat-inner-wrapper">{messages}</div> <div className="chat-inner-wrapper">{messages}</div>
<span className="entry-box"> <span className="entry-box">

View file

@ -1,64 +1,136 @@
{ {
"variableNames": ["userName", "content"], "variableNames": ["userName", "content"],
"acceptedLangs": ["en_US", "zh_TW", "el_GR"], "acceptedLangs": ["en_US", "zh_TW", "el_GR"],
"en_US": { "en_US": {
"homepage": { "homepage": {
"userNamePrompt": "Your username: ", "userNamePrompt": "Your username: ",
"title": "LAN Chat Server", "title": "LAN Chat Server",
"description": "This web application was built for the purposes of an EPQ project.", "description": "This web application was built for the purposes of an EPQ project.",
"copyrightText": "Copyright 2024 - 2025 Zhongheng Liu @ Byron College", "copyrightText": "Copyright 2024 - 2025 Zhongheng Liu @ Byron College",
"switchLang": "Switch Language", "switchLang": "Switch Language",
"newLangPrompt": "Input your ISO-639_ISO-3166 language-contry code below - for example: \"en_US\": " "newLangPrompt": "Input your ISO-639_ISO-3166 language-contry code below - for example: \"en_US\": "
}, },
"chat": { "chat": {
"sendButtonPrompt": "Send", "window": {
"serverMessage": "Message from $userName: $content", "title": "Logged in as $userName"
"joinMessage": "$userName joined the server" },
} "sendButtonPrompt": "Send",
}, "serverMessage": "Message from $userName: $content",
"zh_TW": { "joinMessage": "$userName joined the server"
"homepage": { },
"userNamePrompt": "您的用戶名: ", "login": {
"title": "本地聊天伺服器", "error": {
"description": "該網絡伺服器應用程式專爲Edexcel Level 3 EPQ而製作", "unameTakenOrInvalid": "Username is taken or invalid!",
"copyrightText": "版權所有 2024 - 2025 Zhongheng Liu @ Byron College", "unameNotExists": "Username does not exist!",
"switchLang": "切換語言", "passwdInvalid": "Password incorrect!"
"newLangPrompt": "在下方輸入您想使用的語言的ISO-639_ISO-3166組合語言代碼 - 例如:\"en_US\"" },
}, "window": {
"chat": { "title": "Login window",
"sendButtonPrompt": "發送", "uname": "Username: ",
"serverMessage": "來自 $userName 的訊息:$content", "login": "Login",
"joinMessage": "$userName 加入了伺服器!" "passwd": "Password: ",
} "register": "Register",
}, "logout": "Logout"
"el_GR": { }
"homepage": { }
"userNamePrompt": "το όνομα χρήστη σας: ", },
"title": "Διακομιστής τοπικού δικτύου συνομιλίας", "zh_TW": {
"description": "Αυτή η διαδικτυακή εφαρμογή δημιουργήθηκε για τους σκοπούς ενός έργου EPQ.", "homepage": {
"copyrightText": "Πνευματικά δικαιώματα 2024 - 2025 Zhongheng Liu @ Byron College", "userNamePrompt": "您的用戶名: ",
"switchLang": "Αλλαγή γλώσσας", "title": "本地聊天伺服器",
"newLangPrompt": "Εισαγάγετε τον κωδικό γλώσσας-χώρας ISO-639 ISO-3166 παρακάτω - για παράδειγμα: \"en_US\":" "description": "該網絡伺服器應用程式專爲Edexcel Level 3 EPQ而製作",
}, "copyrightText": "版權所有 2024 - 2025 Zhongheng Liu @ Byron College",
"chat": { "switchLang": "切換語言",
"sendButtonPrompt": "Στείλετε", "newLangPrompt": "在下方輸入您想使用的語言的ISO-639_ISO-3166組合語言代碼 - 例如:\"en_US\""
"joinMessage": "$userName έγινε μέλος του διακομιστή", },
"serverMessage": "μήνυμα από $userName: $content" "chat": {
} "window": {
}, "title": "當前以 $userName 登入"
"ar_SA": { },
"homepage": { "sendButtonPrompt": "發送",
"userNamePrompt": "اسم المستخدم الخاص بك:", "serverMessage": "來自 $userName 的訊息:$content",
"title": "خادم الدردشة LAN", "joinMessage": "$userName 加入了伺服器!"
"description": "تم إنشاء تطبيق الويب هذا لأغراض مشروع EPQ.", },
"copyrightText": "حقوق الطبع والنشر 2024 - 2025 Zhongheng Liu @ كلية بايرون", "login": {
"switchLang": "تبديل اللغة", "error": {
"newLangPrompt": "أدخل رمز اللغة ISO-639_ISO-3166 أدناه - على سبيل المثال: \"en_US\":" "unameTakenOrInvalid": "用戶名已存在或不合規!",
}, "unameNotExists": "該用戶不存在!",
"chat": { "passwdInvalid": "密碼不正確!"
"sendButtonPrompt": "يرسل", },
"joinMessage": "$userName انضم إلى الخادم", "window": {
"serverMessage": "رسالة من $userName: $content" "title": "登入窗口",
} "uname": "用戶名:",
} "login": "登入",
"passwd": "密碼:",
"register": "註冊",
"logout": "登出"
}
}
},
"el_GR": {
"homepage": {
"userNamePrompt": "το όνομα χρήστη σας: ",
"title": "Διακομιστής τοπικού δικτύου συνομιλίας",
"description": "Αυτή η διαδικτυακή εφαρμογή δημιουργήθηκε για τους σκοπούς ενός έργου EPQ.",
"copyrightText": "Πνευματικά δικαιώματα 2024 - 2025 Zhongheng Liu @ Byron College",
"switchLang": "Αλλαγή γλώσσας",
"newLangPrompt": "Εισαγάγετε τον κωδικό γλώσσας-χώρας ISO-639 ISO-3166 παρακάτω - για παράδειγμα: \"en_US\":"
},
"chat": {
"window": {
"title": "Συνδεδεμένος ως $userName"
},
"sendButtonPrompt": "Στείλετε",
"joinMessage": "$userName έγινε μέλος του διακομιστή",
"serverMessage": "μήνυμα από $userName: $content"
},
"login": {
"error": {
"unameTakenOrInvalid": "Το όνομα χρήστη έχει ληφθεί ή δεν είναι έγκυρο!",
"unameNotExists": "Το όνομα χρήστη δεν υπάρχει!",
"passwdInvalid": "Λάθος κωδικός!"
},
"window": {
"title": "Παράθυρο σύνδεσης",
"uname": "Όνομα χρήστη: ",
"login": "Σύνδεση",
"passwd": "Κωδικός πρόσβασης: ",
"register": "Εγγραφή",
"logout": "Αποσύνδεση"
}
}
},
"ar_SA": {
"homepage": {
"userNamePrompt": "اسم المستخدم الخاص بك:",
"title": "خادم الدردشة LAN",
"description": "تم إنشاء تطبيق الويب هذا لأغراض مشروع EPQ.",
"copyrightText": "حقوق الطبع والنشر 2024 - 2025 Zhongheng Liu @ كلية بايرون",
"switchLang": "تبديل اللغة",
"newLangPrompt": "أدخل رمز اللغة ISO-639_ISO-3166 أدناه - على سبيل المثال: \"en_US\":"
},
"chat": {
"window": {
"title": "Logged in as $userName"
},
"sendButtonPrompt": "يرسل",
"joinMessage": "$userName انضم إلى الخادم",
"serverMessage": "رسالة من $userName: $content"
},
"login": {
"error": {
"unameTakenOrInvalid": "Username is taken or invalid!",
"unameNotExists": "Username does not exist!",
"passwdInvalid": "Password incorrect!"
},
"window": {
"title": "Login window",
"uname": "Username: ",
"login": "Login",
"passwd": "Password: ",
"register": "Register",
"logout": "Logout"
}
}
}
} }

View file

@ -1,8 +1,9 @@
import { useState } from "react"; import { useContext, useState } from "react";
import { contentTypes, domain, endpoints, port } from "../consts"; import { contentTypes, domain, endpoints, port } from "../consts";
import { LoginType } from "../context"; import { LangContext, LoginType } from "../context";
import { User } from "../type/userTypes"; import { User } from "../type/userTypes";
import "./Login.css"; import "./Login.css";
import strings from "../Intl/strings.json";
const encrypt = (rawPasswordString: string) => { const encrypt = (rawPasswordString: string) => {
// TODO Encryption method stub // TODO Encryption method stub
return rawPasswordString; return rawPasswordString;
@ -12,8 +13,10 @@ export const Login = ({
}: { }: {
setLogin: (newLogin: LoginType | undefined) => void; setLogin: (newLogin: LoginType | undefined) => void;
}): React.ReactElement => { }): React.ReactElement => {
const [valid, setValid] = useState<boolean | undefined>(true); const [valid, setValid] = useState<boolean | undefined>(undefined);
const [validText, setValidText] = useState<string | undefined>(); const [validText, setValidText] = useState<string | undefined>();
const lang = useContext(LangContext);
const loginPage = strings[lang].login;
const registrationHandler = () => { const registrationHandler = () => {
const uname = ( const uname = (
document.getElementById("username") as HTMLInputElement document.getElementById("username") as HTMLInputElement
@ -36,7 +39,9 @@ export const Login = ({
// 400 Bad request // 400 Bad request
console.log("Username is taken or invalid!"); console.log("Username is taken or invalid!");
setValid(false); setValid(false);
setValidText("Username is taken or invalid!"); setValidText(
loginPage.error.unameTakenOrInvalid
);
} else if (response.status === 200) { } else if (response.status === 200) {
// 200 OK // 200 OK
const futureDate = new Date(); const futureDate = new Date();
@ -73,7 +78,7 @@ export const Login = ({
"404 not found encountered" "404 not found encountered"
); );
throw new Error( throw new Error(
"Username does not exist" loginPage.error.unameNotExists
); );
} else if (res.status === 200) { } else if (res.status === 200) {
console.log("200 OK"); console.log("200 OK");
@ -88,9 +93,12 @@ export const Login = ({
const validLogin = passwd === user.passwordHash; const validLogin = passwd === user.passwordHash;
if (!validLogin) { if (!validLogin) {
// login invalid // login invalid
throw new Error("Password incorrect!"); throw new Error(
loginPage.error.passwdInvalid
);
} else { } else {
// login valid // login valid
setValid(true);
const validUntilDate: Date = new Date(); const validUntilDate: Date = new Date();
validUntilDate.setHours( validUntilDate.setHours(
validUntilDate.getHours() + 2 validUntilDate.getHours() + 2
@ -111,47 +119,51 @@ export const Login = ({
return ( return (
<div className="login"> <div className="login">
<fieldset> <fieldset>
<legend>Login window</legend> <legend>{loginPage.window.title}</legend>
<p className="uname-error-text"> <p className="uname-error-text">
{valid && valid !== undefined {!valid && valid !== undefined
? "" ? validText
: validText} : ""}
</p> </p>
<label htmlFor="username">Username: </label> <label htmlFor="username">
{loginPage.window.uname}
</label>
<br /> <br />
<input id="username" type="text"></input> <input id="username" type="text"></input>
<br /> <br />
<label htmlFor="passwd">Password: </label> <label htmlFor="passwd">
{loginPage.window.passwd}
</label>
<br /> <br />
<input id="passwd" type="password"></input> <input id="passwd" type="password"></input>
<br /> <br />
<button <button
disabled={!valid} disabled={valid}
type="submit" type="submit"
onClick={() => { onClick={() => {
loginHandler(); loginHandler();
}} }}
> >
Login {loginPage.window.login}
</button>
<button
disabled={!valid}
type="submit"
onClick={() => {
registrationHandler();
}}
>
Register
</button> </button>
<button <button
disabled={valid} disabled={valid}
type="submit" type="submit"
onClick={() => { onClick={() => {
setLogin(undefined); registrationHandler();
setValid(false);
}} }}
> >
Logout {loginPage.window.register}
</button>
<button
disabled={!valid}
type="submit"
onClick={() => {
setLogin(undefined);
setValid(undefined);
}}
>
{loginPage.window.logout}
</button> </button>
</fieldset> </fieldset>
</div> </div>

View file

@ -1,3 +1,3 @@
.msg .msg-err { .msg .msg-err {
overflow-wrap: break-word; overflow-wrap: break-word;
} }

View file

@ -3,6 +3,7 @@ import { Message, MessageType } from "../type/messageTypes";
import { LangContext } from "../context"; import { LangContext } from "../context";
import strings from "../Intl/strings.json"; import strings from "../Intl/strings.json";
import "./MessageDisplay.css"; import "./MessageDisplay.css";
import { queryByRole } from "@testing-library/react";
export const MessageDisplay = ({ export const MessageDisplay = ({
type, type,
fromUserId, fromUserId,

View file

@ -0,0 +1,5 @@
import {Message, MessageType } from "../type/messageTypes"
export const dataMsgHandler = (msg: Message) => {
if (msg.type !== MessageType.DATA) {return <></>}
}
export const chnameMsgHandler = () => {}

View file

@ -1,13 +1,13 @@
body { body {
margin: 0; margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif; sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }

View file

@ -1,7 +1,13 @@
import { URL } from "url";
export type UserAvatar = {
iconUrls: URL[];
};
export type User = { export type User = {
id: number; id: number;
userName: string; userName: string;
dateJoined: number; dateJoined: number;
lastSeen: number; lastSeen: number;
passwordHash: string; passwordHash: string;
// avatar: UserAvatar;
}; };