Compare commits

...

5 Commits

Author SHA1 Message Date
victorAnumudu 333ada0a1c implemented logout 2024-04-27 23:52:11 +01:00
ameye bb718953ad Merge branch 'verify-bvn-bug' of DigiFi/digifi-www into master 2024-04-27 01:41:59 +00:00
victorAnumudu a31b36686d verify bvn auto api calling bug fixed 2024-04-27 02:36:40 +01:00
CHIEFSOFT\ameye 00f4e1b565 extra host 2024-04-26 19:31:33 -04:00
ameye 6d302def04 Merge branch 'added-axios-package' of DigiFi/digifi-www into master 2024-04-26 23:18:29 +00:00
10 changed files with 152 additions and 42 deletions
+5 -2
View File
@@ -11,10 +11,13 @@ services:
ports: ports:
- 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
stdin_open: true stdin_open: true
volumes: volumes:
src: src:
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"
+51 -33
View File
@@ -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,18 +168,18 @@ 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">
+11
View File
@@ -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
} }
+45 -4
View File
@@ -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
View File
@@ -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>
); );
+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, action) => {
state.userDetails = { ...action.payload };
},
},
});
// Action creators are generated for each case reducer function
export const { updateUserDetails } = userSlice.actions;
export default userSlice.reducer;
+9
View File
@@ -0,0 +1,9 @@
import { configureStore } from "@reduxjs/toolkit";
import userDetailReducer from "./UserDetails";
export default configureStore({
reducer: {
userDetails: userDetailReducer,
},
});