sync misc fmt changes
This commit is contained in:
parent
56feab2ea1
commit
4df2355001
11 changed files with 216 additions and 134 deletions
10
src/App.css
10
src/App.css
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
23
src/App.tsx
23
src/App.tsx
|
@ -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."
|
||||||
);
|
);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
.msg .msg-err {
|
.msg .msg-err {
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
5
src/MessageDisplay/messageHandler.tsx
Normal file
5
src/MessageDisplay/messageHandler.tsx
Normal 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 = () => {}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue