Sfoglia il codice sorgente

added forget password and reset password

pull/21/head
Safet Purkovic 3 anni fa
parent
commit
86c5714a2b

+ 6
- 0
src/AppRoutes.js Vedi File

HOME_PAGE, HOME_PAGE,
ADS_PAGE, ADS_PAGE,
FORGOT_PASSWORD_PAGE, FORGOT_PASSWORD_PAGE,
FORGOT_PASSWORD_CONFIRMATION_PAGE,
NOT_FOUND_PAGE, NOT_FOUND_PAGE,
ERROR_PAGE, ERROR_PAGE,
BASE_PAGE, BASE_PAGE,
RESET_PASSWORD_PAGE
} from "./constants/pages"; } from "./constants/pages";


// import LoginPage from './pages/LoginPage/LoginPage'; // import LoginPage from './pages/LoginPage/LoginPage';
// import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage'; // import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage';
import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI";
import PrivateRoute from "./components/Router/PrivateRoute"; import PrivateRoute from "./components/Router/PrivateRoute";
import ForgotPasswordConfirmationPage from "./pages/ForgotPasswordPage/ForgotPasswordConfirmationPageMUI";
import ResetPasswordPage from "./pages/ForgotPasswordPage/ResetPasswordPageMUI";


const AppRoutes = () => ( const AppRoutes = () => (
<Switch> <Switch>
<Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> <Route path={NOT_FOUND_PAGE} component={NotFoundPage} />
<Route path={ERROR_PAGE} component={ErrorPage} /> <Route path={ERROR_PAGE} component={ErrorPage} />
<Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />
<Route path={FORGOT_PASSWORD_CONFIRMATION_PAGE} component={ForgotPasswordConfirmationPage} />
<Route path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} />
<PrivateRoute exact path={HOME_PAGE} component={HomePage} /> <PrivateRoute exact path={HOME_PAGE} component={HomePage} />
<PrivateRoute exact path={ADS_PAGE} component={AdsPage} /> <PrivateRoute exact path={ADS_PAGE} component={AdsPage} />
<Redirect from="*" to={NOT_FOUND_PAGE} /> <Redirect from="*" to={NOT_FOUND_PAGE} />

+ 3
- 1
src/constants/pages.js Vedi File

export const HOME_PAGE = '/home'; export const HOME_PAGE = '/home';
export const ADS_PAGE = '/ads'; export const ADS_PAGE = '/ads';
export const ERROR_PAGE = '/error-page'; export const ERROR_PAGE = '/error-page';
export const NOT_FOUND_PAGE = '/not-found';
export const NOT_FOUND_PAGE = '/not-found';
export const FORGOT_PASSWORD_CONFIRMATION_PAGE = '/forgot-password-confirmation';
export const RESET_PASSWORD_PAGE = '/reset-password';

+ 5
- 0
src/i18n/resources/rs.js Vedi File

// continue: 'Continue', // continue: 'Continue',
labelUsername: 'Korisničko ime', labelUsername: 'Korisničko ime',
labelPassword: 'Šifra', labelPassword: 'Šifra',
labelConfirmPassword: 'Ponovljena šifra',
or: 'ili', or: 'ili',
// next: 'Next', // next: 'Next',
// nextPage: 'Next page', // nextPage: 'Next page',
usernameRequired: 'Potrebno je uneti korisničko ime.', usernameRequired: 'Potrebno je uneti korisničko ime.',
passwordRequired: 'Potrebno je uneti šifru.', passwordRequired: 'Potrebno je uneti šifru.',
forgotYourPassword: 'Zaboravio/la si šifru?', forgotYourPassword: 'Zaboravio/la si šifru?',
forgotYourPasswordHelpText: 'Samo unesi e-mail adresu svog HR Center profila.',
forgotYourPasswordButton: 'POŠALJI',
forgotYourPasswordBackLink: 'Nazad na Login',
forgotYourPasswordConfimation: 'Proveri email adresu da bi resetovao šifru.',
// _useDifferentEmail: 'Use different email address or username', // _useDifferentEmail: 'Use different email address or username',
// get useDifferentEmail() { // get useDifferentEmail() {
// return this._useDifferentEmail; // return this._useDifferentEmail;

+ 66
- 0
src/pages/ForgotPasswordPage/ForgotPasswordConfirmationPageMUI.js Vedi File

import React from 'react';
import { useTranslation } from 'react-i18next';
import HrLogo from "../../assets/images/hrcenter.png";
import {
Box,
Container,
Typography,
Link,
Grid,
} from '@mui/material';
import Backdrop from '../../components/MUI/BackdropComponent';
import { LOGIN_PAGE } from '../../constants/pages';
import { NavLink } from 'react-router-dom';



const ForgotPasswordConfirmationPage = () => {
const { t } = useTranslation();

return (
<Container
component="main"
maxWidth="xl"
className="c-login-container"
fullwidth="true">
<div className="l-t-rectangle"></div>
<div className="r-b-rectangle"></div>
<Box
sx={{
marginTop: 2,
width: 350,
height: 684,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<img src={HrLogo} className="login-logo" />
<Typography variant="h5" sx={{ m: 2, mt: 3 }}>
{t("login.forgotYourPassword")}
</Typography>
<Typography variant="p">
{t("login.forgotYourPasswordConfimation")}
</Typography>
<Box
component="form"
sx={{ position: 'relative', mt: 1, p: 1 }}
>
<Backdrop position="absolute" isLoading={false} />
<Grid container justifyContent="center">
<Link
to={LOGIN_PAGE}
component={NavLink}
variant="body2"
underline="hover"
>
{t('login.forgotYourPasswordBackLink')}
</Link>
</Grid>
</Box>
</Box>
</Container>
);
};

export default ForgotPasswordConfirmationPage;

+ 56
- 12
src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js Vedi File

import React from 'react'; import React from 'react';
import PropTypes from "prop-types";
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDispatch } from "react-redux";
import * as Yup from 'yup'; import * as Yup from 'yup';
import HrLogo from "../../assets/images/hrcenter.png";
import i18next from 'i18next'; import i18next from 'i18next';
import { import {
Box, Box,
Grid, Grid,
} from '@mui/material'; } from '@mui/material';
import Backdrop from '../../components/MUI/BackdropComponent'; import Backdrop from '../../components/MUI/BackdropComponent';
import { LOGIN_PAGE } from '../../constants/pages';
import { FORGOT_PASSWORD_CONFIRMATION_PAGE, LOGIN_PAGE } from '../../constants/pages';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { forgetPassword } from '../../store/actions/login/loginActions';



const forgotPasswordValidationSchema = Yup.object().shape({ const forgotPasswordValidationSchema = Yup.object().shape({
email: Yup.string() email: Yup.string()
.email(i18next.t('forgotPassword.emailFormat')), .email(i18next.t('forgotPassword.emailFormat')),
}); });


const ForgotPasswordPage = () => {
const ForgotPasswordPage = ({ history }) => {
const dispatch = useDispatch();
const { t } = useTranslation(); const { t } = useTranslation();


const handleSubmit = (values) => { const handleSubmit = (values) => {
console.log('Values', values);
const email = values.email;
dispatch(
forgetPassword({
email,
handleApiResponseSuccess,
})
);
};

const handleApiResponseSuccess = () => {
history.push({
pathname: FORGOT_PASSWORD_CONFIRMATION_PAGE,
state: {
from: history.location.pathname,
},
});
}; };


const formik = useFormik({ const formik = useFormik({
}); });


return ( return (
<Container component="main" maxWidth="md">
<Container
component="main"
maxWidth="xl"
className="c-login-container"
fullwidth="true">
<div className="l-t-rectangle"></div>
<div className="r-b-rectangle"></div>
<Box <Box
sx={{ sx={{
marginTop: 32,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
marginTop: 2,
width: 350,
height: 684,
display: "flex",
flexDirection: "column",
alignItems: "center",
}} }}
> >
<Typography component="h1" variant="h5">
{t('forgotPassword.title')}
<img src={HrLogo} className="login-logo" />
<Typography variant="h5" sx={{ m: 2, mt: 3 }}>
{t("login.forgotYourPassword")}
</Typography>
<Typography variant="p">
{t("login.forgotYourPasswordHelpText")}
</Typography> </Typography>
<Box <Box
component="form" component="form"
variant="contained" variant="contained"
sx={{ mt: 3, mb: 2 }} sx={{ mt: 3, mb: 2 }}
fullWidth fullWidth
className="c-btn c-btn--primary"
> >
{t('forgotPassword.label')}
{t('login.forgotYourPasswordButton')}
</Button> </Button>
<Grid container justifyContent="center"> <Grid container justifyContent="center">
<Link <Link
variant="body2" variant="body2"
underline="hover" underline="hover"
> >
{t('common.back')}
{t('login.forgotYourPasswordBackLink')}
</Link> </Link>
</Grid> </Grid>
</Box> </Box>
); );
}; };


ForgotPasswordPage.propTypes = {
history: PropTypes.shape({
replace: PropTypes.func,
push: PropTypes.func,
location: PropTypes.shape({
pathname: PropTypes.string,
}),
}),
}

export default ForgotPasswordPage; export default ForgotPasswordPage;

+ 210
- 0
src/pages/ForgotPasswordPage/ResetPasswordPageMUI.js Vedi File

import React, { useState } from 'react';
import PropTypes from "prop-types";
import { useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import { useDispatch } from "react-redux";
// import * as Yup from 'yup';
// import i18next from 'i18next';
import HrLogo from "../../assets/images/hrcenter.png";
import {
Box,
Container,
Typography,
Button,
InputAdornment,
IconButton,
TextField,
Link,
Grid,
} from '@mui/material';
import { Visibility, VisibilityOff } from "@mui/icons-material";
import Backdrop from '../../components/MUI/BackdropComponent';
import { LOGIN_PAGE } from '../../constants/pages';
import { NavLink } from 'react-router-dom';
import { resetPassword } from '../../store/actions/login/loginActions';

// const resetPasswordValidationSchema = Yup.object().shape({
// email: Yup.string()
// .required(i18next.t('forgotPassword.emailRequired'))
// .email(i18next.t('forgotPassword.emailFormat')),
// });
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
// console.log(query)//"app=article&act=news_content&aid=160990"
var vars = query.split("&");
// console.log(vars) //[ 'app=article', 'act=news_content', 'aid=160990' ]
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
// console.log(pair)//[ 'app', 'article' ][ 'act', 'news_content' ][ 'aid', '160990' ]
if (pair[0] == variable) { return pair[1]; }
}
return (false);
}
const ResetPasswordPage = ({ history }) => {
const dispatch = useDispatch();
const { t } = useTranslation();

const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const handleClickShowPassword = () => setShowPassword(!showPassword);
const handleMouseDownPassword = () => setShowPassword(!showPassword);

const handleClickShowConfirmPassword = () => setShowConfirmPassword(!showConfirmPassword);
const handleMouseDownConfirmPassword = () => setShowConfirmPassword(!showConfirmPassword);


const handleSubmit = (values) => {
const password = values.password;
const confirmPassword = values.confirmPassword;
console.log(password);
console.log(confirmPassword);
if (password === confirmPassword)
{
const code = getQueryVariable('token'),
email = getQueryVariable('email');
dispatch(
resetPassword({
code,
email,
password,
handleApiResponseSuccess,
})
);
}
};

const handleApiResponseSuccess = () => {
history.push({
pathname: LOGIN_PAGE,
state: {
from: history.location.pathname,
},
});
};

const formik = useFormik({
initialValues: {
password: '',
confirmPassword: '',
},
// validationSchema: resetPasswordValidationSchema,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

return (
<Container
component="main"
maxWidth="xl"
className="c-login-container"
fullwidth="true">
<div className="l-t-rectangle"></div>
<div className="r-b-rectangle"></div>
<Box
sx={{
marginTop: 2,
width: 350,
height: 684,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<img src={HrLogo} className="login-logo" />
<Typography variant="h5" sx={{ m: 2, mt: 3 }}>
{t("login.forgotYourPassword")}
</Typography>
<Typography variant="p">
{t("login.forgotYourPasswordHelpText")}
</Typography>
<Box
component="form"
onSubmit={formik.handleSubmit}
sx={{ position: 'relative', mt: 1, p: 1 }}
>
<Backdrop position="absolute" isLoading={false} />
<TextField
className="rounded-input"
name="password"
label={t("common.labelPassword")}
margin="normal"
type={showPassword ? "text" : "password"}
value={formik.values.password}
onChange={formik.handleChange}
error={formik.touched.password && Boolean(formik.errors.password)}
helperText={formik.touched.password && formik.errors.password}
fullWidth
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
}}
/>
<TextField
className="rounded-input"
name="confirmPassword"
label={t("common.labelConfirmPassword")}
margin="normal"
type={showConfirmPassword ? "text" : "password"}
value={formik.values.confirmPassword}
onChange={formik.handleChange}
error={formik.touched.confirmPassword && Boolean(formik.errors.confirmPassword)}
helperText={formik.touched.confirmPassword && formik.errors.confirmPassword}
fullWidth
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton
onClick={handleClickShowConfirmPassword}
onMouseDown={handleMouseDownConfirmPassword}
>
{showConfirmPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
}}
/>
<Button
type="submit"
variant="contained"
sx={{ mt: 3, mb: 2 }}
fullWidth
className="c-btn c-btn--primary"
>
{t('login.forgotYourPasswordButton')}
</Button>
<Grid container justifyContent="center">
<Link
to={LOGIN_PAGE}
component={NavLink}
variant="body2"
underline="hover"
>
{t('login.forgotYourPasswordBackLink')}
</Link>
</Grid>
</Box>
</Box>
</Container>
);
};

ResetPasswordPage.propTypes = {
history: PropTypes.shape({
replace: PropTypes.func,
push: PropTypes.func,
location: PropTypes.shape({
pathname: PropTypes.string,
}),
}),
}

export default ResetPasswordPage;

+ 2
- 0
src/request/apiEndpoints.js Vedi File

googleLogin: base + "/users/authenticateGoogle", googleLogin: base + "/users/authenticateGoogle",
refreshToken: base + "/users/refresh", refreshToken: base + "/users/refresh",
logout: base + "/users/logout?userId={userId}", logout: base + "/users/logout?userId={userId}",
forgetPassword: base + "/users/ForgotPassword",
resetPassword: base + "/users/RessetPassword",
}, },
}; };

