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"
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_SIGNUP_ERROR_TIMEOUT=7000
+7 -9
View File
@@ -9,7 +9,13 @@ import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout";
import { useDispatch, useSelector } from "react-redux";
import {updateUserDetails} from '../../../store/UserDetails'
export default function Login() {
const dispatch = useDispatch()
const [checked, setValue] = useState(false);
const [loginLoading, setLoginLoading] = useState(false);
@@ -51,21 +57,13 @@ export default function Login() {
//debugger;
// if (email === "support@mermsemr.com") {
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("uid", `${loginResult.data.uid}`);
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}`);
setLoginLoading(true);
// userApi.getUserReminders(); //testing
dispatch(updateUserDetails(loginResult.data))
setTimeout(() => {
navigate("/", { replace: true });
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 AuthLayout from "../AuthLayout";
import InputCom from "../../Helpers/Inputs/InputCom";
@@ -28,34 +28,6 @@ export default function VerifyLink() {
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
const completeSignup = async () => {
if (email === "" && password === "") {
@@ -85,14 +57,6 @@ export default function VerifyLink() {
localStorage.setItem("email", `${data?.email}`);
localStorage.setItem("member_id", `${data?.member_id}`);
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}`);
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);
});
}, []);
return (
<>
+12 -4
View File
@@ -9,6 +9,7 @@ import slider3 from "../../assets/images/slider-3.jpg";
import CountDown from "../Helpers/CountDown";
import SliderCom from "../Helpers/SliderCom";
import HomeSliders from "./HomeSliders";
import { useSelector } from "react-redux";
export default function Hero({ className }) {
const settings = {
@@ -20,6 +21,8 @@ export default function Hero({ className }) {
};
const sildeData =null;
const [addFavorite, setValue] = useState(false);
const {userDetails} = useSelector((state) => state?.userDetails)
const favoriteHandler = () => {
if (!addFavorite) {
setValue(true);
@@ -29,6 +32,11 @@ export default function Hero({ className }) {
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 (
<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 ${
@@ -47,19 +55,19 @@ export default function Hero({ className }) {
Welcome
</h1>
<span className="text-[18px] font-thin tracking-wide text-white">
Last Login : 10-10-2026
Last Login : {loginDate}
</span>
</div>
{/* user */}
<div className="flex items-center space-x-3">
<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>
<p className="text-xl tracking-wide font-bold antise text-white">
Brokln Simons
{`${firstname} ${lastname}`}
</p>
<p className="text-sm tracking-wide text-white">@broklinslam_75</p>
<p className="text-sm tracking-wide text-white">@{userEmail}</p>
</div>
</div>
{/* countdown */}
+5 -1
View File
@@ -10,6 +10,8 @@ import UpdateTable from "./UpdateTable";
import HomeTaskDisplay from "./HomeTaskDisplay";
import UsersService from "../../services/UsersService";
import usersService from "../../services/UsersService";
import { useSelector } from "react-redux";
export default function Home() {
const trending = datas.datas;
@@ -18,10 +20,12 @@ export default function Home() {
const userApi = new usersService();
const homeData = userApi.getHomeDate();
const {userDetails} = useSelector((state) => state?.userDetails)
return (
<Layout>
<div className="home-page-wrapper">
<Hero className="mb-10" />
<Hero className="mb-10" data={userDetails} />
{/* <CreateNft />
<TrendingSection trending={trending} className="mb-10" />*/}
<HomeTaskDisplay
+11 -3
View File
@@ -15,6 +15,7 @@ import usersService from "../../services/UsersService";
import siteLogo from '../../assets/images/wrenchboard.png'
import Flag from '../../assets/images/united-states.svg'
import { useSelector } from "react-redux";
export default function Header({ logoutModalHandler, sidebarHandler }) {
@@ -24,6 +25,8 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
const [moneyPopup, setPopup] = useToggle(false);
const [toggleNotification, setToggleNotification] = useToggle(false)
const darkMode = useContext(DarkModeContext);
const {userDetails} = useSelector((state) => state?.userDetails)
const [myWalletList, setMyWalletList] = useState([]);
const api = new usersService();
@@ -87,6 +90,11 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
const setNotification = ()=> {
setToggleNotification.toggle()
}
// User Profile
let {firstname, lastname, email, profile_pic} = userDetails
let userEmail = email.split('@')[0]
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">
@@ -463,17 +471,17 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
{/* profile-image */}
<div className="lg:w-[62px] lg:h-[62px] w-[50px] h-[50px] rounded-full overflow-hidden">
<img
src={profileImg}
src={profile_pic != '' ? profile_pic : profileImg}
alt="profile"
className="w-full h-full"
/>
</div>
<div className="lg:block hidden">
<h1 className="text-xl font-bold text-dark-gray dark:text-white">
Brokln Simons
{`${firstname} ${lastname}`}
</h1>
<p className="text-sm text-thin-light-gray">
@broklinslam_75
@{userEmail}
</p>
</div>
</div>
+3 -3
View File
@@ -22,9 +22,9 @@ export default function Layout({ children }) {
const logOut = () => {
localStorage.removeItem("email");
localStorage.clear();
toast.success("Come Back Soon", {
icon: `🙂`,
});
// toast.success("Come Back Soon", {
// icon: `🙂`,
// });
navigate("/login", { replace: true });
};
+2 -2
View File
@@ -1,8 +1,8 @@
import React from 'react'
function LoadingSpinner({size, color}) {
function LoadingSpinner({size, color, height}) {
return (
<div className='flex items-center justify-center'>
<div className={`flex items-center justify-center ${height ? height : ''}`}>
<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">
<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 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 apiCall = new usersService()
const dispatch = useDispatch()
const [lastActivityTime, setLastActivityTime] = useState(Date.now());
const isLogin = localStorage.getItem("email");
let [isLogin, setIsLogin] = useState({loading: true, status: false})
const navigate = useNavigate();
const { pathname } = useLocation();
//Removing Data stored at localStorage after session expires
const expireSession = () => {
localStorage.removeItem("email");
localStorage.removeItem('session_token');
localStorage.removeItem('firstname');
localStorage.removeItem('member_id');
localStorage.removeItem('lastname');
localStorage.removeItem('state');
localStorage.removeItem('last_login');
localStorage.removeItem('uid');
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
};
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
const resetTime = () => {
setLastActivityTime(Date.now());
@@ -40,19 +33,52 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
window.addEventListener('mousemove', 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(() => {
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
return () => {
clearInterval(checkInactivity)
window.removeEventListener('mousemove', resetTime)
window.removeEventListener('keydown', resetTime)
}
}, [pathname, lastActivityTime])
}, [lastActivityTime])
if (!isLogin) {
return <Navigate to={redirectPath} replace />;
}
return children || <Outlet />;
return (
isLogin.loading ?
<LoadingSpinner size='32' color='sky-blue' height='h-screen' />
// 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 drawerReducer from "./drawer";
import userDetailReducer from "./UserDetails";
export default configureStore({
reducer: {
drawer: drawerReducer,
userDetails: userDetailReducer,
},
});
});