232 lines
8.7 KiB
JavaScript
232 lines
8.7 KiB
JavaScript
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 topic’s 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 variable’s 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;
|