+ 6
- 0
src/request/loginRequest.js Vedi File

export const attemptLogin = (payload) => export const attemptLogin = (payload) =>
postRequest(apiEndpoints.authentications.login, payload); postRequest(apiEndpoints.authentications.login, payload);


export const forgetPasswordEmailSend = (payload) =>
getRequest(apiEndpoints.authentications.forgetPassword, payload)

export const sendResetPassword = (payload) =>
postRequest(apiEndpoints.authentications.resetPassword, payload);

export const attemptGoogleLogin = (payload) => export const attemptGoogleLogin = (payload) =>
postRequest(apiEndpoints.authentications.googleLogin, payload); postRequest(apiEndpoints.authentications.googleLogin, payload);



+ 10
- 0
src/store/actions/login/loginActionConstants.js Vedi File

export const GENERATE_TOKEN = createSubmitType(GENERATE_TOKEN_SCOPE); export const GENERATE_TOKEN = createSubmitType(GENERATE_TOKEN_SCOPE);
export const GENERATE_TOKEN_SUCCESS = createSuccessType(GENERATE_TOKEN_SCOPE); export const GENERATE_TOKEN_SUCCESS = createSuccessType(GENERATE_TOKEN_SCOPE);
export const GENERATE_TOKEN_ERROR = createErrorType(GENERATE_TOKEN_SCOPE); export const GENERATE_TOKEN_ERROR = createErrorType(GENERATE_TOKEN_SCOPE);

