-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from chuang8511/feat-login
Feat login
- Loading branch information
Showing
17 changed files
with
357 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from "react"; | ||
|
||
interface InputProps { | ||
value: string; | ||
onChange: (value: string) => void; | ||
label: string; | ||
type: "email" | "password"; | ||
placeholder?: string; | ||
} | ||
|
||
const LoginInput: React.FC<InputProps> = ({ value, onChange, label, type, placeholder }) => { | ||
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { | ||
onChange(event.target.value); | ||
}; | ||
|
||
return ( | ||
<div> | ||
<label htmlFor={type}>{label}:</label> | ||
<input id={type} type={type} placeholder={placeholder} value={value} onChange={handleChange} /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default LoginInput; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import React, { useState } from "react"; | ||
import LoginInput from "./component/input"; | ||
import fetch from "node-fetch" | ||
|
||
const LoginPage: React.FC = () => { | ||
const [email, setLoginEmail] = useState<string>(""); | ||
const [password, setLoginPassword] = useState<string>(""); | ||
|
||
const [message, setLoginResultMessage] = useState<string>(""); | ||
|
||
const handleLogin = async (email: string, password: string, event: React.FormEvent<HTMLFormElement>) => { | ||
event.preventDefault() | ||
console.log("Login data:", { email }) | ||
setLoginResultMessage(""); | ||
|
||
if (!(email && password)) { | ||
setLoginResultMessage("Please fill in all fields") | ||
return | ||
} | ||
|
||
try { | ||
const response = await fetch("http://localhost:3001/v1/api/account/login" , { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json" | ||
}, | ||
body: JSON.stringify({ email, password }) | ||
}) | ||
|
||
const status = response.status | ||
const apiData = await response.json(); | ||
const failureReason = apiData.data?.failureReason | ||
|
||
if (status == 201) { | ||
setLoginResultMessage("Successfully Login") | ||
// to display the friends page and set the session to keep login status | ||
|
||
} else if (status == 403 && failureReason == "no user") { | ||
setLoginResultMessage("No email is found") | ||
|
||
} else if (status == 403 && failureReason == "wrong password") { | ||
const remainingTimes = apiData.data.times | ||
setLoginResultMessage("Password is wrong, you still have " + remainingTimes + " times to try today") | ||
|
||
} else { | ||
throw new Error("Failed to connect server") | ||
} | ||
|
||
} catch (error: any) { | ||
console.error("Unexpected error", error.message); | ||
setLoginResultMessage("Something weng wrong, please do it later.") | ||
} | ||
|
||
} | ||
return ( | ||
<div> | ||
<form onSubmit={(event) => handleLogin(email, password, event)}> | ||
<LoginInput | ||
value={email} | ||
onChange={setLoginEmail} | ||
label="Email" | ||
type="email" | ||
placeholder="xxx@gmail.com" | ||
/> | ||
<LoginInput | ||
value={password} | ||
onChange={setLoginPassword} | ||
label="Password" | ||
type="password" | ||
placeholder="xxx" | ||
/> | ||
<button type="submit" data-testid="login-form">Login</button> | ||
</form> | ||
{message && <p data-testid="submit-message">{message}</p>} | ||
</div> | ||
) | ||
|
||
} | ||
|
||
export default LoginPage |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from "react"; | ||
import { render, fireEvent } from "@testing-library/react" | ||
import "@testing-library/jest-dom" | ||
import LoginInput from "../../../LoginPage/component/input"; | ||
|
||
describe("LoginInput", () => { | ||
it("renders email input", () => { | ||
const fakeOnChange = jest.fn() | ||
const { getByLabelText } = render(<LoginInput value="" onChange={fakeOnChange} label="Email" type="email" placeholder="xxx@gmail.com" />); | ||
const emailInput = getByLabelText("Email:") | ||
expect(emailInput).toHaveAttribute("type", "email") | ||
}) | ||
|
||
it("renders password input", () =>{ | ||
const fakeOnChange = jest.fn() | ||
const { getByLabelText } = render(<LoginInput value="" onChange={fakeOnChange} label="Password" type="password" placeholder="xxx" />); | ||
const passwordInput = getByLabelText("Password:") | ||
expect(passwordInput).toHaveAttribute("type", "password") | ||
}) | ||
|
||
it("triggers the function when the input is updated", () => { | ||
const fakeOnChange = jest.fn() | ||
const { getByLabelText } = render(<LoginInput value="" onChange={fakeOnChange} label="Email" type="email" placeholder="xxx@gmail.com" />); | ||
const emailInput = getByLabelText("Email:") | ||
fireEvent.change(emailInput, { target: { value: "test@gmail.com" }}) | ||
expect(fakeOnChange).toHaveBeenCalledTimes(1) | ||
expect(fakeOnChange).toHaveBeenCalledWith("test@gmail.com") | ||
|
||
}) | ||
|
||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React from "react"; | ||
import { render, fireEvent, waitFor } from "@testing-library/react" | ||
import LoginPage from "../../LoginPage"; | ||
|
||
describe("Login page", () => { | ||
it("render without crashing", () => { | ||
render(<LoginPage/ >) | ||
}) | ||
|
||
it("display error message when submitting with empty fileds", async () => { | ||
const { getByTestId } = render(<LoginPage />); | ||
const loginBtn = getByTestId("login-form") | ||
fireEvent.submit(loginBtn); | ||
|
||
await waitFor(() => { | ||
expect(getByTestId("submit-message").textContent).toBe("Please fill in all fields") | ||
}) | ||
}) | ||
// todo: add the test case after knowing how to mock fetch | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Column, Entity, Index, PrimaryGeneratedColumn, BeforeInsert, BeforeUpdate, CreateDateColumn, UpdateDateColumn, BaseEntity } from 'typeorm' | ||
|
||
@Entity() | ||
export class LoginRecord extends BaseEntity { | ||
@PrimaryGeneratedColumn() | ||
id: number; | ||
|
||
@Column() | ||
email: string; | ||
|
||
@Column({ | ||
nullable: true | ||
}) | ||
loginIp: string; | ||
|
||
@Column() | ||
result: string; | ||
|
||
@CreateDateColumn() | ||
created_at: Date; | ||
|
||
@UpdateDateColumn() | ||
updated_at: Date; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { LoginRecord } from "../entity/LoginRecord.entity" | ||
|
||
export class AccountPersistence { | ||
static getFailureTimes = async (email: string): Promise<number> => { | ||
const today = new Date(); | ||
today.setHours(0, 0, 0, 0) | ||
let failureTimes = await LoginRecord | ||
.createQueryBuilder("record") | ||
.where("record.email = :email", { email: email }) | ||
.where("record.result = :result", { result: "NG" }) | ||
.where("record.created_at >= :startDate", { startDate: today }) | ||
.getCount() | ||
|
||
return failureTimes | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.