Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 333ada0a1c | |||
| bb718953ad | |||
| a31b36686d | |||
| 00f4e1b565 | |||
| 6d302def04 |
@@ -12,6 +12,9 @@ services:
|
|||||||
- 6030:5173
|
- 6030:5173
|
||||||
expose:
|
expose:
|
||||||
- "5173"
|
- "5173"
|
||||||
|
extra_hosts:
|
||||||
|
- digifi-apidev.chiefsoft.net:10.10.33.15
|
||||||
|
- backend.wrenchboard.api.test:10.10.33.15
|
||||||
environment:
|
environment:
|
||||||
- PORT=${DIGIFI_PORT}
|
- PORT=${DIGIFI_PORT}
|
||||||
tty: true
|
tty: true
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
@@ -1,6 +1,7 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import NairaBag from "../../assets/images/dashboard/naira-bag.png";
|
import NairaBag from "../../assets/images/dashboard/naira-bag.png";
|
||||||
import { Button } from "../";
|
import { Button } from "../";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
export interface DashBoardCardProps {
|
export interface DashBoardCardProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
@@ -73,11 +74,12 @@ interface DashboardHomeIntroProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({ handleNextStep, step }) => {
|
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({ handleNextStep, step }) => {
|
||||||
|
const { userDetails } = useSelector((state:any) => state?.userDetails); // CHECKS IF USER Details are avaliable
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{step == 1 ?
|
{step == 1 ?
|
||||||
<>
|
<>
|
||||||
<h1 className="font-bold my-5 text-2xl">Hello, Olanrewaju</h1>
|
<h1 className="font-bold my-5 text-2xl">Hello, {userDetails.firstname}</h1>
|
||||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||||
<DashBoardCard
|
<DashBoardCard
|
||||||
cardClass="bg-[#5C2684] relative"
|
cardClass="bg-[#5C2684] relative"
|
||||||
@@ -95,7 +97,7 @@ const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({ handleNextStep, step
|
|||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
<>
|
<>
|
||||||
<h1 className="font-bold my-5 text-2xl">Welcome Back, Olanrewaju</h1>
|
<h1 className="font-bold my-5 text-2xl">Welcome Back, {userDetails.firstname}</h1>
|
||||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||||
<DashBoardCard
|
<DashBoardCard
|
||||||
cardClass="bg-[#5C2684] relative"
|
cardClass="bg-[#5C2684] relative"
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import { InputCompOne } from "..";
|
|||||||
import {useNavigate} from 'react-router-dom'
|
import {useNavigate} from 'react-router-dom'
|
||||||
import { RouteHandler } from "../../router/routes";
|
import { RouteHandler } from "../../router/routes";
|
||||||
|
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { updateUserDetails } from "../../store/UserDetails";
|
||||||
|
|
||||||
import { validateBVN, verifyOTP } from "../../core/apiRequest";
|
import { validateBVN, verifyOTP } from "../../core/apiRequest";
|
||||||
import { RequestStatus } from "../../core/models";
|
import { RequestStatus } from "../../core/models";
|
||||||
|
|
||||||
@@ -21,7 +24,11 @@ const validationSchema = Yup.object().shape({
|
|||||||
.min(11, "must be 11 digits")
|
.min(11, "must be 11 digits")
|
||||||
.max(11, "must be 11 digits"),
|
.max(11, "must be 11 digits"),
|
||||||
otp: Yup.string()
|
otp: Yup.string()
|
||||||
.required("OTP is required")
|
// .when('require_otp', {
|
||||||
|
// is: true,
|
||||||
|
// then: Yup.string().required("OTP is required")
|
||||||
|
// })
|
||||||
|
// .required("OTP is required")
|
||||||
.test("no-e", "Invalid number", (value:any) => {
|
.test("no-e", "Invalid number", (value:any) => {
|
||||||
if (value && /^[0-9]*$/.test(value) == false) {
|
if (value && /^[0-9]*$/.test(value) == false) {
|
||||||
return false;
|
return false;
|
||||||
@@ -50,52 +57,66 @@ type ValidBVN = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LetsGetStarted: React.FC = () => {
|
const LetsGetStarted: React.FC = () => {
|
||||||
|
const dispatch = useDispatch()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
// const [pinValues, setPinValues] = React.useState({
|
// const [pinValues, setPinValues] = React.useState({
|
||||||
// bvn: "",
|
// bvn: "",
|
||||||
// otp: "",
|
// otp: "",
|
||||||
// });
|
// });
|
||||||
|
// const otpInputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const firstInputRef = React.useRef<HTMLInputElement>(null);
|
|
||||||
const secondInputRef = React.useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
const [requestStatusBVN, setRequestStatusBVN] = React.useState<RequestStatus>({loading:false, status:undefined, message:''});
|
const [requestStatusBVN, setRequestStatusBVN] = React.useState<RequestStatus>({loading:false, status:undefined, message:''});
|
||||||
|
|
||||||
|
const [requestStatusOTP, setRequestStatusOTP] = React.useState<RequestStatus>({loading:false, status:undefined, message:''});
|
||||||
|
|
||||||
const [bvnIsValid, setBvnIsValid] = React.useState<ValidBVN>({
|
const [bvnIsValid, setBvnIsValid] = React.useState<ValidBVN>({
|
||||||
verification_id: '',
|
verification_id: '',
|
||||||
valid: undefined
|
valid: undefined
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
|
||||||
let { value } = e.target as HTMLInputElement;
|
// e: React.FormEvent<HTMLInputElement>
|
||||||
let bvn = value
|
// let { value } = e.target as HTMLInputElement;
|
||||||
if(value.length == 11){
|
const bvnValidation = (values:any) => { // Function to Validate BVN
|
||||||
setRequestStatusBVN({loading:true, status:false, message:''})
|
let bvn = values.bvn
|
||||||
validateBVN({bvn}).then(res => {
|
setRequestStatusBVN({loading:true, status:false, message:''})
|
||||||
if(!res || !res.data.call_return){
|
validateBVN({bvn}).then(res => {
|
||||||
setBvnIsValid({verification_id:'', valid: false})
|
if(!res || !res.data.call_return){
|
||||||
setRequestStatusBVN({loading:false, status:false, message:'unable to verify BVN'})
|
|
||||||
return setTimeout(()=>{
|
|
||||||
setRequestStatusBVN({loading:false, status:false, message:''})
|
|
||||||
}, 4000)
|
|
||||||
}
|
|
||||||
setBvnIsValid({verification_id:res.data.verification_id, valid: true})
|
|
||||||
setRequestStatusBVN({loading:false, status:true, message:'verified'})
|
|
||||||
}).catch(err => {
|
|
||||||
setBvnIsValid({verification_id:'', valid: false})
|
setBvnIsValid({verification_id:'', valid: false})
|
||||||
console.log(err)
|
setRequestStatusBVN({loading:false, status:false, message:'unable to verify BVN'})
|
||||||
})
|
return setTimeout(()=>{
|
||||||
}
|
setRequestStatusBVN({loading:false, status:false, message:''})
|
||||||
|
}, 4000)
|
||||||
|
}
|
||||||
|
setBvnIsValid({verification_id:res.data.verification_id, valid: true})
|
||||||
|
setRequestStatusBVN({loading:false, status:true, message:'verified'})
|
||||||
|
}).catch(err => {
|
||||||
|
setBvnIsValid({verification_id:'', valid: false})
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (values:any) => {
|
const handleSubmit = (values:any) => { // Function to VERIFY OTP AND LOGIN USER
|
||||||
|
setRequestStatusOTP({loading:true, status:false, message:''})
|
||||||
// console.log('values', values)
|
// console.log('values', values)
|
||||||
verifyOTP({...values, verification_id:bvnIsValid.verification_id}).then(res=>{
|
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})
|
navigate(RouteHandler.dashboardHome, {replace:true})
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
setRequestStatusOTP({loading:false, status:false, message:'something went wrong, try again'})
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
return setTimeout(()=>{
|
||||||
|
setRequestStatusOTP({loading:false, status:false, message:''})
|
||||||
|
},4000)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,7 +124,7 @@ const LetsGetStarted: React.FC = () => {
|
|||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={bvnIsValid.valid ? handleSubmit : bvnValidation}
|
||||||
>
|
>
|
||||||
{(props:any) => (
|
{(props:any) => (
|
||||||
<Form className="">
|
<Form className="">
|
||||||
@@ -129,9 +150,6 @@ const LetsGetStarted: React.FC = () => {
|
|||||||
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
||||||
value={props.values.bvn}
|
value={props.values.bvn}
|
||||||
onChange={props.handleChange}
|
onChange={props.handleChange}
|
||||||
onInput={handleInput}
|
|
||||||
ref={firstInputRef}
|
|
||||||
maxLength={11}
|
|
||||||
error={(props.errors.bvn && props.touched.bvn) && props.errors.bvn}
|
error={(props.errors.bvn && props.touched.bvn) && props.errors.bvn}
|
||||||
/>
|
/>
|
||||||
<p className={`p-2 ${!requestStatusBVN.status ? 'text-red-500' : 'text-emerald-500'}`}>{requestStatusBVN.loading ? 'verifying...' : requestStatusBVN.message}</p>
|
<p className={`p-2 ${!requestStatusBVN.status ? 'text-red-500' : 'text-emerald-500'}`}>{requestStatusBVN.loading ? 'verifying...' : requestStatusBVN.message}</p>
|
||||||
@@ -150,19 +168,19 @@ const LetsGetStarted: React.FC = () => {
|
|||||||
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
||||||
value={props.values.otp}
|
value={props.values.otp}
|
||||||
onChange={props.handleChange}
|
onChange={props.handleChange}
|
||||||
ref={secondInputRef}
|
|
||||||
maxLength={11}
|
|
||||||
error={(props.errors.otp && props.touched.otp) && props.errors.otp}
|
error={(props.errors.otp && props.touched.otp) && props.errors.otp}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
type='submit'
|
type='submit'
|
||||||
className="w-full h-[3.625rem] rounded bg-[#FBB700] rounded-2 px-4 text-[18px] text-[#282828] font-semibold disabled:text-[#282828] disabled:text-opacity-50"
|
className="w-full h-[3.625rem] rounded bg-[#FBB700] rounded-2 px-4 text-[18px] text-[#282828] font-semibold disabled:text-[#282828] disabled:text-opacity-50"
|
||||||
disabled={!props.values.otp || requestStatusBVN.loading}
|
disabled={requestStatusBVN.loading || (!props.values.otp && bvnIsValid.valid)}
|
||||||
>
|
>
|
||||||
Enter
|
Enter
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<p className={`p-2 ${!requestStatusOTP.status ? 'text-red-500' : 'text-emerald-500'}`}>{requestStatusOTP.message}</p>
|
||||||
|
|
||||||
{bvnIsValid.valid || bvnIsValid.valid == undefined ? (
|
{bvnIsValid.valid || bvnIsValid.valid == undefined ? (
|
||||||
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
|
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
|
||||||
***Every personal information attached to your BVN is safe and
|
***Every personal information attached to your BVN is safe and
|
||||||
|
|||||||
@@ -4,4 +4,15 @@ export interface RequestStatus {
|
|||||||
message?:string
|
message?:string
|
||||||
name?:string
|
name?:string
|
||||||
data?:{}[] | [any] | {}
|
data?:{}[] | [any] | {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
firstname?:string
|
||||||
|
lastname?:string
|
||||||
|
last_login?:string
|
||||||
|
message?:string
|
||||||
|
token?:string
|
||||||
|
uid?:string
|
||||||
|
call_return?:string
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,52 @@
|
|||||||
|
|
||||||
|
import {useState, useEffect} from 'react'
|
||||||
import DashboardLayout from "./DashboardLayout";
|
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() {
|
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 (
|
return (
|
||||||
<DashboardLayout>
|
<>
|
||||||
<Outlet />
|
{loading && !Object.keys(userDetails).length ?
|
||||||
</DashboardLayout>
|
<div className='w-full h-screen flex flex-col justify-center items-center gap-4'>
|
||||||
|
<img className='animate-pulse' src={Logo} alt='Logo' />
|
||||||
|
<p className='animate-pulse'>loading...</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<DashboardLayout>
|
||||||
|
<Outlet />
|
||||||
|
</DashboardLayout>
|
||||||
|
}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -35,6 +35,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
const logoutUser = () => {
|
const logoutUser = () => {
|
||||||
|
localStorage.clear()
|
||||||
navigate(RouteHandler.letsGetStarted, {replace:true})
|
navigate(RouteHandler.letsGetStarted, {replace:true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -4,10 +4,15 @@ import { BrowserRouter } from "react-router-dom";
|
|||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
|
import { Provider } from "react-redux";
|
||||||
|
import store from "./store/store";
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<App />
|
<Provider store={store}>
|
||||||
|
<App />
|
||||||
|
</Provider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
import userDetailReducer from "./UserDetails";
|
||||||
|
|
||||||
|
export default configureStore({
|
||||||
|
reducer: {
|
||||||
|
userDetails: userDetailReducer,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user