const FORGOT_PASSWORD_SCOPE = 'FORGOT_PASSWORD';
export const FORGOT_PASSWORD = createSubmitType(FORGOT_PASSWORD_SCOPE);
export const FORGOT_PASSWORD_SUCCESS = createSuccessType(FORGOT_PASSWORD_SCOPE);
export const FORGOT_PASSWORD_ERROR = createErrorType(FORGOT_PASSWORD_SCOPE);

const RESET_PASSWORD_SCOPE = 'RESET_PASSWORD';
export const RESET_PASSWORD = createSubmitType(RESET_PASSWORD_SCOPE);
export const RESET_PASSWORD_SUCCESS = createSuccessType(RESET_PASSWORD_SCOPE);
export const RESET_PASSWORD_ERROR = createErrorType(RESET_PASSWORD_SCOPE);

+ 39
- 0
src/store/actions/login/loginActions.js Vedi File

GENERATE_TOKEN, GENERATE_TOKEN,
GENERATE_TOKEN_SUCCESS, GENERATE_TOKEN_SUCCESS,
GENERATE_TOKEN_ERROR, GENERATE_TOKEN_ERROR,
FORGOT_PASSWORD,
FORGOT_PASSWORD_SUCCESS,
FORGOT_PASSWORD_ERROR,
RESET_PASSWORD,
RESET_PASSWORD_SUCCESS,
RESET_PASSWORD_ERROR,
} from './loginActionConstants'; } from './loginActionConstants';




