Start forgot password

This commit is contained in:
Paulo Gustavo Veiga 2020-12-07 23:34:01 -08:00
parent 7c53c6b9c7
commit a6fe41b5c9
14 changed files with 194 additions and 69 deletions

View File

@ -8,7 +8,6 @@
"lint": "eslint src", "lint": "eslint src",
"extract": "formatjs extract", "extract": "formatjs extract",
"compile": "formatjs compile" "compile": "formatjs compile"
}, },
"repository": "http://www.wisemapping.com", "repository": "http://www.wisemapping.com",
"author": "Paulo Veiga <pveiga@gmail.com>, Ezequiel Bergamaschi <ezequielbergamaschi@gmail.com>", "author": "Paulo Veiga <pveiga@gmail.com>, Ezequiel Bergamaschi <ezequielbergamaschi@gmail.com>",
@ -44,6 +43,7 @@
"webpack-dev-server": "^3.11.0" "webpack-dev-server": "^3.11.0"
}, },
"dependencies": { "dependencies": {
"@types/react-google-recaptcha": "^2.1.0",
"axios": "^0.21.0", "axios": "^0.21.0",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
@ -51,4 +51,4 @@
"react-intl": "^5.10.6", "react-intl": "^5.10.6",
"react-router-dom": "^5.2.0" "react-router-dom": "^5.2.0"
} }
} }

View File

@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> --> <!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="WiseMappping" /> <meta name="description" content="WiseMappping" />
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.png" /> --> <!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.png" /> -->

View File

