| "i18next": "^20.3.1", | "i18next": "^20.3.1", | ||||
| "json-server": "^0.17.0", | "json-server": "^0.17.0", | ||||
| "jsonwebtoken": "^8.5.1", | "jsonwebtoken": "^8.5.1", | ||||
| "jwt-decode": "^3.1.2", | |||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "lodash.isempty": "^4.4.0", | "lodash.isempty": "^4.4.0", | ||||
| "owasp-password-strength-test": "^1.3.0", | "owasp-password-strength-test": "^1.3.0", | ||||
| "safe-buffer": "^5.0.1" | "safe-buffer": "^5.0.1" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/jwt-decode": { | |||||
| "version": "3.1.2", | |||||
| "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", | |||||
| "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||||
| }, | |||||
| "node_modules/keyv": { | "node_modules/keyv": { | ||||
| "version": "3.1.0", | "version": "3.1.0", | ||||
| "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | ||||
| "safe-buffer": "^5.0.1" | "safe-buffer": "^5.0.1" | ||||
| } | } | ||||
| }, | }, | ||||
| "jwt-decode": { | |||||
| "version": "3.1.2", | |||||
| "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", | |||||
| "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||||
| }, | |||||
| "keyv": { | "keyv": { | ||||
| "version": "3.1.0", | "version": "3.1.0", | ||||
| "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", | "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", |
| "i18next": "^20.3.1", | "i18next": "^20.3.1", | ||||
| "json-server": "^0.17.0", | "json-server": "^0.17.0", | ||||
| "jsonwebtoken": "^8.5.1", | "jsonwebtoken": "^8.5.1", | ||||
| "jwt-decode": "^3.1.2", | |||||
| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "lodash.isempty": "^4.4.0", | "lodash.isempty": "^4.4.0", | ||||
| "owasp-password-strength-test": "^1.3.0", | "owasp-password-strength-test": "^1.3.0", |
| Learn how to configure a non-root public URL by running `npm run build`. | Learn how to configure a non-root public URL by running `npm run build`. | ||||
| --> | --> | ||||
| <title>React App</title> | <title>React App</title> | ||||
| <script src="https://accounts.google.com/gsi/client" async defer></script> | |||||
| </head> | </head> | ||||
| <body> | <body> | ||||
| <noscript>You need to enable JavaScript to run this app.</noscript> | <noscript>You need to enable JavaScript to run this app.</noscript> |
| ul { | ul { | ||||
| list-style: none; | list-style: none; | ||||
| padding: 0; | padding: 0; | ||||
| } | |||||
| .S9gUrf-YoZ4jf { | |||||
| @include flex-center; | |||||
| width: 100% !important; | |||||
| overflow: hidden; | |||||
| padding: 0 !important; | |||||
| margin: 0 !important; | |||||
| } | |||||
| .S9gUrf-YoZ4jf > * { | |||||
| margin: auto; | |||||
| padding: 0 !important; | |||||
| margin: 0 !important; | |||||
| } | } |
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import HrLogo from "../../assets/images/hrcenter.png"; | import HrLogo from "../../assets/images/hrcenter.png"; | ||||
| import DiligLogo from "../../assets/images/logo_horizontal_black.png"; | import DiligLogo from "../../assets/images/logo_horizontal_black.png"; | ||||
| import jwt_decode from "jwt-decode"; | |||||
| import googleLogo from "../../assets/images/google1.png"; | import googleLogo from "../../assets/images/google1.png"; | ||||
| import { | import { | ||||
| clearLoginErrors, | clearLoginErrors, | ||||
| fetchUser, | fetchUser, | ||||
| fetchGoogleUser, | |||||
| } from "../../store/actions/login/loginActions"; | } from "../../store/actions/login/loginActions"; | ||||
| import { selectLoginError } from "../../store/selectors/loginSelectors"; | import { selectLoginError } from "../../store/selectors/loginSelectors"; | ||||
| import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../constants/pages"; | import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../constants/pages"; | ||||
| const error = useSelector(selectLoginError); | const error = useSelector(selectLoginError); | ||||
| const [showPassword, setShowPassword] = useState(false); | const [showPassword, setShowPassword] = useState(false); | ||||
| const [isInit, setIsInit] = useState(true); | |||||
| const handleClickShowPassword = () => setShowPassword(!showPassword); | const handleClickShowPassword = () => setShowPassword(!showPassword); | ||||
| const handleMouseDownPassword = () => setShowPassword(!showPassword); | const handleMouseDownPassword = () => setShowPassword(!showPassword); | ||||
| redirectClient(); | redirectClient(); | ||||
| }, [history]); | }, [history]); | ||||
| const handleCallbackResponse = (response) => { | |||||
| const userObject = jwt_decode(response.credential); | |||||
| const user = userObject; | |||||
| const token = response.credential; | |||||
| dispatch(clearLoginErrors()); | |||||
| dispatch( | |||||
| fetchGoogleUser({ | |||||
| user, | |||||
| token, | |||||
| handleApiResponseSuccess, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| const isLoading = useSelector( | const isLoading = useSelector( | ||||
| selectIsLoadingByActionType(LOGIN_USER_LOADING) | selectIsLoadingByActionType(LOGIN_USER_LOADING) | ||||
| ); | ); | ||||
| }; | }; | ||||
| const handleSubmit = (values) => { | const handleSubmit = (values) => { | ||||
| const { username,password } = values; | |||||
| const { username, password } = values; | |||||
| dispatch(clearLoginErrors()); | dispatch(clearLoginErrors()); | ||||
| dispatch( | dispatch( | ||||
| fetchUser({ | fetchUser({ | ||||
| ); | ); | ||||
| }; | }; | ||||
| useEffect(() => { | |||||
| if (isInit) { | |||||
| setIsInit(false); | |||||
| return; | |||||
| } | |||||
| google.accounts.id.initialize({ | |||||
| client_id: | |||||
| "734219382849-nvnulsu7ibfl4bk3n164bgb7c1h5dgca.apps.googleusercontent.com", | |||||
| callback: handleCallbackResponse, | |||||
| }); | |||||
| google.accounts.id.renderButton(document.getElementById("signInDiv"), { | |||||
| theme: "outline", | |||||
| size: "large", | |||||
| width: "250", | |||||
| }); | |||||
| }, [isInit]); | |||||
| // const handleGoogleSubmit = (values) => { | |||||
| // /* global google */ | |||||
| // google.accounts.id.initialize({ | |||||
| // client_id: | |||||
| // "734219382849-nvnulsu7ibfl4bk3n164bgb7c1h5dgca.apps.googleusercontent.com", | |||||
| // callback: handleCallbackResponse, | |||||
| // }); | |||||
| // google.accounts.id.renderButton(document.getElementById("signInDiv"), { | |||||
| // theme: "outline", | |||||
| // size: "large", | |||||
| // }); | |||||
| // }; | |||||
| const formik = useFormik({ | const formik = useFormik({ | ||||
| initialValues: { | initialValues: { | ||||
| username: "", | username: "", | ||||
| <div className="hr-mid">{t("common.or")}</div> | <div className="hr-mid">{t("common.or")}</div> | ||||
| <div className="hr hr-e"></div> | <div className="hr hr-e"></div> | ||||
| </div> | </div> | ||||
| <Button | |||||
| className="c-btn c-btn--gray flex-center" | |||||
| sx={{ width: "100%", mt: 2 }} | |||||
| > | |||||
| <img src={googleLogo} style={{ marginRight: "15px" }} /> | |||||
| <Typography sx={{ m: 0, p: 0 }} variant="buttonText"> | |||||
| {t("login.signInWithGoogle")} | |||||
| </Typography> | |||||
| </Button> | |||||
| <div> | |||||
| {/* <Button | |||||
| className="c-btn c-btn--gray flex-center" | |||||
| sx={{ width: "100%", mt: 2 }} | |||||
| onClick={handleGoogleSubmit} | |||||
| > | |||||
| <img src={googleLogo} style={{ marginRight: "15px" }} /> | |||||
| <Typography sx={{ m: 0, p: 0 }} variant="buttonText"> | |||||
| {t("login.signInWithGoogle")} | |||||
| </Typography> | |||||
| </Button> */} | |||||
| <div id="signInDiv"></div> | |||||
| </div> | |||||
| <div className="flex-center"> | <div className="flex-center"> | ||||
| <img src={DiligLogo} style={{ margin: "70px auto 0px auto" }} /> | <img src={DiligLogo} style={{ margin: "70px auto 0px auto" }} /> | ||||
| </div> | </div> |
| const base = "http://localhost:26081/v1"; | |||||
| export default { | export default { | ||||
| authentications: { | authentications: { | ||||
| login: 'http://localhost:26081/v1/users/authenticate', | |||||
| refreshToken:'http://localhost:26081/v1/users/refresh' | |||||
| login: base + "/users/authenticate", | |||||
| googleLogin: base + "/users/authenticateGoogle", | |||||
| refreshToken: base + "/users/refresh", | |||||
| }, | }, | ||||
| }; | }; |
| export const attemptLogin = (payload) => | export const attemptLogin = (payload) => | ||||
| postRequest(apiEndpoints.authentications.login, payload); | postRequest(apiEndpoints.authentications.login, payload); | ||||
| export const attemptGoogleLogin = (payload) => | |||||
| postRequest(apiEndpoints.authentications.googleLogin, payload); | |||||
| export const updateSecurityAnswer = (payload) => | export const updateSecurityAnswer = (payload) => | ||||
| postRequest(apiEndpoints.authentications.confirmSecurityQuestion, payload); | postRequest(apiEndpoints.authentications.confirmSecurityQuestion, payload); | ||||
| ); | ); | ||||
| export const LOGIN_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | export const LOGIN_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | ||||
| const LOGIN_GOOGLE_USER_SCOPE = 'LOGIN_GOOGLE_USER'; | |||||
| export const LOGIN_GOOGLE_USER_FETCH = createFetchType(LOGIN_GOOGLE_USER_SCOPE); | |||||
| export const LOGIN_GOOGLE_USER_SUCCESS = createSuccessType(LOGIN_GOOGLE_USER_SCOPE); | |||||
| export const LOGIN_GOOGLE_USER_ERROR = createErrorType(LOGIN_GOOGLE_USER_SCOPE); | |||||
| export const CLEAR_LOGIN_GOOGLE_USER_ERROR = createClearType( | |||||
| `${LOGIN_GOOGLE_USER_SCOPE}_ERROR`, | |||||
| ); | |||||
| export const LOGIN_GOOGLE_USER_LOADING = createLoadingType(LOGIN_USER_SCOPE); | |||||
| export const UPDATE_USER_JWT_TOKEN = 'UPDATE_USER_JWT_TOKEN'; | export const UPDATE_USER_JWT_TOKEN = 'UPDATE_USER_JWT_TOKEN'; | ||||
| export const RESET_LOGIN_STATE = 'RESET_LOGIN_STATE'; | export const RESET_LOGIN_STATE = 'RESET_LOGIN_STATE'; |
| LOGIN_USER_ERROR, | LOGIN_USER_ERROR, | ||||
| LOGIN_USER_FETCH, | LOGIN_USER_FETCH, | ||||
| LOGIN_USER_SUCCESS, | LOGIN_USER_SUCCESS, | ||||
| LOGIN_GOOGLE_USER_ERROR, | |||||
| LOGIN_GOOGLE_USER_FETCH, | |||||
| LOGIN_GOOGLE_USER_SUCCESS, | |||||
| LOGOUT_USER, | LOGOUT_USER, | ||||
| RESET_LOGIN_STATE, | RESET_LOGIN_STATE, | ||||
| UPDATE_USER_JWT_TOKEN, | UPDATE_USER_JWT_TOKEN, | ||||
| payload, | payload, | ||||
| }); | }); | ||||
| export const fetchGoogleUser = (payload) => ({ | |||||
| type: LOGIN_GOOGLE_USER_FETCH, | |||||
| payload, | |||||
| }); | |||||
| export const fetchUserSuccess = (payload) => ({ | export const fetchUserSuccess = (payload) => ({ | ||||
| type: LOGIN_USER_SUCCESS, | type: LOGIN_USER_SUCCESS, | ||||
| payload, | payload, | ||||
| }); | }); | ||||
| export const fetchGoogleUserSuccess = (payload) => ({ | |||||
| type: LOGIN_GOOGLE_USER_SUCCESS, | |||||
| payload, | |||||
| }); | |||||
| export const fetchUserError = (payload) => ({ | export const fetchUserError = (payload) => ({ | ||||
| type: LOGIN_USER_ERROR, | type: LOGIN_USER_ERROR, | ||||
| payload, | payload, | ||||
| }); | }); | ||||
| export const fetchGoogleUserError = (payload) => ({ | |||||
| type: LOGIN_GOOGLE_USER_ERROR, | |||||
| payload, | |||||
| }); | |||||
| export const updateUserToken = (payload) => ({ | export const updateUserToken = (payload) => ({ | ||||
| type: UPDATE_USER_JWT_TOKEN, | type: UPDATE_USER_JWT_TOKEN, | ||||
| payload | payload |
| import history from '../utils/history'; | import history from '../utils/history'; | ||||
| import { | import { | ||||
| AUTHENTICATE_USER, | AUTHENTICATE_USER, | ||||
| LOGIN_GOOGLE_USER_FETCH, | |||||
| LOGIN_USER_FETCH, | LOGIN_USER_FETCH, | ||||
| LOGOUT_USER, | LOGOUT_USER, | ||||
| REFRESH_TOKEN, | REFRESH_TOKEN, | ||||
| GENERATE_TOKEN, | GENERATE_TOKEN, | ||||
| } from '../actions/login/loginActionConstants'; | } from '../actions/login/loginActionConstants'; | ||||
| import { | import { | ||||
| attemptGoogleLogin, | |||||
| attemptLogin, | attemptLogin, | ||||
| logoutUserRequest, | logoutUserRequest, | ||||
| refreshTokenRequest, | refreshTokenRequest, | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| function* fetchGoogleUser({ payload }) { | |||||
| try { | |||||
| const { data } = yield call(attemptGoogleLogin, payload); | |||||
| if (data.token) { | |||||
| // const user = jwt.decode(data.token); | |||||
| yield call(authScopeSetHelper, JWT_TOKEN, data.token); | |||||
| yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken); | |||||
| yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.RefreshToken); | |||||
| yield call(addHeaderToken, data.token); | |||||
| yield put(setUser(data)); | |||||
| } | |||||
| yield put(fetchUserSuccess(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* authenticateUser() { | function* authenticateUser() { | ||||
| try { | try { | ||||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | ||||
| export default function* loginSaga() { | export default function* loginSaga() { | ||||
| yield all([ | yield all([ | ||||
| takeLatest(LOGIN_USER_FETCH, fetchUser), | takeLatest(LOGIN_USER_FETCH, fetchUser), | ||||
| takeLatest(LOGIN_GOOGLE_USER_FETCH, fetchGoogleUser), | |||||
| takeLatest(AUTHENTICATE_USER, authenticateUser), | takeLatest(AUTHENTICATE_USER, authenticateUser), | ||||
| takeLatest(LOGOUT_USER, logoutUser), | takeLatest(LOGOUT_USER, logoutUser), | ||||
| takeLatest(REFRESH_TOKEN, refreshToken), | takeLatest(REFRESH_TOKEN, refreshToken), |
| "jwa" "^1.4.1" | "jwa" "^1.4.1" | ||||
| "safe-buffer" "^5.0.1" | "safe-buffer" "^5.0.1" | ||||
| "jwt-decode@^3.1.2": | |||||
| "integrity" "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" | |||||
| "resolved" "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz" | |||||
| "version" "3.1.2" | |||||
| "keyv@^3.0.0": | "keyv@^3.0.0": | ||||
| "integrity" "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==" | "integrity" "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==" | ||||
| "resolved" "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz" | "resolved" "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz" |