type: GENERATE_TOKEN_ERROR, type: GENERATE_TOKEN_ERROR,
payload, payload,
}); });


export const forgetPassword = (payload) => ({
type: FORGOT_PASSWORD,
payload,
});

export const forgetPasswordSuccess = (payload) => ({
type: FORGOT_PASSWORD_SUCCESS,
payload,
});

export const forgetPasswordError = (payload) => ({
type: FORGOT_PASSWORD_ERROR,
payload,
});

export const resetPassword = (payload) => ({
type: RESET_PASSWORD,
payload,
});

export const resetPasswordSuccess = (payload) => ({
type: RESET_PASSWORD_SUCCESS,
payload,
});

export const resetPasswordError = (payload) => ({
type: RESET_PASSWORD_ERROR,
payload,
});



+ 46
- 0
src/store/saga/loginSaga.js Vedi File

LOGOUT_USER, LOGOUT_USER,
REFRESH_TOKEN, REFRESH_TOKEN,
GENERATE_TOKEN, GENERATE_TOKEN,
FORGOT_PASSWORD,
RESET_PASSWORD
} from '../actions/login/loginActionConstants'; } from '../actions/login/loginActionConstants';
import { import {
attemptGoogleLogin, attemptGoogleLogin,
logoutUserRequest, logoutUserRequest,
refreshTokenRequest, refreshTokenRequest,
generateTokenRequest, generateTokenRequest,
forgetPasswordEmailSend,
sendResetPassword
} from '../../request/loginRequest'; } from '../../request/loginRequest';
import { import {
fetchUserError, fetchUserError,
fetchUserSuccess, fetchUserSuccess,
forgetPasswordSuccess,
updateUserToken, updateUserToken,
} from '../actions/login/loginActions'; } from '../actions/login/loginActions';
import { LOGIN_PAGE,BASE_PAGE } from '../../constants/pages'; import { LOGIN_PAGE,BASE_PAGE } from '../../constants/pages';
} }
} }
} }

