Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
tdemin committed Nov 10, 2019
2 parents 332968c + 989309a commit 3d86326
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 9 deletions.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "amber_web",
"version": "0.0.4.1",
"version": "0.0.5",
"private": true,
"dependencies": {
"@types/jest": "24.0.18",
Expand Down
2 changes: 1 addition & 1 deletion src/const.ts
@@ -1,7 +1,7 @@
export const baseURI: string =
process.env.REACT_APP_APIURI || "https://amber.h.tdem.in/api";

export const appVersion: string = "0.0.4.1";
export const appVersion: string = "0.0.5";
export const appFullName: string = "Amber Web";
export const appName: string = "amber_web";
export const appAuthor: string = "Timur Demin";
Expand Down
6 changes: 6 additions & 0 deletions src/main.tsx
Expand Up @@ -5,6 +5,7 @@ import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { Store } from "./typings/store";

import LoginForm from "./views/loginForm";
import SignupForm from "./views/signupForm";
import MainView from "./views/mainView";
import EditorView from "./views/editorView";

Expand Down Expand Up @@ -49,6 +50,11 @@ class App extends React.Component<Props, Props> {
<Router>
{!loggedIn && (
<Switch>
<Route
path="/signup"
exact
component={SignupForm}
/>
<Route path="/" exact component={LoginForm} />
</Switch>
)}
Expand Down
8 changes: 8 additions & 0 deletions src/views/assets/locales.ts
Expand Up @@ -8,6 +8,14 @@ export default new LocalizedStrings({
login_userNameTp: "User name",
login_passwordTp: "Password",
login_wrongPassTp: "Login failed. Check username and password.",
signup_processMsg: "Signing up...",
signup_successMsg: "Success. Redirecting to login...",
signup_failMsg: "Signup failed",
signup_unknownError: "Unknown error",
signup_disabled: "Signup disabled",
signup_userExists: "User with this name exists",
login_signupBtn: "Sign up",
login_goBackBtn: "Go back",
main_loggedInMsg: "Logged in as",
main_logoutBtn: "Logout",
main_searchTp: "Search tasks...",
Expand Down
32 changes: 25 additions & 7 deletions src/views/loginForm.tsx
@@ -1,6 +1,7 @@
import React from "react";
import { ThunkDispatch } from "redux-thunk";
import { connect } from "react-redux";
import { RouteComponentProps } from "react-router-dom";

import { login } from "../actions/auth";
import { AuthAction } from "../typings/actions";
Expand All @@ -20,7 +21,7 @@ interface State {
password: string;
loginFailed: boolean;
}
interface Props {
interface Props extends RouteComponentProps {
loginFailed?: boolean;
dispatch: ThunkDispatch<any, any, AuthAction>;
}
Expand All @@ -40,6 +41,7 @@ class LoginForm extends React.PureComponent<Props, State> {
this.setState({ password: event.currentTarget.value });
login = () =>
this.props.dispatch(login(this.state.username, this.state.password));
toSignup = () => this.props.history.push("/signup");
onKeyPress = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter") this.login();
};
Expand Down Expand Up @@ -75,12 +77,28 @@ class LoginForm extends React.PureComponent<Props, State> {
>
{strings.login_wrongPassTp}
</span>
<input
type="button"
className="button"
value={strings.login_loginBtn}
onClick={this.login}
/>
<div className="level is-mobile">
<div className="level-item level-left">
<div className="control">
<input
type="button"
className="button"
value={strings.login_loginBtn}
onClick={this.login}
/>
</div>
</div>
<div className="level-item level-right">
<div className="control">
<input
type="button"
className="button"
onClick={this.toSignup}
value={strings.login_signupBtn}
/>
</div>
</div>
</div>
</form>
</div>
);
Expand Down
161 changes: 161 additions & 0 deletions src/views/signupForm.tsx
@@ -0,0 +1,161 @@
import React from "react";
import { RouteComponentProps as RCP } from "react-router-dom";
import { AxiosError, AxiosResponse } from "axios";

import req from "../axios";

import strings from "./assets/locales";

import "./styles/signupForm.scss";

enum Status {
UNDEFINED,
FAILED,
SUCCESS,
IN_PROCESS,
}
enum Errors {
FORBIDDEN = 403,
USER_EXISTS = 409,
}
interface State {
name: string;
password: string;
status: Status;
httpCode: number;
}

interface MsgProps {
message: string;
code: Status;
matchCode: Status;
}
/**
* Used for displaying messages on matching status code.
*/
const Msg: React.FC<MsgProps> = (props) => (
<span
style={{ display: props.code === props.matchCode ? "block" : "none" }}
>
{props.message}
</span>
);

class SignupForm extends React.PureComponent<RCP, State> {
state = {
name: "",
password: "",
status: Status.UNDEFINED,
httpCode: 0,
};
componentDidUpdate = () => {
if (this.state.status === Status.SUCCESS) {
setTimeout(() => {
this.props.history.push("/");
}, 5000);
}
};
signup = () => {
this.setState({ status: Status.IN_PROCESS });
// prettier-ignore
req.post("/signup", {
name: this.state.name,
password: this.state.password,
})
.then(
() => this.setState({ status: Status.SUCCESS }),
(e: AxiosError) => this.setState({
status: Status.FAILED,
httpCode: (e.response as AxiosResponse).status
})
);
};
goBack = () => this.props.history.push("/");
updateName = (e: React.FormEvent<HTMLInputElement>) =>
this.setState({ name: e.currentTarget.value });
updatePassword = (e: React.FormEvent<HTMLInputElement>) =>
this.setState({ password: e.currentTarget.value });
render = () => {
let message: string;
switch (this.state.httpCode) {
case Errors.FORBIDDEN:
message = strings.signup_disabled;
case Errors.USER_EXISTS:
message = strings.signup_userExists;
default:
message = strings.signup_unknownError;
}
return (
<div className="container signup_form">
<form className="signupForm">
<div className="field">
<label className="label">
{strings.login_userNameTp}
</label>
<div className="control">
<input
type="text"
autoFocus
className="input"
onChange={this.updateName}
/>
</div>
</div>
<div className="field">
<label className="label">
{strings.login_passwordTp}
</label>
<div className="control">
<input
className="input"
type="password"
onChange={this.updatePassword}
/>
</div>
</div>
<div className="level is-mobile">
<div className="level-item level-left">
<div className="control">
<input
type="button"
className="button"
value={strings.login_signupBtn}
onClick={this.signup}
/>
</div>
</div>
<div className="level-item">
<Msg
code={this.state.status}
matchCode={Status.FAILED}
message={`${strings.signup_failMsg}: ${message}`}
/>
<Msg
code={this.state.status}
matchCode={Status.IN_PROCESS}
message={strings.signup_processMsg}
/>
<Msg
code={this.state.status}
matchCode={Status.SUCCESS}
message={strings.signup_successMsg}
/>
</div>
<div className="level-item level-right">
<div className="control">
<input
type="button"
className="button"
value={strings.login_goBackBtn}
onClick={this.goBack}
/>
</div>
</div>
</div>
</form>
</div>
);
};
}

export default SignupForm;
5 changes: 5 additions & 0 deletions src/views/styles/signupForm.scss
@@ -0,0 +1,5 @@
@import "./common.scss";

form.signupForm {
max-width: 320px;
}

0 comments on commit 3d86326

Please sign in to comment.