diff options
-rw-r--r-- | src/App.css | 10 | ||||
-rw-r--r-- | src/App.tsx | 23 | ||||
-rw-r--r-- | src/Chat/Chat.css | 20 | ||||
-rw-r--r-- | src/Chat/Chat.tsx | 5 | ||||
-rw-r--r-- | src/Intl/strings.json | 196 | ||||
-rw-r--r-- | src/Login/Login.tsx | 50 | ||||
-rw-r--r-- | src/MessageDisplay/MessageDisplay.css | 4 | ||||
-rw-r--r-- | src/MessageDisplay/MessageDisplay.tsx | 1 | ||||
-rw-r--r-- | src/MessageDisplay/messageHandler.tsx | 5 | ||||
-rw-r--r-- | src/index.css | 16 | ||||
-rw-r--r-- | src/type/userTypes.ts | 6 |
11 files changed, 209 insertions, 127 deletions
diff --git a/src/App.css b/src/App.css index 05482ad..e4849cc 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,6 @@ body { - background-color: black; - color: #00FF33; - margin: 1%; - min-height: 100vh; -}
\ No newline at end of file + background-color: black; + color: #00FF33; + margin: 1%; + min-height: 100vh; +} diff --git a/src/App.tsx b/src/App.tsx index e5d3328..7d908e3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -67,29 +67,10 @@ const App = ({ }: { changeLang: (value: string) => void; }): React.ReactElement => { - const [username, setUsername] = useState<string>(); const [messages, setMessages] = useState<Message[]>([]); const login = useContext(LoginContext); const lang = useContext(LangContext); 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) { return <></>; } else @@ -116,8 +97,8 @@ const App = ({ }) .then((responseBody: { success: boolean }) => { if (responseBody.success) { - setUsername(newUsername as string); - } else { + // TODO Put new username response true handler method stub + } else { console.error( "Server POST message failed." ); diff --git a/src/Chat/Chat.css b/src/Chat/Chat.css index d92e700..76b19f6 100644 --- a/src/Chat/Chat.css +++ b/src/Chat/Chat.css @@ -1,15 +1,17 @@ .chat-inner-wrapper { - height: 50vh; - overflow-y:scroll; - /* overflow-wrap: normal; */ - display: flex; - flex-direction: column; + height: 50vh; + overflow-y: scroll; + /* overflow-wrap: normal; */ + display: flex; + flex-direction: column; } + .entry-box { - margin-top: 5px; + margin-top: 5px; } + .chat { - /* min-height: 80vh; */ - position: relative; -}
\ No newline at end of file + /* min-height: 80vh; */ + position: relative; +} diff --git a/src/Chat/Chat.tsx b/src/Chat/Chat.tsx index 7aff06f..1aa884a 100644 --- a/src/Chat/Chat.tsx +++ b/src/Chat/Chat.tsx @@ -125,7 +125,10 @@ const Chat = ({ user }: { user: string }): React.ReactElement => { return ( <fieldset className="chat"> <legend> - Logged in as <b>{user}</b> + {chatPage.window.title.replaceAll( + "$userName", + user + )} </legend> <div className="chat-inner-wrapper">{messages}</div> <span className="entry-box"> diff --git a/src/Intl/strings.json b/src/Intl/strings.json index 7dd6bc1..ceff215 100644 --- a/src/Intl/strings.json +++ b/src/Intl/strings.json @@ -1,64 +1,136 @@ { - "variableNames": ["userName", "content"], - "acceptedLangs": ["en_US", "zh_TW", "el_GR"], - "en_US": { - "homepage": { - "userNamePrompt": "Your username: ", - "title": "LAN Chat Server", - "description": "This web application was built for the purposes of an EPQ project.", - "copyrightText": "Copyright 2024 - 2025 Zhongheng Liu @ Byron College", - "switchLang": "Switch Language", - "newLangPrompt": "Input your ISO-639_ISO-3166 language-contry code below - for example: \"en_US\": " - }, - "chat": { - "sendButtonPrompt": "Send", - "serverMessage": "Message from $userName: $content", - "joinMessage": "$userName joined the server" - } - }, - "zh_TW": { - "homepage": { - "userNamePrompt": "您的用戶名: ", - "title": "本地聊天伺服器", - "description": "該網絡伺服器應用程式專爲Edexcel Level 3 EPQ而製作", - "copyrightText": "版權所有 2024 - 2025 Zhongheng Liu @ Byron College", - "switchLang": "切換語言", - "newLangPrompt": "在下方輸入您想使用的語言的ISO-639_ISO-3166組合語言代碼 - 例如:\"en_US\":" - }, - "chat": { - "sendButtonPrompt": "發送", - "serverMessage": "來自 $userName 的訊息:$content", - "joinMessage": "$userName 加入了伺服器!" - } - }, - "el_GR": { - "homepage": { - "userNamePrompt": "το όνομα χρήστη σας: ", - "title": "Διακομιστής τοπικού δικτύου συνομιλίας", - "description": "Αυτή η διαδικτυακή εφαρμογή δημιουργήθηκε για τους σκοπούς ενός έργου EPQ.", - "copyrightText": "Πνευματικά δικαιώματα 2024 - 2025 Zhongheng Liu @ Byron College", - "switchLang": "Αλλαγή γλώσσας", - "newLangPrompt": "Εισαγάγετε τον κωδικό γλώσσας-χώρας ISO-639 ISO-3166 παρακάτω - για παράδειγμα: \"en_US\":" - }, - "chat": { - "sendButtonPrompt": "Στείλετε", - "joinMessage": "$userName έγινε μέλος του διακομιστή", - "serverMessage": "μήνυμα από $userName: $content" - } - }, - "ar_SA": { - "homepage": { - "userNamePrompt": "اسم المستخدم الخاص بك:", - "title": "خادم الدردشة LAN", - "description": "تم إنشاء تطبيق الويب هذا لأغراض مشروع EPQ.", - "copyrightText": "حقوق الطبع والنشر 2024 - 2025 Zhongheng Liu @ كلية بايرون", - "switchLang": "تبديل اللغة", - "newLangPrompt": "أدخل رمز اللغة ISO-639_ISO-3166 أدناه - على سبيل المثال: \"en_US\":" - }, - "chat": { - "sendButtonPrompt": "يرسل", - "joinMessage": "$userName انضم إلى الخادم", - "serverMessage": "رسالة من $userName: $content" - } - } + "variableNames": ["userName", "content"], + "acceptedLangs": ["en_US", "zh_TW", "el_GR"], + "en_US": { + "homepage": { + "userNamePrompt": "Your username: ", + "title": "LAN Chat Server", + "description": "This web application was built for the purposes of an EPQ project.", + "copyrightText": "Copyright 2024 - 2025 Zhongheng Liu @ Byron College", + "switchLang": "Switch Language", + "newLangPrompt": "Input your ISO-639_ISO-3166 language-contry code below - for example: \"en_US\": " + }, + "chat": { + "window": { + "title": "Logged in as $userName" + }, + "sendButtonPrompt": "Send", + "serverMessage": "Message from $userName: $content", + "joinMessage": "$userName joined the server" + }, + "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" + } + } + }, + "zh_TW": { + "homepage": { + "userNamePrompt": "您的用戶名: ", + "title": "本地聊天伺服器", + "description": "該網絡伺服器應用程式專爲Edexcel Level 3 EPQ而製作", + "copyrightText": "版權所有 2024 - 2025 Zhongheng Liu @ Byron College", + "switchLang": "切換語言", + "newLangPrompt": "在下方輸入您想使用的語言的ISO-639_ISO-3166組合語言代碼 - 例如:\"en_US\":" + }, + "chat": { + "window": { + "title": "當前以 $userName 登入" + }, + "sendButtonPrompt": "發送", + "serverMessage": "來自 $userName 的訊息:$content", + "joinMessage": "$userName 加入了伺服器!" + }, + "login": { + "error": { + "unameTakenOrInvalid": "用戶名已存在或不合規!", + "unameNotExists": "該用戶不存在!", + "passwdInvalid": "密碼不正確!" + }, + "window": { + "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" + } + } + } } diff --git a/src/Login/Login.tsx b/src/Login/Login.tsx index 7f5ff79..6518eff 100644 --- a/src/Login/Login.tsx +++ b/src/Login/Login.tsx @@ -1,8 +1,9 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import { contentTypes, domain, endpoints, port } from "../consts"; -import { LoginType } from "../context"; +import { LangContext, LoginType } from "../context"; import { User } from "../type/userTypes"; import "./Login.css"; +import strings from "../Intl/strings.json"; const encrypt = (rawPasswordString: string) => { // TODO Encryption method stub return rawPasswordString; @@ -12,8 +13,10 @@ export const Login = ({ }: { setLogin: (newLogin: LoginType | undefined) => void; }): React.ReactElement => { - const [valid, setValid] = useState<boolean | undefined>(true); + const [valid, setValid] = useState<boolean | undefined>(undefined); const [validText, setValidText] = useState<string | undefined>(); + const lang = useContext(LangContext); + const loginPage = strings[lang].login; const registrationHandler = () => { const uname = ( document.getElementById("username") as HTMLInputElement @@ -36,7 +39,9 @@ export const Login = ({ // 400 Bad request console.log("Username is taken or invalid!"); setValid(false); - setValidText("Username is taken or invalid!"); + setValidText( + loginPage.error.unameTakenOrInvalid + ); } else if (response.status === 200) { // 200 OK const futureDate = new Date(); @@ -73,7 +78,7 @@ export const Login = ({ "404 not found encountered" ); throw new Error( - "Username does not exist" + loginPage.error.unameNotExists ); } else if (res.status === 200) { console.log("200 OK"); @@ -88,9 +93,12 @@ export const Login = ({ const validLogin = passwd === user.passwordHash; if (!validLogin) { // login invalid - throw new Error("Password incorrect!"); + throw new Error( + loginPage.error.passwdInvalid + ); } else { // login valid + setValid(true); const validUntilDate: Date = new Date(); validUntilDate.setHours( validUntilDate.getHours() + 2 @@ -111,47 +119,51 @@ export const Login = ({ return ( <div className="login"> <fieldset> - <legend>Login window</legend> + <legend>{loginPage.window.title}</legend> <p className="uname-error-text"> - {valid && valid !== undefined - ? "" - : validText} + {!valid && valid !== undefined + ? validText + : ""} </p> - <label htmlFor="username">Username: </label> + <label htmlFor="username"> + {loginPage.window.uname} + </label> <br /> <input id="username" type="text"></input> <br /> - <label htmlFor="passwd">Password: </label> + <label htmlFor="passwd"> + {loginPage.window.passwd} + </label> <br /> <input id="passwd" type="password"></input> <br /> <button - disabled={!valid} + disabled={valid} type="submit" onClick={() => { loginHandler(); }} > - Login + {loginPage.window.login} </button> <button - disabled={!valid} + disabled={valid} type="submit" onClick={() => { registrationHandler(); }} > - Register + {loginPage.window.register} </button> <button - disabled={valid} + disabled={!valid} type="submit" onClick={() => { setLogin(undefined); - setValid(false); + setValid(undefined); }} > - Logout + {loginPage.window.logout} </button> </fieldset> </div> diff --git a/src/MessageDisplay/MessageDisplay.css b/src/MessageDisplay/MessageDisplay.css index 15af7eb..7ca7722 100644 --- a/src/MessageDisplay/MessageDisplay.css +++ b/src/MessageDisplay/MessageDisplay.css @@ -1,3 +1,3 @@ .msg .msg-err { - overflow-wrap: break-word; -}
\ No newline at end of file + overflow-wrap: break-word; +} diff --git a/src/MessageDisplay/MessageDisplay.tsx b/src/MessageDisplay/MessageDisplay.tsx index 92e9e79..18a9277 100644 --- a/src/MessageDisplay/MessageDisplay.tsx +++ b/src/MessageDisplay/MessageDisplay.tsx @@ -3,6 +3,7 @@ import { Message, MessageType } from "../type/messageTypes"; import { LangContext } from "../context"; import strings from "../Intl/strings.json"; import "./MessageDisplay.css"; +import { queryByRole } from "@testing-library/react"; export const MessageDisplay = ({ type, fromUserId, diff --git a/src/MessageDisplay/messageHandler.tsx b/src/MessageDisplay/messageHandler.tsx new file mode 100644 index 0000000..801692e --- /dev/null +++ b/src/MessageDisplay/messageHandler.tsx @@ -0,0 +1,5 @@ +import {Message, MessageType } from "../type/messageTypes" +export const dataMsgHandler = (msg: Message) => { + if (msg.type !== MessageType.DATA) {return <></>} +} +export const chnameMsgHandler = () => {} diff --git a/src/index.css b/src/index.css index ec2585e..a158d83 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,13 @@ body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; } diff --git a/src/type/userTypes.ts b/src/type/userTypes.ts index b888745..d5c1e37 100644 --- a/src/type/userTypes.ts +++ b/src/type/userTypes.ts @@ -1,7 +1,13 @@ +import { URL } from "url"; + +export type UserAvatar = { + iconUrls: URL[]; +}; export type User = { id: number; userName: string; dateJoined: number; lastSeen: number; passwordHash: string; + // avatar: UserAvatar; }; |