function* forgetPassword({ payload }) {
try {
const { data } = yield call(forgetPasswordEmailSend, payload);
yield put(forgetPasswordSuccess(data));
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
} catch (e) {
if (e.response && e.response.data) {
if (payload.handleApiResponseFailed) {
yield call(payload.handleApiResponseFailed);
}
const errorMessage = yield call(rejectErrorCodeHelper, e);
yield put(fetchUserError(errorMessage));
}
}
}

function* resetPassword({ payload }) {
try {
console.log(payload)
const { data } = yield call(sendResetPassword, payload);
console.log(data);
yield put(forgetPasswordSuccess(data));
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
} catch (e) {
if (e.response && e.response.data) {
if (payload.handleApiResponseFailed) {
yield call(payload.handleApiResponseFailed);
}
const errorMessage = yield call(rejectErrorCodeHelper, e);
yield put(fetchUserError(errorMessage));
}
}
}

function* fetchGoogleUser({ payload }) { function* fetchGoogleUser({ payload }) {
try { try {
const { data } = yield call(attemptGoogleLogin, payload); const { data } = yield call(attemptGoogleLogin, payload);
export default function* loginSaga() { export default function* loginSaga() {
yield all([ yield all([
takeLatest(LOGIN_USER_FETCH, fetchUser), takeLatest(LOGIN_USER_FETCH, fetchUser),
takeLatest(FORGOT_PASSWORD, forgetPassword),
takeLatest(RESET_PASSWORD, resetPassword),
takeLatest(LOGIN_GOOGLE_USER_FETCH, fetchGoogleUser), takeLatest(LOGIN_GOOGLE_USER_FETCH, fetchGoogleUser),
takeLatest(AUTHENTICATE_USER, authenticateUser), takeLatest(AUTHENTICATE_USER, authenticateUser),
takeLatest(LOGOUT_USER, logoutUser), takeLatest(LOGOUT_USER, logoutUser),

Loading…
Annulla
Salva