@ -2,9 +2,9 @@ import React, { useEffect, useState } from 'react';
import { Service, RestService } from './services/Service'; import { Service, RestService } from './services/Service';
import { IntlProvider } from 'react-intl' import { IntlProvider } from 'react-intl'
import LoginPage from './components/LoginPage'; import { RegistrationSuccessPage } from './components/registration-success-page';
import { RegistationPage } from './components/RegistrationPage'; import { RegistationPage } from './components/registration-page';
import { RegistrationSuccessPage } from './components/RegistrationSuccessPage'; import LoginPage from './components/login-page';
import { import {
Route, Route,
@ -12,6 +12,7 @@ import {
Redirect, Redirect,
BrowserRouter as Router, BrowserRouter as Router,
} from 'react-router-dom'; } from 'react-router-dom';
import { ForgotPasswordPage } from './components/forgot-password-page';
function loadLocaleData(language: string) { function loadLocaleData(language: string) {
switch (language) { switch (language) {
@ -56,6 +57,7 @@ const App = () => {
<RegistationPage service={service} /> <RegistationPage service={service} />
</Route> </Route>
<Route path="/c/user/registrationSuccess" component={RegistrationSuccessPage} /> <Route path="/c/user/registrationSuccess" component={RegistrationSuccessPage} />
<Route path="/c/user/resetPassword" component={ForgotPasswordPage} />
</Switch> </Switch>
</Router> </Router>
</IntlProvider> </IntlProvider>

View File

@ -1,27 +1,29 @@
import React from 'react' import React from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
const logo = require('../images/logo-text.svg') const logo = require('../../images/logo-text.svg')
const Footer = () => { const Footer = () => {
return ( return (
<footer className="footer" > <footer className="footer" >
{/* Todo: Replace this with a SVG Image */} {/* Todo: Replace this with a SVG Image */}
<div style={{padding: 0, margin: 0}}> <div style={{ padding: 0, margin: 0 }}>
<a href="http://www.wisemapping.org/"> <a href="http://www.wisemapping.org/">
<div style={{textAlign: "left"}}>Powered By</div><img src={logo} alt="logo" /> <div style={{ textAlign: "left" }}>Powered By</div><img src={logo} alt="logo" />
</a> </a>
</div> </div>
<div > <div >
<div><a href="https://www.wisemapping.com/termsofuse.html"> <FormattedMessage id="footer.termsandconditions" defaultMessage="Term And Conditions" /> </a></div> <h4><FormattedMessage id="footer.faqandhelp" defaultMessage="Help &amp; FAQ" /></h4>
<div><a href="https://www.wisemapping.com/faq.html"> <FormattedMessage id="footer.faq" defaultMessage="F.A.Q." /> </a></div > <div><a href="https://www.wisemapping.com/faq.html"> <FormattedMessage id="footer.faq" defaultMessage="F.A.Q." /> </a></div >
<div><a href="https://www.wisemapping.com/aboutus.html"> <FormattedMessage id="footer.aboutus" defaultMessage="About Us" /></a></div > <div><a href="https://www.wisemapping.com/termsofuse.html"> <FormattedMessage id="footer.termsandconditions" defaultMessage="Term And Conditions" /> </a></div>
<div><a href="mailto:team@wisemapping.com"> <FormattedMessage id="footer.contactus" defaultMessage="Contact Us" /> </a></div>
</div> </div>
<div > <div >
<div><a href="http://www.wisemapping.org/"> <FormattedMessage id="footer.opensource" defaultMessage="Open Source" /> </a></div> <h4><FormattedMessage id="footer.others" defaultMessage="Others" /></h4>
<div><a href="mailto:team@wisemapping.com"> <FormattedMessage id="footer.contactus" defaultMessage="Contact Us" /> </a></div> <div><a href="https://www.wisemapping.com/aboutus.html"> <FormattedMessage id="footer.aboutus" defaultMessage="About Us" /></a></div >
<div><a href="mailto:feedback@wisemapping.com" > <FormattedMessage id="footer.feedback" defaultMessage="Feedback" /> </a></div> <div><a href="mailto:feedback@wisemapping.com" > <FormattedMessage id="footer.feedback" defaultMessage="Feedback" /> </a></div>
<div><a href="http://www.wisemapping.org/"> <FormattedMessage id="footer.opensource" defaultMessage="Open Source" /> </a></div>
</div> </div>
<div> <div>
<div><span className="button-style2" >< a href="https://www.paypal.com/webapps/shoppingcart?flowlogging_id=c7ac923b53025&mfid=1606520600355_c7ac923b53025#/checkout/openButton">< FormattedMessage id="footer.donations" defaultMessage="PayPal Donations" /> </a></span ></div> <div><span className="button-style2" >< a href="https://www.paypal.com/webapps/shoppingcart?flowlogging_id=c7ac923b53025&mfid=1606520600355_c7ac923b53025#/checkout/openButton">< FormattedMessage id="footer.donations" defaultMessage="PayPal Donations" /> </a></span ></div>

View File

@ -0,0 +1,86 @@
import React, { useState, useEffect } from 'react'
import { FormattedMessage, useIntl } from 'react-intl'
import { useHistory } from "react-router-dom"
import { Service } from '../../services/Service'
import Header from '../header'
import Footer from '../footer'
import SubmitButton from '../submit-button'
const css = require('../../css/registration.css');
interface ErrorMessageDialogProps {
message: string
}
const ErrorMessageDialog = (props: ErrorMessageDialogProps) => {
const message = props.message;
return message ? <p className='form-error-dialog'>{message}</p> : <span></span>;
}
type ForgotPasswordProps = {
email: string;
}
const RegistrationForm = (props: ServiceProps) => {
const [email, setEmail] = useState("");
const [errorMsg, setErrorMsg] = useState("");
const [disableButton, setDisableButton] = useState(false);
const history = useHistory();
const intl = useIntl();
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
setDisableButton(true);
// Call Service ...
props.service.resetPassword(
email,
() => history.push("/c/user/forgotPasswordSuccess"),
(msg) => { setErrorMsg(msg); setDisableButton(false); }
);
}
return (
<div className="wrapper">
<div className="content">
<h1><FormattedMessage id="forgot.title" defaultMessage="Reset your password" /></h1>
<p><FormattedMessage id="forgot.desc" defaultMessage="We will send you an email to reset your password" /></p>
<form action="/" method="POST" onSubmit={e => handleSubmit(e)}>
<input type="email" name="email" onChange={e => setEmail(e.target.value)} placeholder={intl.formatMessage({ id: "forgot.email", defaultMessage: "Email" })} required={true} autoComplete="email" />
<ErrorMessageDialog message={errorMsg} />
<SubmitButton disabled={disableButton} value={intl.formatMessage({ id: "forgot.register", defaultMessage: "Send recovery link" })} />
</form>
</div>
</div>
);
}
type ServiceProps = {
service: Service
}
const ForgotPasswordPage = (props: ServiceProps) => {
useEffect(() => {
document.title = 'Forgot Password | WiseMapping';
});
return (
<div>
<Header type='only-signin' />
<RegistrationForm service={props.service} />
<Footer />
</div>
);
}
export { ForgotPasswordPage }

View File

@ -2,7 +2,7 @@ import React from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
const logo = require('../images/header-logo.png') const logo = require('../../images/header-logo.png')
interface HeaderProps { interface HeaderProps {
type: 'only-signup' | 'only-signin' | 'none'; type: 'only-signup' | 'only-signin' | 'none';

View File

@ -2,11 +2,11 @@ import React, { useEffect } from 'react'
import { FormattedMessage, useIntl } from 'react-intl' import { FormattedMessage, useIntl } from 'react-intl'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import Header from './Header' import Header from '../header'
import Footer from './Footer' import Footer from '../footer'
import SubmitButton from './SubmitButton' import SubmitButton from '../submit-button'
const css = require('../css/login.css') const css = require('../../css/login.css')
const ConfigStatusMessage = (props: any) => { const ConfigStatusMessage = (props: any) => {
@ -53,8 +53,8 @@ const LoginForm = () => {
return ( return (
<div className="wrapper"> <div className="wrapper">
<div className="content"> <div className="content">
<h1><FormattedMessage id="login.welcome" defaultMessage="Welcome" /></h1> <h1><FormattedMessage id="login.title" defaultMessage="Welcome" /></h1>
<p><FormattedMessage id="login.loginto" defaultMessage="Log Into Your Account" /></p> <p><FormattedMessage id="login.desc" defaultMessage="Log Into Your Account" /></p>
<LoginError /> <LoginError />

View File

@ -1,15 +1,15 @@
import React, { useState, useEffect} from 'react' import React, { useState, useEffect} from 'react'
import { FormattedMessage, useIntl } from 'react-intl' import { FormattedMessage, useIntl } from 'react-intl'
import ReCAPTCHA from "react-google-recaptcha" import ReCAPTCHA from 'react-google-recaptcha'
import { useHistory } from "react-router-dom" import { useHistory } from "react-router-dom"
import { Service, NewUser } from '../services/Service' import { Service, NewUser } from '../../services/Service'
import Header from './Header' import Header from '../header'
import Footer from './Footer' import Footer from '../footer'
import SubmitButton from './SubmitButton' import SubmitButton from '../submit-button'
const css = require('../css/registration.css'); const css = require('../../css/registration.css');
interface ErrorMessageDialogProps { interface ErrorMessageDialogProps {
message: string message: string
@ -29,15 +29,16 @@ const ErrorMessageDialog = (props: ErrorMessageDialogProps) => {
type RegistrationBody = { type RegistrationBody = {
email: string; email: string;
firstName: string; firstname: string;
lastName: string; lastlname: string;
password: string; password: string;
recaptcha: string | null; recaptcha: string | null;
} }
const RegistrationForm = (props: ServiceProps) => { const RegistrationForm = (props: ServiceProps) => {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [lastName, setLastname] = useState("") const [lastname, setLastname] = useState("")
const [firstName, setFirstname] = useState(""); const [firstname, setFirstname] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [recaptchaToken, setRecaptchaToken] = useState<string | null>(""); const [recaptchaToken, setRecaptchaToken] = useState<string | null>("");
const [errorMsg, setErrorMsg] = useState(""); const [errorMsg, setErrorMsg] = useState("");
@ -54,8 +55,8 @@ const RegistrationForm = (props: ServiceProps) => {
const user: NewUser = const user: NewUser =
{ {
email: email, email: email,
firstname: firstName, firstname: firstname,
lastname: lastName, lastname: lastname,
password: password, password: password,
recaptcha: String(recaptchaToken) recaptcha: String(recaptchaToken)
}; };
@ -71,10 +72,10 @@ const RegistrationForm = (props: ServiceProps) => {
return ( return (
<div className="wrapper"> <div className="wrapper">
<div className="content"> <div className="content">
<h1><FormattedMessage id="registration.become" defaultMessage="Become a member of our comunity" /></h1> <h1><FormattedMessage id="registration.title" defaultMessage="Become a member of our comunity" /></h1>
<p><FormattedMessage id="registration.signup" defaultMessage="Signing up is free and just take a moment " /></p> <p><FormattedMessage id="registration.desc" defaultMessage="Signing up is free and just take a moment " /></p>
<form method="POST" onSubmit={e => handleSubmit(e)}> <form action="/" method="POST" onSubmit={e => handleSubmit(e)}>
<input type="email" name="email" onChange={e => setEmail(e.target.value)} placeholder={intl.formatMessage({ id: "registration.email", defaultMessage: "Email" })} required={true} autoComplete="email" /> <input type="email" name="email" onChange={e => setEmail(e.target.value)} placeholder={intl.formatMessage({ id: "registration.email", defaultMessage: "Email" })} required={true} autoComplete="email" />
<input type="text" name="firstname" onChange={e => setFirstname(e.target.value)} placeholder={intl.formatMessage({ id: "registration.firstname", defaultMessage: "First Name" })} required={true} autoComplete="given-name" /> <input type="text" name="firstname" onChange={e => setFirstname(e.target.value)} placeholder={intl.formatMessage({ id: "registration.firstname", defaultMessage: "First Name" })} required={true} autoComplete="given-name" />
<input type="text" name="lastname" onChange={e => setLastname(e.target.value)} placeholder={intl.formatMessage({ id: "registration.lastname", defaultMessage: "Last Name" })} required={true} autoComplete="family-name" /> <input type="text" name="lastname" onChange={e => setLastname(e.target.value)} placeholder={intl.formatMessage({ id: "registration.lastname", defaultMessage: "Last Name" })} required={true} autoComplete="family-name" />

View File

@ -1,10 +1,10 @@
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
import Header, { SignInButton } from './Header' import Header, { SignInButton } from '../header'
import Footer from './Footer' import Footer from '../footer'
const css = require('../css/success.css'); const css = require('../../css/success.css');
const RegistrationSuccessPage = () => { const RegistrationSuccessPage = () => {
@ -21,7 +21,7 @@ const RegistrationSuccessPage = () => {
<FormattedMessage id="registration.success.title" defaultMessage="Your account has been created successfully" /> <FormattedMessage id="registration.success.title" defaultMessage="Your account has been created successfully" />
</h1> </h1>
<p> <p>
<FormattedMessage id="registration.success.desc" defaultMessage="Click to 'Sign In' button below and start creating mind maps." /> <FormattedMessage id="registration.success.desc" defaultMessage="Click 'Sign In' button below and start creating mind maps." />
</p> </p>
<SignInButton style='style1'/> <SignInButton style='style1'/>

View File

@ -136,19 +136,25 @@ nav a {
/* Footer */ /* Footer */
.footer { .footer {
height: 170px; height: 250px;
margin-top: 50px; margin-top: 80px;
padding: 30px 40px 10px 50px; padding: 60px 40px 10px 50px;
background-color: #f9a826; background-color: #f9a826;
display: grid; display: grid;
} }
.footer a { .footer a {
font-size: 14px; font-size: 14px;
margin: 0px 10px;
color: white; color: white;
word-wrap: nowrap; word-wrap: nowrap;
text-align: center; }
.footer h4 {
font-size: 14px;
color: white;
word-wrap: nowrap;
font-weight: 500px;
margin: 0px;
} }
.footer>svg { .footer>svg {
@ -196,11 +202,8 @@ nav a {
.footer { .footer {
grid-template-columns: 0px 1fr 1fr 5px; grid-template-columns: 0px 1fr 1fr 5px;
} }
.footer>svg, .footer div:nth-child(1),
.footer div:nth-child(4) { .footer div:nth-child(4),
display: none;
visibility: hidden;
}
.header-area-content-span { .header-area-content-span {
display: none; display: none;
visibility: hidden; visibility: hidden;
@ -291,6 +294,7 @@ input:placeholder {
} }
.button-style1 a { .button-style1 a {
color: #f9a826;
background-color: white; background-color: white;
border: solid 1px #f9a826; border: solid 1px #f9a826;
} }

View File

@ -0,0 +1,39 @@
@import "core.css";
.wrapper {
max-width: 1024px;
display: grid;
grid-template-areas: "content" "footer";
}
.content {
grid-area: content;
text-align: center;
}
.content input:placeholder {
color: grey;
}
.content label {
font-size: 14px;
}
.content a {
color: #f9a826;
font-size: 15px;
}
.db-warn-msg {
margin-top: 30px;
width: 100%;
}
.db-warn-msg p {
margin: 0 auto;
width: 500px;
background-color: #e97450;
font-size: 15px;
color: white;
padding: 15px 30px;
border-radius: 10px;
}

View File

@ -19,21 +19,4 @@
.rcontent h1 { .rcontent h1 {
color: #f9a826; color: #f9a826;
font-size: 30px; font-size: 30px;
} }
/* .button-style1 {
font-size: 20px;
font-weight: 500;
font-stretch: normal;
font-style: normal;
letter-spacing: normal;
white-space: nowrap;
padding-top: 10px;
}
.button-style1 a {
padding: 10px 30px 10px 30px;
transition: background-color 0.3s ease;
border-radius: 9px;
} */

View File

@ -1,14 +1,17 @@
import axios from 'axios' import axios from 'axios'
type NewUser = { type NewUser = {
email: string; email: string;
firstname: string; firstname: string;
lastname: string; lastname: string;
password: string; password: string;
recaptcha: string; recaptcha: string | null;
} }
interface Service { interface Service {
registerNewUser(user: NewUser, onSuccess: () => void, onError: (msg: string) => void): void; registerNewUser(user: NewUser, onSuccess: () => void, onError: (msg: string) => void): void;
resetPassword(email:string, onSuccess: () => void, onError: (msg: string) => void): void;
} }
class RestService implements Service { class RestService implements Service {
@ -56,5 +59,10 @@ class RestService implements Service {
onError(msg); onError(msg);
}); });
} }
resetPassword(email:string, onSuccess: () => void, onError: (msg: string) => void): void {
}
} }
export { Service, RestService, NewUser } export { Service, RestService, NewUser }