Compare commits

...

4 Commits

Author SHA1 Message Date
Ebube ddce27c65a Merge branch 'master' of https://gitlab.chiefsoft.net/WrenchBoard/Users-Wrench into login-dash-test 2023-05-01 12:36:27 +01:00
Ebube 87d1615b73 added header 2023-05-01 12:33:27 +01:00
Ebube 9ef2084956 login dash 2023-05-01 12:21:35 +01:00
ameye 15e6ed3264 Merge branch 'transfer_page_bug' of WrenchBoard/Users-Wrench into master 2023-05-01 10:50:51 +00:00
11 changed files with 147 additions and 88 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ REACT_APP_USERS_ENDPOINT="https://apigate.lotus.g1.wrenchboard.com/svs/user"
#"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser" #"https://devapi.mermsemr.com/en/desktop/api/v2/myfituser"
REACT_APP_SESSION_EXPIRE_MINUTES=300000 REACT_APP_SESSION_EXPIRE_MINUTES=300000
REACT_APP_SESSION_EXPIRE_CHECKER=60000 REACT_APP_SESSION_EXPIRE_CHECKER=300000
REACT_APP_LOGIN_ERROR_TIMEOUT=7000 REACT_APP_LOGIN_ERROR_TIMEOUT=7000
REACT_APP_SIGNUP_ERROR_TIMEOUT=7000 REACT_APP_SIGNUP_ERROR_TIMEOUT=7000
+7 -9
View File
@@ -9,7 +9,13 @@ import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
import { useDispatch, useSelector } from "react-redux";
import {updateUserDetails} from '../../../store/UserDetails'
export default function Login() { export default function Login() {
const dispatch = useDispatch()
const [checked, setValue] = useState(false); const [checked, setValue] = useState(false);
const [loginLoading, setLoginLoading] = useState(false); const [loginLoading, setLoginLoading] = useState(false);
@@ -51,21 +57,13 @@ export default function Login() {
//debugger; //debugger;
// if (email === "support@mermsemr.com") { // if (email === "support@mermsemr.com") {
if (loginResult.data.status > 0 && loginResult.data.internal_return == 100 && loginResult.data.session != '') { // just for a start if (loginResult.data.status > 0 && loginResult.data.internal_return == 100 && loginResult.data.session != '') { // just for a start
localStorage.setItem("email", `${loginResult.data.email}`);
localStorage.setItem("member_id", `${loginResult.data.member_id}`); localStorage.setItem("member_id", `${loginResult.data.member_id}`);
localStorage.setItem("uid", `${loginResult.data.uid}`); localStorage.setItem("uid", `${loginResult.data.uid}`);
localStorage.setItem("session_token", `${loginResult.data.session}`); localStorage.setItem("session_token", `${loginResult.data.session}`);
localStorage.setItem("added", `${loginResult.data.added}`);
localStorage.setItem("city", `${loginResult.data.city}`);
localStorage.setItem("country", `${loginResult.data.country}`);
localStorage.setItem("firstname", `${loginResult.data.firstname}`);
localStorage.setItem("last_login", `${loginResult.data.last_login}`);
localStorage.setItem("lastname", `${loginResult.data.lastname}`);
localStorage.setItem("state", `${loginResult.data.state}`);
localStorage.setItem("zip_code", `${loginResult.data.zip_code}`);
localStorage.setItem("session", `${loginResult.data.session}`); localStorage.setItem("session", `${loginResult.data.session}`);
setLoginLoading(true); setLoginLoading(true);
// userApi.getUserReminders(); //testing // userApi.getUserReminders(); //testing
dispatch(updateUserDetails(loginResult.data))
setTimeout(() => { setTimeout(() => {
navigate("/", { replace: true }); navigate("/", { replace: true });
setLoginLoading(false); setLoginLoading(false);
+31 -39
View File
@@ -1,4 +1,4 @@
import { useState, useLayoutEffect, useCallback } from "react"; import { useState, useEffect, useCallback } from "react";
import { useLocation, Link, useNavigate } from "react-router-dom"; import { useLocation, Link, useNavigate } from "react-router-dom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
@@ -28,34 +28,6 @@ export default function VerifyLink() {
setPassword(e.target.value); setPassword(e.target.value);
}; };
// for verifying the incoming verification link and render the correct component
const verifyEmail = useCallback(async (code) => {
try {
const verifyRes = await userApi.verifyEmail(code);
if (verifyRes.status === 200) {
let { data } = verifyRes;
if (
data &&
data.internal_return >= 0 &&
data.status_text === "Link Verfied"
) {
setPageLoader(false);
} else {
setPageLoader(false);
setLinkSuccess(false);
}
}
} catch (error) {
setPageLoader(false);
setLinkSuccess(false);
throw new Error(error);
}
}, []);
// delay verify requests by 10000ms
const debouncedEmail = debounce(verifyEmail, 1000);
// if verification is okay. set a complete signup form // if verification is okay. set a complete signup form
const completeSignup = async () => { const completeSignup = async () => {
if (email === "" && password === "") { if (email === "" && password === "") {
@@ -85,14 +57,6 @@ export default function VerifyLink() {
localStorage.setItem("email", `${data?.email}`); localStorage.setItem("email", `${data?.email}`);
localStorage.setItem("member_id", `${data?.member_id}`); localStorage.setItem("member_id", `${data?.member_id}`);
localStorage.setItem("session_token", `${data?.session}`); localStorage.setItem("session_token", `${data?.session}`);
localStorage.setItem("added", `${data?.added}`);
localStorage.setItem("city", `${data?.city}`);
localStorage.setItem("country", `${data?.country}`);
localStorage.setItem("firstname", `${data?.firstname}`);
localStorage.setItem("last_login", `${data?.last_login}`);
localStorage.setItem("lastname", `${data?.lastname}`);
localStorage.setItem("state", `${data?.state}`);
localStorage.setItem("zip_code", `${data?.zip_code}`);
localStorage.setItem("session", `${data?.session}`); localStorage.setItem("session", `${data?.session}`);
navigate("/", { replace: true }); navigate("/", { replace: true });
@@ -118,9 +82,37 @@ export default function VerifyLink() {
} }
}; };
useLayoutEffect(() => { // for verifying the incoming verification link and render the correct component
const verifyEmail = useCallback(async (code) => {
try {
const verifyRes = await userApi.verifyEmail(code);
if (verifyRes.status === 200) {
let { data } = verifyRes;
if (
data &&
data.internal_return >= 0 &&
data.status_text === "Link Verfied"
) {
setPageLoader(false);
} else {
setPageLoader(false);
setLinkSuccess(false);
}
}
} catch (error) {
setPageLoader(false);
setLinkSuccess(false);
throw new Error(error);
}
}, []);
// delay verify requests by 10000ms
const debouncedEmail = debounce(verifyEmail, 1000);
useEffect(() => {
debouncedEmail(token); debouncedEmail(token);
}); }, []);
return ( return (
<> <>
+12 -4
View File
@@ -9,6 +9,7 @@ import slider3 from "../../assets/images/slider-3.jpg";
import CountDown from "../Helpers/CountDown"; import CountDown from "../Helpers/CountDown";
import SliderCom from "../Helpers/SliderCom"; import SliderCom from "../Helpers/SliderCom";
import HomeSliders from "./HomeSliders"; import HomeSliders from "./HomeSliders";
import { useSelector } from "react-redux";
export default function Hero({ className }) { export default function Hero({ className }) {
const settings = { const settings = {
@@ -20,6 +21,8 @@ export default function Hero({ className }) {
}; };
const sildeData =null; const sildeData =null;
const [addFavorite, setValue] = useState(false); const [addFavorite, setValue] = useState(false);
const {userDetails} = useSelector((state) => state?.userDetails)
const favoriteHandler = () => { const favoriteHandler = () => {
if (!addFavorite) { if (!addFavorite) {
setValue(true); setValue(true);
@@ -29,6 +32,11 @@ export default function Hero({ className }) {
toast.warn("Remove to Favorite List"); toast.warn("Remove to Favorite List");
} }
}; };
let loginDate = userDetails?.last_login.split(' ')[0]
let {firstname, lastname, email, profile_pic} = userDetails
let userEmail = email.split('@')[0]
return ( return (
<div <div
className={`w-full lg:h-[444px] h-full lg:flex lg:p-8 p-4 justify-between items-center lg:space-x-28 rounded-2xl overflow-hidden ${ className={`w-full lg:h-[444px] h-full lg:flex lg:p-8 p-4 justify-between items-center lg:space-x-28 rounded-2xl overflow-hidden ${
@@ -47,19 +55,19 @@ export default function Hero({ className }) {
Welcome Welcome
</h1> </h1>
<span className="text-[18px] font-thin tracking-wide text-white"> <span className="text-[18px] font-thin tracking-wide text-white">
Last Login : 10-10-2026 Last Login : {loginDate}
</span> </span>
</div> </div>
{/* user */} {/* user */}
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<div className="w-14 h-14 flex justify-center items-center rounded-full overflow-hidden"> <div className="w-14 h-14 flex justify-center items-center rounded-full overflow-hidden">
<img src={heroUser} alt="" /> <img src={profile_pic != '' ? profile_pic : heroUser} alt="" />
</div> </div>
<div> <div>
<p className="text-xl tracking-wide font-bold antise text-white"> <p className="text-xl tracking-wide font-bold antise text-white">
Brokln Simons {`${firstname} ${lastname}`}
</p> </p>
<p className="text-sm tracking-wide text-white">@broklinslam_75</p> <p className="text-sm tracking-wide text-white">@{userEmail}</p>
</div> </div>
</div> </div>
{/* countdown */} {/* countdown */}
+5 -1
View File
@@ -10,6 +10,8 @@ import UpdateTable from "./UpdateTable";
import HomeTaskDisplay from "./HomeTaskDisplay"; import HomeTaskDisplay from "./HomeTaskDisplay";
import UsersService from "../../services/UsersService"; import UsersService from "../../services/UsersService";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import { useSelector } from "react-redux";
export default function Home() { export default function Home() {
const trending = datas.datas; const trending = datas.datas;
@@ -18,10 +20,12 @@ export default function Home() {
const userApi = new usersService(); const userApi = new usersService();
const homeData = userApi.getHomeDate(); const homeData = userApi.getHomeDate();
const {userDetails} = useSelector((state) => state?.userDetails)
return ( return (
<Layout> <Layout>
<div className="home-page-wrapper"> <div className="home-page-wrapper">
<Hero className="mb-10" /> <Hero className="mb-10" data={userDetails} />
{/* <CreateNft /> {/* <CreateNft />
<TrendingSection trending={trending} className="mb-10" />*/} <TrendingSection trending={trending} className="mb-10" />*/}
<HomeTaskDisplay <HomeTaskDisplay
+11 -3
View File
@@ -15,6 +15,7 @@ import usersService from "../../services/UsersService";
import siteLogo from '../../assets/images/wrenchboard.png' import siteLogo from '../../assets/images/wrenchboard.png'
import Flag from '../../assets/images/united-states.svg' import Flag from '../../assets/images/united-states.svg'
import { useSelector } from "react-redux";
export default function Header({ logoutModalHandler, sidebarHandler }) { export default function Header({ logoutModalHandler, sidebarHandler }) {
@@ -24,6 +25,8 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
const [moneyPopup, setPopup] = useToggle(false); const [moneyPopup, setPopup] = useToggle(false);
const [toggleNotification, setToggleNotification] = useToggle(false) const [toggleNotification, setToggleNotification] = useToggle(false)
const darkMode = useContext(DarkModeContext); const darkMode = useContext(DarkModeContext);
const {userDetails} = useSelector((state) => state?.userDetails)
const [myWalletList, setMyWalletList] = useState([]); const [myWalletList, setMyWalletList] = useState([]);
const api = new usersService(); const api = new usersService();
@@ -87,6 +90,11 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
const setNotification = ()=> { const setNotification = ()=> {
setToggleNotification.toggle() setToggleNotification.toggle()
} }
// User Profile
let {firstname, lastname, email, profile_pic} = userDetails
let userEmail = email.split('@')[0]
return ( return (
<> <>
<div className="header-wrapper backdrop-blur-sm bg-[#efedfe5e]/60 dark:bg-transparent w-full h-full flex items-center xl:px-0 md:px-10 px-5"> <div className="header-wrapper backdrop-blur-sm bg-[#efedfe5e]/60 dark:bg-transparent w-full h-full flex items-center xl:px-0 md:px-10 px-5">
@@ -463,17 +471,17 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
{/* profile-image */} {/* profile-image */}
<div className="lg:w-[62px] lg:h-[62px] w-[50px] h-[50px] rounded-full overflow-hidden"> <div className="lg:w-[62px] lg:h-[62px] w-[50px] h-[50px] rounded-full overflow-hidden">
<img <img
src={profileImg} src={profile_pic != '' ? profile_pic : profileImg}
alt="profile" alt="profile"
className="w-full h-full" className="w-full h-full"
/> />
</div> </div>
<div className="lg:block hidden"> <div className="lg:block hidden">
<h1 className="text-xl font-bold text-dark-gray dark:text-white"> <h1 className="text-xl font-bold text-dark-gray dark:text-white">
Brokln Simons {`${firstname} ${lastname}`}
</h1> </h1>
<p className="text-sm text-thin-light-gray"> <p className="text-sm text-thin-light-gray">
@broklinslam_75 @{userEmail}
</p> </p>
</div> </div>
</div> </div>
+3 -3
View File
@@ -22,9 +22,9 @@ export default function Layout({ children }) {
const logOut = () => { const logOut = () => {
localStorage.removeItem("email"); localStorage.removeItem("email");
localStorage.clear(); localStorage.clear();
toast.success("Come Back Soon", { // toast.success("Come Back Soon", {
icon: `🙂`, // icon: `🙂`,
}); // });
navigate("/login", { replace: true }); navigate("/login", { replace: true });
}; };
+2 -2
View File
@@ -1,8 +1,8 @@
import React from 'react' import React from 'react'
function LoadingSpinner({size, color}) { function LoadingSpinner({size, color, height}) {
return ( return (
<div className='flex items-center justify-center'> <div className={`flex items-center justify-center ${height ? height : ''}`}>
<div role="status"> <div role="status">
<svg aria-hidden="true" className={`w-${size} h-${size} text-gray-200 animate-spin dark:text-gray-600 fill-${color}`} viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg aria-hidden="true" className={`w-${size} h-${size} text-gray-200 animate-spin dark:text-gray-600 fill-${color}`} viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/> <path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
+51 -25
View File
@@ -1,38 +1,31 @@
import { useEffect, useState } from "react"; import { useEffect, useState, useCallback } from "react";
import { Navigate, Outlet, useLocation, useNavigate } from "react-router-dom"; import { Navigate, Outlet, useLocation, useNavigate } from "react-router-dom";
import usersService from '../services/UsersService'
import LoadingSpinner from '../components/Spinners/LoadingSpinner'
import WrenchBoard from "../assets/images/wrenchboard.png"
import { useDispatch, useSelector } from "react-redux";
import {updateUserDetails} from '../store/UserDetails'
const AuthRoute = ({ redirectPath = "/login", children }) => { const AuthRoute = ({ redirectPath = "/login", children }) => {
const apiCall = new usersService()
const dispatch = useDispatch()
const [lastActivityTime, setLastActivityTime] = useState(Date.now()); const [lastActivityTime, setLastActivityTime] = useState(Date.now());
const isLogin = localStorage.getItem("email"); let [isLogin, setIsLogin] = useState({loading: true, status: false})
const navigate = useNavigate(); const navigate = useNavigate();
const { pathname } = useLocation();
//Removing Data stored at localStorage after session expires //Removing Data stored at localStorage after session expires
const expireSession = () => { const expireSession = () => {
localStorage.removeItem("email");
localStorage.removeItem('session_token'); localStorage.removeItem('session_token');
localStorage.removeItem('firstname');
localStorage.removeItem('member_id'); localStorage.removeItem('member_id');
localStorage.removeItem('lastname');
localStorage.removeItem('state');
localStorage.removeItem('last_login');
localStorage.removeItem('uid'); localStorage.removeItem('uid');
localStorage.removeItem('session'); localStorage.removeItem('session');
localStorage.removeItem('city');
localStorage.removeItem('country');
localStorage.removeItem('loglevel');
localStorage.removeItem('zip_code');
localStorage.removeItem('added');
navigate("/login", { replace: true }); // redirects user to login page after session expires navigate("/login", { replace: true }); // redirects user to login page after session expires
}; };
const checkInactivity = setInterval(() => {
if (Date.now() - lastActivityTime > process.env.REACT_APP_SESSION_EXPIRE_MINUTES) {
expireSession()
}
}, process.env.REACT_APP_SESSION_EXPIRE_CHECKER) // Checks for inactivity every minute
// Reset last activity time on user input // Reset last activity time on user input
const resetTime = () => { const resetTime = () => {
setLastActivityTime(Date.now()); setLastActivityTime(Date.now());
@@ -40,19 +33,52 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
window.addEventListener('mousemove', resetTime) window.addEventListener('mousemove', resetTime)
window.addEventListener('keydown', resetTime) window.addEventListener('keydown', resetTime)
const loadProfile = ()=>{ // function to load user profile
apiCall.loadProfile().then((res)=>{
if(res.data.internal_return < 0){
setIsLogin({loading: false, status: false})
return
}
dispatch(updateUserDetails(res.data))
setIsLogin({loading: false, status: true})
}).catch(error =>{
setIsLogin({loading: false, status: false})
})
}
const getProfile = useCallback(()=>{
loadProfile() // API CALL TO GET USER PROFILE
}, [])
useEffect(() => { useEffect(() => {
getProfile()
const checkInactivity = setInterval(() => {
if (Date.now() - lastActivityTime > process.env.REACT_APP_SESSION_EXPIRE_MINUTES) {
expireSession()
}
}, process.env.REACT_APP_SESSION_EXPIRE_CHECKER) // Checks for inactivity every minute
// cleaning up listeners // cleaning up listeners
return () => { return () => {
clearInterval(checkInactivity) clearInterval(checkInactivity)
window.removeEventListener('mousemove', resetTime) window.removeEventListener('mousemove', resetTime)
window.removeEventListener('keydown', resetTime) window.removeEventListener('keydown', resetTime)
} }
}, [pathname, lastActivityTime]) }, [lastActivityTime])
if (!isLogin) { return (
return <Navigate to={redirectPath} replace />; isLogin.loading ?
} <LoadingSpinner size='32' color='sky-blue' height='h-screen' />
return children || <Outlet />; // Stills needs fixing
// <div className="h-screen m-auto">
// <img src={WrenchBoard} alt="wrenchboard" className="h-10" />
// </div>
:
!isLogin.status ?
<Navigate to={redirectPath} replace />
:
(children || <Outlet />)
)
}; };
export default AuthRoute; export default AuthRoute;
+20
View File
@@ -0,0 +1,20 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
userDetails: {}
};
export const userSlice = createSlice({
name: "userDetails",
initialState,
reducers: {
updateUserDetails: (state,payload) => {
state.userDetails = {...payload.payload}
},
},
});
// Action creators are generated for each case reducer function
export const { updateUserDetails } = userSlice.actions;
export default userSlice.reducer;
+4 -1
View File
@@ -1,8 +1,11 @@
import { configureStore } from "@reduxjs/toolkit"; import { configureStore } from "@reduxjs/toolkit";
import drawerReducer from "./drawer"; import drawerReducer from "./drawer";
import userDetailReducer from "./UserDetails";
export default configureStore({ export default configureStore({
reducer: { reducer: {
drawer: drawerReducer, drawer: drawerReducer,
userDetails: userDetailReducer,
}, },
}); });