From 333ada0a1c606747f8945bfd952d277cd29075b6 Mon Sep 17 00:00:00 2001 From: victorAnumudu Date: Sat, 27 Apr 2024 23:52:11 +0100 Subject: [PATCH] implemented logout --- src/assets/images/logo.png | Bin 0 -> 4382 bytes .../Dashboard/DashboardHomeIntro.tsx | 6 ++- .../LetsGetStated/LetsGetStarted.tsx | 23 +++++++- src/core/models.ts | 11 ++++ src/layouts/DashboardLayout/DashboardAuth.tsx | 49 ++++++++++++++++-- .../DashboardLayout/DashboardLayout.tsx | 1 + src/main.tsx | 7 ++- src/store/UserDetails.ts | 20 +++++++ src/store/store.ts | 9 ++++ 9 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 src/assets/images/logo.png create mode 100644 src/store/UserDetails.ts create mode 100644 src/store/store.ts diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0f4b8fa64dcbe608122d538635c25c99840b2de4 GIT binary patch literal 4382 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 literal 0 HcmV?d00001 diff --git a/src/components/Dashboard/DashboardHomeIntro.tsx b/src/components/Dashboard/DashboardHomeIntro.tsx index 8fa3345..c08bd03 100644 --- a/src/components/Dashboard/DashboardHomeIntro.tsx +++ b/src/components/Dashboard/DashboardHomeIntro.tsx @@ -1,6 +1,7 @@ import React, { FC } from "react"; import NairaBag from "../../assets/images/dashboard/naira-bag.png"; import { Button } from "../"; +import { useSelector } from "react-redux"; export interface DashBoardCardProps { title?: string; @@ -73,11 +74,12 @@ interface DashboardHomeIntroProps { } const DashboardHomeIntro: FC = ({ handleNextStep, step }) => { + const { userDetails } = useSelector((state:any) => state?.userDetails); // CHECKS IF USER Details are avaliable return ( <> {step == 1 ? <> -

Hello, Olanrewaju

+

Hello, {userDetails.firstname}

= ({ handleNextStep, step : <> -

Welcome Back, Olanrewaju

+

Welcome Back, {userDetails.firstname}

{ + const dispatch = useDispatch() const navigate = useNavigate() // const [pinValues, setPinValues] = React.useState({ // bvn: "", @@ -63,6 +67,8 @@ const LetsGetStarted: React.FC = () => { const [requestStatusBVN, setRequestStatusBVN] = React.useState({loading:false, status:undefined, message:''}); + const [requestStatusOTP, setRequestStatusOTP] = React.useState({loading:false, status:undefined, message:''}); + const [bvnIsValid, setBvnIsValid] = React.useState({ verification_id: '', valid: undefined @@ -91,12 +97,26 @@ const LetsGetStarted: React.FC = () => { }; const handleSubmit = (values:any) => { // Function to VERIFY OTP AND LOGIN USER + setRequestStatusOTP({loading:true, status:false, message:''}) // console.log('values', values) verifyOTP({...values, verification_id:bvnIsValid.verification_id}).then(res=>{ - console.log(res.data) + if(!res || !res.data.call_return){ + setRequestStatusOTP({loading:false, status:false, message:'wrong otp'}) + return setTimeout(()=>{ + setRequestStatusOTP({loading:false, status:false, message:''}) + },4000) + } + // console.log(res.data) + localStorage.setItem('token', res.data.token) + localStorage.setItem('uid', res.data.uid) + dispatch(updateUserDetails({ ...res.data })); navigate(RouteHandler.dashboardHome, {replace:true}) }).catch(err => { + setRequestStatusOTP({loading:false, status:false, message:'something went wrong, try again'}) console.log(err) + return setTimeout(()=>{ + setRequestStatusOTP({loading:false, status:false, message:''}) + },4000) }) }; @@ -159,6 +179,7 @@ const LetsGetStarted: React.FC = () => { Enter +

{requestStatusOTP.message}

{bvnIsValid.valid || bvnIsValid.valid == undefined ? (

diff --git a/src/core/models.ts b/src/core/models.ts index 3e8f627..397ea5c 100644 --- a/src/core/models.ts +++ b/src/core/models.ts @@ -4,4 +4,15 @@ export interface RequestStatus { message?:string name?:string data?:{}[] | [any] | {} +} + + +export interface User { + firstname?:string + lastname?:string + last_login?:string + message?:string + token?:string + uid?:string + call_return?:string } \ No newline at end of file diff --git a/src/layouts/DashboardLayout/DashboardAuth.tsx b/src/layouts/DashboardLayout/DashboardAuth.tsx index 7a7bd45..2255169 100644 --- a/src/layouts/DashboardLayout/DashboardAuth.tsx +++ b/src/layouts/DashboardLayout/DashboardAuth.tsx @@ -1,11 +1,52 @@ +import {useState, useEffect} from 'react' import DashboardLayout from "./DashboardLayout"; -import { Outlet } from "react-router-dom"; +import { Outlet, useNavigate } from "react-router-dom"; +import { useSelector, useDispatch } from "react-redux"; +import { RouteHandler } from '../../router/routes'; +import { updateUserDetails } from '../../store/UserDetails'; + +import Logo from '../../assets/images/logo.png' export default function DashboardAuth() { + + const navigate = useNavigate() + const dispatch = useDispatch() + + const { userDetails } = useSelector((state:any) => state?.userDetails); // CHECKS IF USER Details are avaliable + + const [loading, setLoading] = useState(true) + + useEffect(()=>{ + let token = localStorage.getItem('token') + if(!token){ + navigate(RouteHandler.letsGetStarted, {replace:true}) + return + } + const getUserByToken = () => { + let data = {firstname:'firstname', lastname:'lastname', uid:'28273737646466464'} + setTimeout(()=>{ + setLoading(false) + dispatch(updateUserDetails({...data})); + },4000) + } + if(!Object.keys(userDetails).length){ + getUserByToken() + } + },[]) + return ( - - - + <> + {loading && !Object.keys(userDetails).length ? +

+ Logo +

loading...

+
+ : + + + + } + ) } \ No newline at end of file diff --git a/src/layouts/DashboardLayout/DashboardLayout.tsx b/src/layouts/DashboardLayout/DashboardLayout.tsx index b48af3e..af51518 100644 --- a/src/layouts/DashboardLayout/DashboardLayout.tsx +++ b/src/layouts/DashboardLayout/DashboardLayout.tsx @@ -35,6 +35,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) { // }); const logoutUser = () => { + localStorage.clear() navigate(RouteHandler.letsGetStarted, {replace:true}) } diff --git a/src/main.tsx b/src/main.tsx index 345a1ed..6873238 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,10 +4,15 @@ import { BrowserRouter } from "react-router-dom"; import App from "./App.tsx"; import "./index.css"; +import { Provider } from "react-redux"; +import store from "./store/store"; + ReactDOM.createRoot(document.getElementById("root")!).render( - + + + ); diff --git a/src/store/UserDetails.ts b/src/store/UserDetails.ts new file mode 100644 index 0000000..8cb2677 --- /dev/null +++ b/src/store/UserDetails.ts @@ -0,0 +1,20 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + userDetails: {}, +}; + +export const userSlice = createSlice({ + name: "userDetails", + initialState, + reducers: { + updateUserDetails: (state, action) => { + state.userDetails = { ...action.payload }; + }, + }, +}); + +// Action creators are generated for each case reducer function +export const { updateUserDetails } = userSlice.actions; + +export default userSlice.reducer; diff --git a/src/store/store.ts b/src/store/store.ts new file mode 100644 index 0000000..e111aec --- /dev/null +++ b/src/store/store.ts @@ -0,0 +1,9 @@ +import { configureStore } from "@reduxjs/toolkit"; + +import userDetailReducer from "./UserDetails"; + +export default configureStore({ + reducer: { + userDetails: userDetailReducer, + }, +}); -- 2.34.1