diff --git a/src/components/app.tsx b/src/components/app.tsx index 4031ccd..1be85f1 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -31,13 +31,17 @@ import ReviewPage from "../pages/review"; import SummaryPage from "../pages/summary"; import WelcomePage from "../pages/intro"; +import { BACKEND_URL } from "../config"; + import { ILevel } from "../models/level"; import { ILearner } from "../models/learner"; import { IVocab, VocabType } from "../models/vocab"; import { IReviewMetadata, ReviewType } from "../models/review"; +import { IUser } from "../models/user"; interface IState { loggedIn: boolean; + user: IUser | {}; lastReview: IReviewMetadata; @@ -47,18 +51,20 @@ interface IState { // TODO: Replace the sessionStorage with localStorage? // TODO: Cache API-Calls +// TODO: When mounting without a login, check if the sessionToken is still valid export default class Application extends React.Component<{}, IState> { constructor(props: any) { super(props); // Load a key from the SessionStorage - const authKey = window.sessionStorage.getItem("authKey") || null; + const authKey = window.sessionStorage.getItem("sessionToken") || null; // TODO const loggedIn = authKey !== null; // TODO: Fetch the last review this.state = { loggedIn, + user: {}, lastReview: { correct: 0, @@ -99,6 +105,8 @@ export default class Application extends React.Component<{}, IState> { } setLastReview = (meta: IReviewMetadata) => { + console.log("STUB: Application::setLastReview"); + // TODO: Send this to the server this.setState({ lastReview: meta, @@ -216,16 +224,32 @@ export default class Application extends React.Component<{}, IState> { } */] as IVocab[]; } - login(username: string, password: string): Promise { - console.log("STUB: Application::login"); - + login(username: string, password: string): Promise { return new Promise((res, rej) => { // TODO: First login? Redirect to /welcome - // TODO - this.setState({ - loggedIn: true - }); - res(); + fetch(`${BACKEND_URL}/login`, { + method: "POST", + headers: new Headers({ + 'Content-Type': "application/json", + }), + body: JSON.stringify({ + // NOTE: We will force HTTPS and hash using pbkdf2 on the + // server + username: username, + hash: password, + }), + }).then(data => data.json()) + .then((resp) => { + if (resp.error === "0") { + this.setState({ + loggedIn: true, + user: resp.data, + }); + res(resp.data); + } else { + rej({}); + } + }); }); } @@ -278,9 +302,8 @@ export default class Application extends React.Component<{}, IState> { onOpen={() => this.setState({ drawerOpen: true })}> - {/* TODO: Replace with the actual username */} - + diff --git a/src/config.ts b/src/config.ts index 0170d89..183f344 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,2 +1,4 @@ // Maximum distance from the answer to be still considered correct export const LEVENSHTEIN_MAX_DISTANCE = 2; + +export const BACKEND_URL = "http://127.0.0.1:8080"; diff --git a/src/models/user.ts b/src/models/user.ts new file mode 100644 index 0000000..5f1cf7a --- /dev/null +++ b/src/models/user.ts @@ -0,0 +1,7 @@ +export interface IUser { + username: string; + uid: string; + showWelcome: boolean; + + sessionToken: string; +}; diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 0ae45e2..a2ea83d 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -10,8 +10,10 @@ import Snackbar from "@material-ui/core/Snackbar"; import { Redirect } from "react-router-dom"; +import { IUser } from "../models/user"; + interface IProps { - login: (username: string, password: string) => Promise; + login: (username: string, password: string) => Promise; loggedIn: boolean; } @@ -25,14 +27,14 @@ interface IState { open: boolean; } -export default class LoginPage extends React.Component<{}, IState> { +export default class LoginPage extends React.Component { constructor(props: any) { super(props); this.state = { username: "", password: "", - loading: false; + loading: false, snack: "", open: false, }; @@ -50,12 +52,12 @@ export default class LoginPage extends React.Component<{}, IState> { } performLogin() { - const load = (loading) => { + const load = (loading: boolean) => { this.setState({ loading }); } - const showSnackbar = (msg) => { + const showSnackbar = (msg: string) => { this.setState({ open: true, snack: msg, @@ -65,9 +67,10 @@ export default class LoginPage extends React.Component<{}, IState> { load(true); const { username, password } = this.state; - this.props.login(username, password).then((res) => { + console.log(this.state); + this.props.login(username, password).then((res: IUser) => { // Set the session key - window.sessionStorage.setItem("authKey", "test123"); + window.sessionStorage.setItem("sessionToken", res.sessionToken); }, (err) => { load(false); showSnackbar("Failed to log in"); @@ -94,13 +97,15 @@ export default class LoginPage extends React.Component<{}, IState> { this.update("username")} /> + onChange={this.update("username")} + value={this.state.username} /> this.update("password")} /> + value={this.state.password} + onChange={this.update("password")} />