From bec0c7998c2944cf32793ca21994767d8d191e9e Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Fri, 11 Dec 2020 20:06:42 -0800 Subject: [PATCH] Complete forgot password page. --- packages/webapp/src/app.tsx | 38 ++++---- .../components/forgot-password-page/index.tsx | 23 ++--- .../forgot-password-success-page/index.tsx | 36 ++++++++ .../components/form-error-dialog/index.tsx | 2 +- .../components/registration-page/index.tsx | 4 +- .../registration-success-page/index.tsx | 6 +- .../src/components/submit-button/index.tsx | 7 -- packages/webapp/src/services/Service.ts | 87 ++++++++++++------- packages/webapp/src/theme/global-style.ts | 6 +- packages/webapp/webpack.config.js | 9 +- 10 files changed, 134 insertions(+), 84 deletions(-) create mode 100644 packages/webapp/src/components/forgot-password-success-page/index.tsx diff --git a/packages/webapp/src/app.tsx b/packages/webapp/src/app.tsx index 8ba8e8a0..652d517f 100644 --- a/packages/webapp/src/app.tsx +++ b/packages/webapp/src/app.tsx @@ -2,9 +2,10 @@ import React, { useEffect, useState } from 'react'; import { Service, RestService } from './services/Service'; import { IntlProvider } from 'react-intl' -import {GlobalStyle} from './theme/global-style'; -import { RegistrationSuccessPage } from './components/registration-success-page'; -import { RegistationPage } from './components/registration-page'; +import { GlobalStyle } from './theme/global-style'; +import RegistrationSuccessPage from './components/registration-success-page'; +import ForgotPasswordSuccessPage from './components/forgot-password-success-page'; +import RegistationPage from './components/registration-page'; import LoginPage from './components/login-page'; import { @@ -49,20 +50,23 @@ const App = () => { return messages ? ( - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + ) :
Loading ...
} diff --git a/packages/webapp/src/components/forgot-password-page/index.tsx b/packages/webapp/src/components/forgot-password-page/index.tsx index 7c400fa5..731919de 100644 --- a/packages/webapp/src/components/forgot-password-page/index.tsx +++ b/packages/webapp/src/components/forgot-password-page/index.tsx @@ -6,25 +6,17 @@ import { Service } from '../../services/Service' import { PageContent } from '../../theme/global-style'; - import Header from '../header' import Footer from '../footer' +import FormErrorDialog from '../form-error-dialog' + import SubmitButton from '../submit-button' -interface ErrorMessageDialogProps { - message: string -} - -const ErrorMessageDialog = (props: ErrorMessageDialogProps) => { - const message = props.message; - return message ?

{message}

: ; -} - type ForgotPasswordProps = { email: string; } -const RegistrationForm = (props: ServiceProps) => { +const ForgotPassword = (props: ServiceProps) => { const [email, setEmail] = useState(""); const [errorMsg, setErrorMsg] = useState(""); @@ -37,7 +29,6 @@ const RegistrationForm = (props: ServiceProps) => { event.preventDefault(); setDisableButton(true); - // Call Service ... props.service.resetPassword( email, @@ -51,10 +42,10 @@ const RegistrationForm = (props: ServiceProps) => {

-
handleSubmit(e)}> + handleSubmit(e)}> setEmail(e.target.value)} placeholder={intl.formatMessage({ id: "forgot.email", defaultMessage: "Email" })} required={true} autoComplete="email" /> - + @@ -68,13 +59,13 @@ type ServiceProps = { const ForgotPasswordPage = (props: ServiceProps) => { useEffect(() => { - document.title = 'Forgot Password | WiseMapping'; + document.title = 'Reset Password | WiseMapping'; }); return (
- +
); diff --git a/packages/webapp/src/components/forgot-password-success-page/index.tsx b/packages/webapp/src/components/forgot-password-success-page/index.tsx new file mode 100644 index 00000000..c4f0de96 --- /dev/null +++ b/packages/webapp/src/components/forgot-password-success-page/index.tsx @@ -0,0 +1,36 @@ +import React, { useEffect } from 'react' +import { FormattedMessage } from 'react-intl' + +import {PageContent} from '../../theme/global-style'; + +import Header, { SignInButton } from '../header' +import Footer from '../footer' + +const ForgotPasswordSuccessPage = () => { + useEffect(() => { + document.title = 'Reset Password | WiseMapping'; + }); + + return ( +
+
+
+ +

+ +

+

+ +

+ + +
+
+
+
+ ); +} + +export default ForgotPasswordSuccessPage + + diff --git a/packages/webapp/src/components/form-error-dialog/index.tsx b/packages/webapp/src/components/form-error-dialog/index.tsx index 8997a6fd..7a809de1 100644 --- a/packages/webapp/src/components/form-error-dialog/index.tsx +++ b/packages/webapp/src/components/form-error-dialog/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import React from 'react' import { StyleDiv } from './styled' type FormErrorDialogProps = { diff --git a/packages/webapp/src/components/registration-page/index.tsx b/packages/webapp/src/components/registration-page/index.tsx index c928d5f3..abce977c 100644 --- a/packages/webapp/src/components/registration-page/index.tsx +++ b/packages/webapp/src/components/registration-page/index.tsx @@ -51,7 +51,7 @@ const RegistrationForm = (props: ServiceProps) => {

-
handleSubmit(e)}> + handleSubmit(e)}> setEmail(e.target.value)} placeholder={intl.formatMessage({ id: "registration.email", defaultMessage: "Email" })} required={true} autoComplete="email" /> setFirstname(e.target.value)} placeholder={intl.formatMessage({ id: "registration.firstname", defaultMessage: "First Name" })} required={true} autoComplete="given-name" /> setLastname(e.target.value)} placeholder={intl.formatMessage({ id: "registration.lastname", defaultMessage: "Last Name" })} required={true} autoComplete="family-name" /> @@ -93,6 +93,6 @@ const RegistationPage = (props: ServiceProps) => { ); } -export { RegistationPage } +export default RegistationPage; diff --git a/packages/webapp/src/components/registration-success-page/index.tsx b/packages/webapp/src/components/registration-success-page/index.tsx index 31a836b5..5665e1c5 100644 --- a/packages/webapp/src/components/registration-success-page/index.tsx +++ b/packages/webapp/src/components/registration-success-page/index.tsx @@ -10,7 +10,7 @@ import Footer from '../footer' const RegistrationSuccessPage = () => { useEffect(() => { - document.title = 'Registration | WiseMapping'; + document.title = 'Reset Password | WiseMapping'; }); return ( @@ -19,7 +19,7 @@ const RegistrationSuccessPage = () => {

- +

@@ -33,6 +33,6 @@ const RegistrationSuccessPage = () => { ); } -export { RegistrationSuccessPage } +export default RegistrationSuccessPage; diff --git a/packages/webapp/src/components/submit-button/index.tsx b/packages/webapp/src/components/submit-button/index.tsx index 9d07906f..c28e4612 100644 --- a/packages/webapp/src/components/submit-button/index.tsx +++ b/packages/webapp/src/components/submit-button/index.tsx @@ -9,18 +9,11 @@ const SubmitButton = (props: SubmitButton) => { const [disabled, setDisabled] = useState(props.disabled ? true : false); const intl = useIntl(); - useEffect(() => { - document.title = 'WiseMapping - Login'; - }); - let valueTxt = props.value; if (disabled) { valueTxt = intl.formatMessage({ id: "common.wait", defaultMessage: "Please wait ..." }); } const [value, setValue] = useState(valueTxt); - - console.log(disabled); - console.log(value); return ( ); diff --git a/packages/webapp/src/services/Service.ts b/packages/webapp/src/services/Service.ts index c2bafe2a..07acbbff 100644 --- a/packages/webapp/src/services/Service.ts +++ b/packages/webapp/src/services/Service.ts @@ -6,12 +6,12 @@ type NewUser = { lastname: string; password: string; recaptcha: string | null; - } +} + - interface Service { registerNewUser(user: NewUser, onSuccess: () => void, onError: (msg: string) => void): void; - resetPassword(email:string, onSuccess: () => void, onError: (msg: string) => void): void; + resetPassword(email: string, onSuccess: () => void, onError: (msg: string) => void): void; } class RestService implements Service { @@ -24,7 +24,7 @@ class RestService implements Service { async registerNewUser(user: NewUser, onSuccess: () => void, onError: (msg: string) => void) { - await axios.post(this.baseUrl + '/service/user', + await axios.post(this.baseUrl + '/service/users', JSON.stringify(user), { headers: { 'Content-Type': 'application/json' } } ).then(response => { @@ -32,36 +32,61 @@ class RestService implements Service { onSuccess(); }).catch(error => { const response = error.response; - let msg = ''; - if (response) { - const status: number = response.status; - const data = response.data; - - switch (status) { - case 401: - this.authFailed(); - break; - default: - console.log(data); - // Is a server error ? - if (!data.fieldErrors) { - msg = response.statusText; - } else if (data) { - const fieldsError = data.fieldErrors; - msg = Object.values(fieldsError)[0] as string; - } - } - - } else { - // Network related problem ... - msg = 'Unexpected error. Please, try latter'; - } - onError(msg); + const errorMsg = this.parseResponseOnError(response); + onError(errorMsg); }); } - resetPassword(email:string, onSuccess: () => void, onError: (msg: string) => void): void { - + async resetPassword(email: string, onSuccess: () => void, onError: (msg: string) => void) { + await axios.put(this.baseUrl + '/service/users/resetPassword?email=' + email, + null, + { headers: { 'Content-Type': 'application/json' } } + ).then(response => { + // All was ok, let's sent to success page ... + onSuccess(); + }).catch(error => { + const response = error.response; + const errorMsg = this.parseResponseOnError(response); + onError(errorMsg); + }); + } + + private parseResponseOnError = (response: any) => { + let msg; + if (response) { + const status: number = response.status; + const data = response.data; + console.log(data); + + switch (status) { + case 401: + this.authFailed(); + break; + default: + if (data) { + let errors: string[] = []; + if (data.globalErrors) { + errors = data.globalErrors; + } else if (data.fieldErrors) { + errors = Object.values(data.fieldErrors); + } + + if (errors.length > 0) { + msg = errors[0]; + } + + } else { + msg = response.statusText; + } + } + } + + // Network related problem ... + if (!msg) { + msg = 'Unexpected error. Please, try latter'; + } + + return msg; } } diff --git a/packages/webapp/src/theme/global-style.ts b/packages/webapp/src/theme/global-style.ts index 6f5e2fce..7d604a44 100644 --- a/packages/webapp/src/theme/global-style.ts +++ b/packages/webapp/src/theme/global-style.ts @@ -124,6 +124,10 @@ padding: 20px 10px 20px 10px; background-color: #f9a826; } +& label { + font-size:15px; +} + & input:placeholder { color: grey; } @@ -147,7 +151,7 @@ padding: 20px 10px 20px 10px; } & a { - font-size: 17px; + font-size: 15px; color: #f9a826; } `; diff --git a/packages/webapp/webpack.config.js b/packages/webapp/webpack.config.js index af190a49..62776ef7 100644 --- a/packages/webapp/webpack.config.js +++ b/packages/webapp/webpack.config.js @@ -1,6 +1,5 @@ const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const HtmlWebpackDynamicEnvPlugin = require('html-webpack-dynamic-env-plugin'); const webpack = require('webpack'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); @@ -17,13 +16,11 @@ module.exports = { extensions: ['.ts', '.tsx', '.js', '.jsx'] }, module: { - rules: [ - - { + rules: [{ test: /\.tsx?$/, use: 'ts-loader', exclude: '/node_modules/' - }, , + }, { test: /\.(png|jpe?g|gif|svg)$/, use: [{ @@ -31,7 +28,7 @@ module.exports = { options: { esModule: false, } - }, ], + }] } ] },