Files
004_comission/james_endl/COMP3322A-Lab-7-React/code/myreactapp/src/App.js
louiscklaw 7d30025aed update,
2025-01-31 21:26:01 +08:00

232 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
// 4.2. Go to class LoginButton. In its render() function, we are rendering a login button with the
// handler function this.handleClick bound to the onclick event. Implement the function
// handleClick(): If the input username and password are valid, use
// this.props.handleStatusChange(xx, yy) received from class Lab7App to update the state
// variables of Lab7App, where xx equals “true” and yy equals this.props.username received from
// class Lab7App; otherwise, alert the message “Login failed!” Hint: you can use the provided
// function checkValid() to check if the input username and password are valid, which returns true
// if the inputs are included in the predefined array userDB, and returns false, otherwise. Read more
// about the array find() function at https://developer.mozilla.org/en-
// US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
class LoginButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.checkValid = this.checkValid.bind(this);
}
checkValid() {
let item = userDB.find((item) => {
return item.username == this.props.username && item.password == this.props.password;
});
if (item != undefined) return true;
else return false;
}
// step 4.2
handleClick() {
if (this.checkValid()) {
this.props.handleStatusChange(true, this.props.username);
} else {
// otherwise, alert the message “Login failed!”
alert("Login failed!");
}
}
render() {
return <button onClick={() => this.handleClick()}>Login</button>;
}
}
class Contents extends React.Component {
constructor(props) {
super(props);
this.state = {
topics: topicsDB,
};
this.handleTopicsChange = this.handleTopicsChange.bind(this);
}
// step 7
// Step 7. Implement filtering of topics list
// Now implement the function handleTopicsChange() in class Contents as follows: if value of the
// argument option is not “all” (i.e., it is one of the three sections instead), apply filter() function on
// topicsDB to obtain a filtered topics array where each topics section is option (learn more about
// JavaScript Array filter method at https://developer.mozilla.org/en-
// US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), and set the state variable
// Topics to be the filtered array; otherwise, set the state variable Topics to be topicsDB. Note that
// you need to use this.setState() to change a state variables value.
handleTopicsChange(option) {
if (option == "all") {
this.setState({ topics: topicsDB });
} else {
this.setState({ topics: topicsDB.filter((o) => o.section == option) });
}
}
render() {
const topics = this.state.topics;
return (
<div id="contents">
<DropDownList handleTopicsChange={this.handleTopicsChange} />
{
// Step 5. Render topics list in class component Contents
// Go to class Contents, which has a state of one key-value pair: topics stores the list of topics to be
// shown on the page, initialized using the given array topicsDB. Complete the render() function of
// class Contents: within { }, apply map() function on topics to create a number of <p> elements,
// each presenting information of one topic in the topics array as <p>Section: {topic.section}; Topic
// Name: {topic.topic}</p>. The handler function handleTopicsChange() is to change the state
// variable topics upon selecting a different option in the drop-down list (to be implemented later).
topics.map((topic) => {
return (
<>
<p>
Section: {topic.section}; Name: {topic.topic}
</p>
</>
);
})
}
</div>
);
}
}
function DropDownList(props) {
var key_pool = {};
const getUniq = (value_in) => {
if (key_pool[value_in] != undefined) return false;
key_pool[value_in] = "";
return true;
};
return (
<div>
<b>Choose one section: </b>
{
// Step 6. Render a drop-down list in function component DropDownList
// Now go to function DropDownList, which receives the handler function handleTopicsChange of
// class Contents in its props. Complete its render() function as follows: remove "{/* step 6*/}", and
// in its place, create a drop-down list using the <select> element with four options (with values
// “all”, “section-1”, “section-2” and “section-3”, respectively). The option “all” should be
// associated with the attribute “selected” as the default option. Add an event handler function to
// onChange event on the <select> element (to track the change of selected option and update
// topics list accordingly), which should be e => props.handleTopicsChange(e.target.value).
}
<></>
{
<select onChange={(e) => props.handleTopicsChange(e.target.value)}>
<option selected value="all">
all
</option>
{
// topicsDB
// get unique by section
// extract section
// sort before exit
}
{topicsDB
.filter((t) => getUniq(t.section))
.map((ut) => ut.section)
.sort()
.map((ts) => (
<option value={ts}>{ts}</option>
))}
</select>
}
</div>
);
}
class Lab7App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLogin: false,
loginName: "",
inputUserName: "",
inputUserPswd: "",
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleStatusChange = this.handleStatusChange.bind(this);
}
// step 3
handleInputChange(event) {
let target = event.target;
let name = target.name;
let value = target.value;
this.setState({ [name]: value });
}
handleStatusChange(newStatus, loginName) {
const isUserLoggedIn = (login_status) => login_status == true;
if (isUserLoggedIn(newStatus)) {
this.setState({ isLogin: newStatus, loginName: loginName });
} else {
this.setState({ isLogin: newStatus, loginName: loginName, inputUserName: "", inputUserPswd: "" });
}
}
render() {
if (!this.state.isLogin) {
return (
<div>
<p>Fill in username and password and click the button to log in</p>
<input type="text" name="inputUserName" placeholder="username" value={this.state.inputUserName} onChange={(e) => this.handleInputChange(e)} />
<input type="password" name="inputUserPswd" placeholder="password" value={this.state.inputUserPswd} onChange={(e) => this.handleInputChange(e)} />
{
// 4.1. In the render() function of Lab7App, render the
// LoginButton component. The LoginButton component receives three props:
// 1. username: which equals the value of state variable inputUserName;
// 2. password: which equals the value of state variable inputUserPswd;
// 3. handleStatusChange: which equals this.handleStatusChange. We have provided the
// implementation of function handleStatusChange(), which receives the login status (boolean
// type) and the name of the logged-in user (string type) as arguments, and set the state
// variables isLogin and loginName to the argument values, respectively.
}
<LoginButton username={this.state.inputUserName} password={this.state.inputUserPswd} handleStatusChange={this.handleStatusChange} />
</div>
);
} else {
return (
<div>
<p>Welcome {this.state.loginName}!</p>
<button onClick={() => this.handleStatusChange(false, "")}>Logout</button>
{/* 4.3. Go to class Lab7App. In the render() function, add an onClick event handler to the logout button, which is an
arrow function ()=>this.handleStatusChange() where handleStatusChange() receives a “false” value and an empty string as arguments. */}
<Contents />
</div>
);
}
}
}
const userDB = [
{ username: "Alex", password: "123" },
{ username: "Bob", password: "231" },
{ username: "Jack", password: "321" },
];
const topicsDB = [
{ section: "section-1", topic: "CSS" },
{ section: "section-1", topic: "HTML" },
{ section: "section-1", topic: "WWW" },
{ section: "section-2", topic: "JaveScript" },
{ section: "section-2", topic: "MongoDB" },
{ section: "section-2", topic: "NodeJS" },
{ section: "section-3", topic: "JQuery" },
{ section: "section-3", topic: "React" },
{ section: "section-3", topic: "Vue" },
];
export default Lab7App;