From 5502bcd1aefff151da65f13902469ca9c44b4765 Mon Sep 17 00:00:00 2001 From: Chief Bube Date: Mon, 23 Oct 2023 04:24:38 -0700 Subject: [PATCH] added context provider for user profile --- components/Authentication/SignInForm.js | 108 ++++++++++++------------ components/_App/Layout.js | 9 +- components/_App/TopNavbar/Profile.js | 4 + contexts/userProfileContext.js | 38 +++++++++ pages/_app.js | 43 ++++++++-- pages/auth/logout.js | 12 ++- pages/pages/profile.js | 5 ++ services/Fetcher.js | 3 +- styles/globals.css | 4 + 9 files changed, 157 insertions(+), 69 deletions(-) create mode 100644 contexts/userProfileContext.js diff --git a/components/Authentication/SignInForm.js b/components/Authentication/SignInForm.js index 33f7c58..5b666fd 100644 --- a/components/Authentication/SignInForm.js +++ b/components/Authentication/SignInForm.js @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; import { setCookie } from "cookies-next"; -import Link from "next/link"; +import { useSnackbar } from "notistack"; import Grid from "@mui/material/Grid"; import LoadingButton from "@mui/lab/LoadingButton"; import IconButton from "@mui/material/IconButton"; @@ -14,8 +14,12 @@ import Visibility from "@mui/icons-material/Visibility"; import VisibilityOff from "@mui/icons-material/VisibilityOff"; import styles from "./signinform.module.css"; import Fetcher from "services/Fetcher"; +import { useUserProfile } from "contexts/userProfileContext"; const SignInForm = () => { + const { state, dispatch } = useUserProfile(); + + // Define and initialize state variables const [formValues, setFormValues] = useState({ email: "", password: "", @@ -27,55 +31,70 @@ const SignInForm = () => { const [loading, setLoading] = useState(false); const [errMsg, setErrMsg] = useState(""); + // Create instances of external services const api = new Fetcher(); const router = useRouter(); + // Access the Snackbar notification function + const { enqueueSnackbar } = useSnackbar(); + + // Handle changes in the input fields const handleChange = (event) => { setFormValues({ ...formValues, [event.target.name]: event.target.value }); }; - // "use server" + // Handle form submission const handleSubmit = async (event) => { event.preventDefault(); const { email, password } = formValues; - if (email === "" || password === "") { + // Validate the form fields + if (email === "" && password === "") { setErrorHandlers({ ...errorHandlers, email: true, password: true }); + setErrMsg("all fields are required"); setTimeout(() => { setErrorHandlers({ ...errorHandlers, email: false, password: false }); - }, 1500); + setErrMsg(""); + }, 2000); return; } else if (email === "") { setErrorHandlers({ ...errorHandlers, email: true }); + setErrMsg("email field is required"); setTimeout(() => { setErrorHandlers({ ...errorHandlers, email: false }); - }, 1500); + setErrMsg(""); + }, 2000); return; } else if (password === "") { setErrorHandlers({ ...errorHandlers, password: true }); + setErrMsg("password field is required"); setTimeout(() => { setErrorHandlers({ ...errorHandlers, password: false }); - }, 1500); + setErrMsg(""); + }, 2000); return; } + // Initiate the login process setLoading(true); try { + // Prepare the login request data const data = { username: email, password, }; + + // Send the login request to the server const res = await api.login(data); if (res.status === 204 || res.length === 0) { - setErrorHandlers({ ...errorHandlers, email: true, password: true }); - setErrMsg("Wrong Credentials"); - setTimeout(() => { - setErrorHandlers({ ...errorHandlers, email: false, password: false }); - setLoading(false); - setErrMsg(""); - }, 1500); + // Handle login failure + enqueueSnackbar("Wrong Credentials", { + variant: "error", + }); + setLoading(false); + return; } // Store the token in cookies @@ -87,29 +106,45 @@ const SignInForm = () => { expires: expirationDate, httpOnly: true, // Make the cookie accessible only via HTTP (recommended for security) }; + + // Set the login token in a cookie await setCookie("cmc-token", res.token); + + const userProfileData = res.profile; + dispatch({ type: 'SET_USER_PROFILE', payload: userProfileData }); + + enqueueSnackbar("Login Successful", { + variant: "success", + autoHideDuration: 4000, + }); + + // Redirect the user to a new page after successful login router.push("/"); console.log(res); } catch (error) { + // Handle any errors that occur during login setLoading(false); console.log(error); } finally { + // Ensure that the loading indicator is cleared after a short delay setTimeout(() => { setLoading(false); }, 5000); } }; + // Define and initialize the state variable for toggling password visibility const [showPassword, setShowPassword] = useState(false); + // Toggle password visibility const handleTogglePassword = () => { setShowPassword(!showPassword); }; useEffect(() => { - // Prefetch the dashboard + // Prefetch the dashboard page to optimize navigation router.prefetch("/"); }); @@ -142,15 +177,6 @@ const SignInForm = () => { className={styles.favicon} /> - {/* - Sign In{" "} - */} { > - {/* - Email - */} - { - {/* - Password - */} - { }, }} > - - {loading ? "Signing in…" : errMsg ? errMsg : "Sign In"} - + {loading ? "Signing in…" : "Sign In"} diff --git a/components/_App/Layout.js b/components/_App/Layout.js index 1736b2a..9b6e926 100644 --- a/components/_App/Layout.js +++ b/components/_App/Layout.js @@ -6,7 +6,6 @@ import TopNavbar from "@/components/_App/TopNavbar"; import Footer from "@/components/_App/Footer"; import ScrollToTop from "./ScrollToTop"; import ControlPanelModal from "./ControlPanelModal"; -import AuthRoute from "middlewares/AuthRoute"; const Layout = ({ children }) => { const router = useRouter(); @@ -34,9 +33,6 @@ const Layout = ({ children }) => { // console.log("isAuthenticationPage:", isAuthenticationPage, router.pathname); const title = isAuthenticationPage ? "CMC - auth" : "CMC - dashboard"; - const mainWrapper = { - paddingLeft: typeof window !== "undefined" && isAuthenticationPage && "0", - }; return ( <> @@ -46,8 +42,9 @@ const Layout = ({ children }) => {
{!isAuthenticationPage && ( <> diff --git a/components/_App/TopNavbar/Profile.js b/components/_App/TopNavbar/Profile.js index 8c8c93a..4d60705 100644 --- a/components/_App/TopNavbar/Profile.js +++ b/components/_App/TopNavbar/Profile.js @@ -17,8 +17,12 @@ import MailOutlineIcon from "@mui/icons-material/MailOutline"; import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline"; import AttachMoneyIcon from "@mui/icons-material/AttachMoney"; import Logout from "@mui/icons-material/Logout"; +import { useUserProfile } from "contexts/userProfileContext"; const Profile = () => { + const { state } = useUserProfile(); + const userProfile = state.userProfile; + const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); const handleClick = (event) => { diff --git a/contexts/userProfileContext.js b/contexts/userProfileContext.js new file mode 100644 index 0000000..9af0b95 --- /dev/null +++ b/contexts/userProfileContext.js @@ -0,0 +1,38 @@ +// UserProfileContext.js +import { createContext, useContext, useReducer } from "react"; + +// Define the initial state +const initialState = { + userProfile: null, +}; + +// Create the context +const UserProfileContext = createContext(); + +// Create a custom hook for using the context +export const useUserProfile = () => { + return useContext(UserProfileContext); +}; + +// Define a reducer function to update the context state +const userProfileReducer = (state, action) => { + switch (action.type) { + case "SET_USER_PROFILE": + return { ...state, userProfile: action.payload }; + case "CLEAR_USER_PROFILE": + return { ...state, userProfile: null }; + default: + return state; + } +}; + +// Create the UserProfileProvider component +export const UserProfileProvider = ({ children }) => { + const [state, dispatch] = useReducer(userProfileReducer, initialState); + + return ( + + {children} + + ); +}; diff --git a/pages/_app.js b/pages/_app.js index c663c75..2fe7406 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import "../styles/remixicon.css"; import "react-tabs/style/react-tabs.css"; import "swiper/css"; @@ -13,18 +13,51 @@ import "../styles/rtl.css"; import "../styles/dark.css"; // Theme Styles import theme from "../styles/theme"; - +import { SnackbarProvider } from "notistack"; import { ThemeProvider, CssBaseline } from "@mui/material"; import Layout from "@/components/_App/Layout"; +import { UserProfileProvider } from "contexts/userProfileContext"; +import { useRouter } from "next/router"; +import { hasCookie } from "cookies-next"; function MyApp({ Component, pageProps }) { + const router = useRouter(); + + const handlePopState = () => { + // Check if the user is logged in or if you need to redirect them after logout + if (!hasCookie("cmc-token")) { + router.push("/auth/login"); + } + }; + + // Attach the event handler when the component mounts + useEffect(() => { + window.onpopstate = handlePopState; + + // Clean up the event handler when the component unmounts + return () => { + window.onpopstate = null; + }; + }, []); + return ( <> + + {!hasCookie("cmc-token") && "CMC - auth"} + - - - + + + + + + + ); diff --git a/pages/auth/logout.js b/pages/auth/logout.js index 966057f..1aeb13f 100644 --- a/pages/auth/logout.js +++ b/pages/auth/logout.js @@ -1,4 +1,4 @@ -import { useRouter } from 'next/router' +import { useRouter } from "next/router"; import { Typography } from "@mui/material"; import { Box } from "@mui/system"; import Button from "@mui/material/Button"; @@ -6,10 +6,16 @@ import LogoutIcon from "@mui/icons-material/Logout"; import { deleteCookie } from "cookies-next"; export default function Logout() { - const router = useRouter() + const router = useRouter(); const handleLogout = () => { + // Remove the cookie deleteCookie("cmc-token"); - router.push("/auth/login") + + // Use replaceState to replace the current URL with the root URL + window.history.replaceState({}, document.title, window.location.href); + + // Redirect to the login page + router.push("/auth/login"); }; return ( <> diff --git a/pages/pages/profile.js b/pages/pages/profile.js index cb5a6fd..3979430 100644 --- a/pages/pages/profile.js +++ b/pages/pages/profile.js @@ -9,8 +9,13 @@ import ProfileContent from '@/components/Pages/Profile/ProfileContent'; import ImpressionGoalConversions from "@/components/Dashboard/Analytics/ImpressionGoalConversions"; import Link from 'next/link'; import styles from '@/styles/PageTitle.module.css'; +import { useUserProfile } from 'contexts/userProfileContext'; export default function Profile() { + const { state } = useUserProfile(); + const userProfile = state.userProfile; + + console.log(userProfile) return ( <> {/* Page title */} diff --git a/services/Fetcher.js b/services/Fetcher.js index 6e667cc..e4ff8f0 100644 --- a/services/Fetcher.js +++ b/services/Fetcher.js @@ -3,7 +3,8 @@ import Axios from "axios"; class Fetcher { constructor(url) { // this.url = url; - console.log("first request!!!"); + // console.log("first request!!!"); + // return new Response("Working!!!" + url) } // Endpoints Here diff --git a/styles/globals.css b/styles/globals.css index 98296fb..c7991d2 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -804,6 +804,10 @@ img { position: relative; transition: all 0.5s ease-out; } + +.main-wrapper-content.authBox{ + padding-left: 0; +} .main-wrapper-content.active { padding-left: 0; }