| @@ -1,5 +1,5 @@ | |||
| import React from 'react'; | |||
| import { Redirect, Route, Switch } from 'react-router-dom'; | |||
| import React from "react"; | |||
| import { Redirect, Route, Switch } from "react-router-dom"; | |||
| import { | |||
| LOGIN_PAGE, | |||
| @@ -8,33 +8,28 @@ import { | |||
| NOT_FOUND_PAGE, | |||
| ERROR_PAGE, | |||
| BASE_PAGE, | |||
| } from './constants/pages'; | |||
| GOOGLE_AUTH_CALLBACK_PAGE, | |||
| } from "./constants/pages"; | |||
| // import LoginPage from './pages/LoginPage/LoginPage'; | |||
| import LoginPage from './pages/LoginPage/LoginPageMUI'; | |||
| // import HomePage from './pages/HomePage/HomePage'; | |||
| import HomePage from './pages/HomePage/HomePageMUI'; | |||
| import NotFoundPage from './pages/ErrorPages/NotFoundPage'; | |||
| import ErrorPage from './pages/ErrorPages/ErrorPage'; | |||
| // import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage'; | |||
| import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPageMUI'; | |||
| import PrivateRoute from './components/Router/PrivateRoute'; | |||
| import LoginPage from "./pages/LoginPage/LoginPageMUI"; | |||
| import HomePage from "./pages/HomePage/HomePageMUI"; | |||
| import NotFoundPage from "./pages/ErrorPages/NotFoundPage"; | |||
| import ErrorPage from "./pages/ErrorPages/ErrorPage"; | |||
| import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; | |||
| import PrivateRoute from "./components/Router/PrivateRoute"; | |||
| import GoogleAuthCallback from "./pages/GoogleAuthCallback/GoogleAuthCallback"; | |||
| const AppRoutes = () => ( | |||
| <Switch> | |||
| <Route exact path={BASE_PAGE} component={LoginPage} /> | |||
| <Route exact path={LOGIN_PAGE} component={LoginPage} /> | |||
| <Route path={GOOGLE_AUTH_CALLBACK_PAGE} component={GoogleAuthCallback} /> | |||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | |||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | |||
| <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | |||
| <PrivateRoute | |||
| exact | |||
| path={HOME_PAGE} | |||
| component={HomePage} | |||
| /> | |||
| <PrivateRoute exact path={HOME_PAGE} component={HomePage} /> | |||
| <Redirect from="*" to={NOT_FOUND_PAGE} /> | |||
| </Switch> | |||
| ); | |||
| export default AppRoutes; | |||
| @@ -3,4 +3,5 @@ export const LOGIN_PAGE = '/login'; | |||
| export const FORGOT_PASSWORD_PAGE = '/forgot-password'; | |||
| export const HOME_PAGE = '/home'; | |||
| export const ERROR_PAGE = '/error-page'; | |||
| export const NOT_FOUND_PAGE = '/not-found'; | |||
| export const NOT_FOUND_PAGE = '/not-found'; | |||
| export const GOOGLE_AUTH_CALLBACK_PAGE = '/api/auth/google/callback' | |||
| @@ -0,0 +1,61 @@ | |||
| import React, { useEffect } from "react"; | |||
| import { useLocation } from "react-router-dom"; | |||
| import { authScopeSetHelper } from "../../util/helpers/authScopeHelpers"; | |||
| import { addHeaderToken } from "../../request"; | |||
| import { HOME_PAGE } from "../../constants/pages"; | |||
| import { JWT_REFRESH_TOKEN, JWT_TOKEN } from "../../constants/localStorage"; | |||
| import { setUser } from "../../store/actions/user/userActions"; | |||
| import PropTypes from "prop-types"; | |||
| import axios from "axios"; | |||
| function GoogleAuthCallback({ history }) { | |||
| const location = useLocation(); | |||
| const handleApiResponseSuccess = () => { | |||
| history.push({ | |||
| pathname: HOME_PAGE, | |||
| state: { | |||
| from: history.location.pathname, | |||
| }, | |||
| }); | |||
| }; | |||
| useEffect(() => { | |||
| if (!location) { | |||
| return; | |||
| } | |||
| const { search } = location; | |||
| axios({ | |||
| method: "GET", | |||
| url: `http://localhost:1337/api/auth/google/callback?${search}`, | |||
| withCredentials: true, | |||
| }).then((res) => { | |||
| if (res.data?.jwt) { | |||
| const user = res.data?.user; | |||
| authScopeSetHelper(JWT_TOKEN, res.data.jwt); | |||
| authScopeSetHelper(JWT_REFRESH_TOKEN, res.data.refreshToken); | |||
| addHeaderToken(res.data?.jwt); | |||
| setUser(user); | |||
| handleApiResponseSuccess(); | |||
| } | |||
| }); | |||
| }, [location]); | |||
| return ( | |||
| <div> | |||
| <></> | |||
| </div> | |||
| ); | |||
| } | |||
| GoogleAuthCallback.propTypes = { | |||
| history: PropTypes.shape({ | |||
| replace: PropTypes.func, | |||
| push: PropTypes.func, | |||
| location: PropTypes.shape({ | |||
| pathname: PropTypes.string, | |||
| }), | |||
| }), | |||
| }; | |||
| export default GoogleAuthCallback; | |||
| @@ -1,16 +1,28 @@ | |||
| import React from "react"; | |||
| import { Box, Grid } from "@mui/material"; | |||
| import { Box, Button, Grid } from "@mui/material"; | |||
| import Navbar from "../../components/MUI/NavbarComponent"; | |||
| import Modals from "../../components/MUI/Examples/ModalsExample"; | |||
| import DataGrid from "../../components/MUI/Examples/DataGridExample"; | |||
| import PagingSortingFiltering from "../../components/MUI/Examples/PagingSortingFilteringExample"; | |||
| import PagingSortingFilteringServerSide from "../../components/MUI/Examples/PagingSortingFilteringExampleServerSide"; | |||
| import RandomDataProvider from "../../context/RandomDataContext"; | |||
| import { getRequest } from "../../request"; | |||
| const HomePage = () => { | |||
| const getPosts = async () => { | |||
| const {data} = await getRequest("api/posts"); | |||
| console.log(data); | |||
| }; | |||
| return ( | |||
| <> | |||
| <Navbar /> | |||
| <Box textAlign="center" marginTop={5}> | |||
| <Button onClick={getPosts} sx={{ width: "200px" }} variant="outlined"> | |||
| Get Posts | |||
| </Button> | |||
| </Box> | |||
| <Box sx={{ mt: 4, mx: 4 }}> | |||
| <Grid container spacing={2} justifyContent="center"> | |||
| <Grid item xs={12} md={3}> | |||
| @@ -26,11 +26,10 @@ import { Visibility, VisibilityOff } from "@mui/icons-material"; | |||
| import Backdrop from "../../components/MUI/BackdropComponent"; | |||
| import ErrorMessage from "../../components/MUI/ErrorMessageComponent"; | |||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||
| import { | |||
| LOGIN_USER_SCOPE, | |||
| } from "../../store/actions/login/loginActionConstants"; | |||
| import { LOGIN_USER_SCOPE } from "../../store/actions/login/loginActionConstants"; | |||
| import loginValidation from "../../validations/loginValidation"; | |||
| import loginInitialValues from "../../initialValues/loginInitialValues"; | |||
| import GoogleIcon from "@mui/icons-material/Google"; | |||
| const LoginPage = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -41,6 +40,10 @@ const LoginPage = ({ history }) => { | |||
| const handleClickShowPassword = () => setShowPassword(!showPassword); | |||
| const handleMouseDownPassword = () => setShowPassword(!showPassword); | |||
| const handleGoogle = () => { | |||
| window.location = "http://localhost:1337/api/connect/google"; | |||
| }; | |||
| // Clear login errors when user firstly enters the page | |||
| useEffect(() => { | |||
| dispatch(clearLoginErrors()); | |||
| @@ -58,7 +61,7 @@ const LoginPage = ({ history }) => { | |||
| }; | |||
| const handleSubmit = (values) => { | |||
| const { email, password} = values; | |||
| const { email, password } = values; | |||
| dispatch(clearLoginErrors()); | |||
| dispatch( | |||
| fetchUser({ | |||
| @@ -139,6 +142,14 @@ const LoginPage = ({ history }) => { | |||
| > | |||
| {t("login.logIn")} | |||
| </Button> | |||
| <Button | |||
| onClick={handleGoogle} | |||
| startIcon={<GoogleIcon />} | |||
| fullWidth | |||
| variant="outlined" | |||
| > | |||
| Connect with Google | |||
| </Button> | |||
| <Grid container> | |||
| <Grid | |||
| item | |||
| @@ -6,7 +6,7 @@ const request = axios.create({ | |||
| headers: { | |||
| "Content-Type": "application/json", | |||
| }, | |||
| withCredentials: true, | |||
| // withCredentials: true, | |||
| // paramsSerializer: (params) => | |||
| // queryString.stringify(params, { arrayFormat: 'comma' }), | |||
| }); | |||
| @@ -4,8 +4,6 @@ import { JWT_REFRESH_TOKEN, JWT_TOKEN } from "../../constants/localStorage"; | |||
| import { attachBeforeRequestListener } from "../../request/index"; | |||
| import { authScopeStringGetHelper } from "../../util/helpers/authScopeHelpers"; | |||
| import { logoutUser, refreshUserToken } from "../actions/login/loginActions"; | |||
| import { apiDefaultUrl } from "../../request/index"; | |||
| import apiEndpoints from "../../request/apiEndpoints"; | |||
| export const accessTokensMiddlewareInterceptorName = "ACCESS_TOKEN_INTERCEPTOR"; | |||
| @@ -31,7 +29,7 @@ export default ({ dispatch }) => | |||
| // If access token is expired, refresh access token | |||
| if (new Date() > new Date(jwtTokenDecoded.exp * 1000)) { | |||
| const axiosResponse = await axios.post( | |||
| `${apiDefaultUrl}${apiEndpoints.authentications.refreshToken}`, | |||
| 'http://localhost:1337/api/token/refresh', | |||
| { | |||
| refreshToken: refresh, | |||
| }, | |||