Compare commits

..

2 Commits

Author SHA1 Message Date
victorAnumudu 82dd11a772 added axios package and api for start bvn verification 2024-04-26 23:41:41 +01:00
ameye 7e9c395f4a Merge branch 'form-validation-contd' of DigiFi/digifi-www into master 2024-04-24 12:32:27 +00:00
7 changed files with 153 additions and 49 deletions
+1
View File
@@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^2.2.1", "@reduxjs/toolkit": "^2.2.1",
"axios": "^1.6.8",
"clsx": "2.1.0", "clsx": "2.1.0",
"formik": "2.4.5", "formik": "2.4.5",
"react": "^18.2.0", "react": "^18.2.0",
+63 -42
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 { validateBVN, verifyOTP } from "../../core/apiRequest";
import { RequestStatus } from "../../core/models";
// To get the validation schema // To get the validation schema
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
bvn: Yup.string() bvn: Yup.string()
@@ -41,6 +44,11 @@ let initialValues = {
otp: '', otp: '',
}; };
type ValidBVN = {
verification_id:string
valid: undefined | boolean
}
const LetsGetStarted: React.FC = () => { const LetsGetStarted: React.FC = () => {
const navigate = useNavigate() const navigate = useNavigate()
// const [pinValues, setPinValues] = React.useState({ // const [pinValues, setPinValues] = React.useState({
@@ -48,36 +56,47 @@ const LetsGetStarted: React.FC = () => {
// otp: "", // otp: "",
// }); // });
const [hideOTPComponent, setHideOTPComponent] = React.useState<boolean>(true);
const firstInputRef = React.useRef<HTMLInputElement>(null); const firstInputRef = React.useRef<HTMLInputElement>(null);
const secondInputRef = React.useRef<HTMLInputElement>(null); const secondInputRef = React.useRef<HTMLInputElement>(null);
// const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const [requestStatusBVN, setRequestStatusBVN] = React.useState<RequestStatus>({loading:false, status:undefined, message:''});
// let { name, value } = e.target as HTMLInputElement;
// setPinValues((prev) => ({ ...prev, [name]: value })); const [bvnIsValid, setBvnIsValid] = React.useState<ValidBVN>({
// }; verification_id: '',
valid: undefined
});
const handleInput = (e: React.FormEvent<HTMLInputElement>) => { const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
let { name, value } = e.target as HTMLInputElement; let { value } = e.target as HTMLInputElement;
let bvn = value
if (name === "bvn") { if(value.length == 11){
const regex = /^[0-9]+$/; setRequestStatusBVN({loading:true, status:false, message:''})
validateBVN({bvn}).then(res => {
if (regex.test(value)) { if(!res || !res.data.call_return){
if (value?.length == 11) { setBvnIsValid({verification_id:'', valid: false})
setHideOTPComponent(false); setRequestStatusBVN({loading:false, status:false, message:'unable to verify BVN'})
// secondInputRef.current?.focus(); return setTimeout(()=>{
} else setHideOTPComponent(true); setRequestStatusBVN({loading:false, status:false, message:''})
} else { }, 4000)
console.log("object not found"); }
} 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) => {
console.log('values', values) // console.log('values', values)
navigate(RouteHandler.dashboardHome, {replace:true}) verifyOTP({...values, verification_id:bvnIsValid.verification_id}).then(res=>{
console.log(res.data)
navigate(RouteHandler.dashboardHome, {replace:true})
}).catch(err => {
console.log(err)
})
}; };
return ( return (
@@ -96,25 +115,28 @@ const LetsGetStarted: React.FC = () => {
</h1> </h1>
</div> </div>
<div className="mx-auto flex flex-col gap-8 max-w-[31.625rem] "> <div className="mx-auto flex flex-col gap-8 max-w-[31.625rem] ">
<InputCompOne <div className='w-full'>
parentClass="flex flex-col gap-2" <InputCompOne
label="Enter Your BVN " parentClass="flex flex-col gap-2"
name="bvn" label="Enter Your BVN "
parentInputClass="w-full" name="bvn"
labelSpan="( To get your BVN, dial *565*0# )" parentInputClass="w-full"
labelSpanClass="text-[13px] text-[#5a5a5a] font-semibold" labelSpan="( To get your BVN, dial *565*0# )"
placeholder="Enter your BVN" labelSpanClass="text-[13px] text-[#5a5a5a] font-semibold"
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#282828] mb-[2px] flex item-center gap-[4px]" placeholder="Enter your BVN"
input labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#282828] mb-[2px] flex item-center gap-[4px]"
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4" input
value={props.values.bvn} inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
onChange={props.handleChange} value={props.values.bvn}
onInput={handleInput} onChange={props.handleChange}
ref={firstInputRef} onInput={handleInput}
maxLength={11} ref={firstInputRef}
error={(props.errors.bvn && props.touched.bvn) && props.errors.bvn} maxLength={11}
/> error={(props.errors.bvn && props.touched.bvn) && props.errors.bvn}
{!hideOTPComponent && ( />
<p className={`p-2 ${!requestStatusBVN.status ? 'text-red-500' : 'text-emerald-500'}`}>{requestStatusBVN.loading ? 'verifying...' : requestStatusBVN.message}</p>
</div>
{bvnIsValid.valid && (
<InputCompOne <InputCompOne
parentClass="flex flex-col gap-2" parentClass="flex flex-col gap-2"
label="Enter OTP " label="Enter OTP "
@@ -128,7 +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.otp} value={props.values.otp}
onChange={props.handleChange} onChange={props.handleChange}
onInput={handleInput}
ref={secondInputRef} ref={secondInputRef}
maxLength={11} maxLength={11}
error={(props.errors.otp && props.touched.otp) && props.errors.otp} error={(props.errors.otp && props.touched.otp) && props.errors.otp}
@@ -137,12 +158,12 @@ const LetsGetStarted: React.FC = () => {
<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} disabled={!props.values.otp || requestStatusBVN.loading}
> >
Enter Enter
</button> </button>
{hideOTPComponent ? ( {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
secure. It is only important for us to verify your information and secure. It is only important for us to verify your information and
+19
View File
@@ -0,0 +1,19 @@
import { postAuxEnd } from "./axiosCall";
// FUNCTION TO START BVN VALIDATION
export const validateBVN = (postData:any) => {
let reqData = {
...postData
}
return postAuxEnd('https://digifi-apidev.chiefsoft.net/digiusers/v1/bvn', reqData)
}
// FUNCTION TO VERIFY OTP AND LOGIN
export const verifyOTP = (postData:any) => {
let reqData = {
...postData
}
return postAuxEnd('https://digifi-apidev.chiefsoft.net/digiusers/v1/bvn/verify', reqData)
}
+49
View File
@@ -0,0 +1,49 @@
import axios from "axios";
export function postAuxEnd(uri:string, reqData:any):Promise<any> {
// const endPoint = import.meta.env.REACT_APP_USERS_ENDPOINT + uri;
const formData = new FormData();
for (let value in reqData) {
formData.append(value, reqData[value]);
}
return axios.post(uri, formData)
.then((response:{}) => {
// if (response.data.internal_return == "-9999") {
// localStorage.clear();
// window.location.href = `/login?sessionExpired=true`;
// }
return response;
})
.catch((error:any) => {
if (error.response) {
//response status is an error code
console.log(
"ERROR-------------------------------------------------------"
);
console.log(error.response.status);
console.log(
"ERROR-------------------------------------------------------"
);
} else if (error.request) {
//response not received though the request was sent
console.log(
"ERROR2-------------------------------------------------------"
);
console.log(error?.request);
console.log(
"ERROR2-------------------------------------------------------"
);
} else {
//an error occurred when setting up the request
console.log(
"ERROR3-------------------------------------------------------"
);
console.log(error);
console.log(
"ERROR3-------------------------------------------------------"
);
}
});
}
+7
View File
@@ -0,0 +1,7 @@
export interface RequestStatus {
loading?:boolean
status?:boolean | undefined
message?:string
name?:string
data?:{}[] | [any] | {}
}
+4 -5
View File
@@ -1,17 +1,16 @@
import { useState } from "react"; import { useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom"; import { Link, useLocation } from "react-router-dom";
import Logo from "../../assets/icons/logo.svg"; import Logo from "../../assets/icons/logo.svg";
import { Icons } from "../../components"; import { Icons } from "../../components";
type Props = { type Props = {
asideDisplay?: () => void; asideDisplay?: () => void;
logoutUser: () => void
}; };
export default function Aside({ asideDisplay }: Props) { export default function Aside({ asideDisplay, logoutUser }: Props) {
const { pathname } = useLocation(); const { pathname } = useLocation();
const navigate = useNavigate();
const [openNestedLink, setOpenNestedLink] = useState<{ name: string | null }>( const [openNestedLink, setOpenNestedLink] = useState<{ name: string | null }>(
{ name: "" } { name: "" }
); );
@@ -115,7 +114,7 @@ export default function Aside({ asideDisplay }: Props) {
<div className="w-full flex justify-center items-center flex-col gap-3"> <div className="w-full flex justify-center items-center flex-col gap-3">
<button <button
className="py-3 px-6 bg-red-100 text-red-500 font-medium rounded-md w-full" className="py-3 px-6 bg-red-100 text-red-500 font-medium rounded-md w-full"
onClick={() => navigate("/login", { replace: true })} onClick={() => logoutUser()}
> >
Log out Log out
</button> </button>
@@ -1,8 +1,12 @@
import { ReactNode, useState, useEffect } from "react"; import { ReactNode, useState, useEffect } from "react";
import { RouteHandler } from "../../router/routes";
import { useNavigate } from "react-router-dom";
import Aside from "./Aside"; import Aside from "./Aside";
export default function DashboardLayout({ children }: { children: ReactNode }) { export default function DashboardLayout({ children }: { children: ReactNode }) {
const navigate = useNavigate();
const [showAside, setShowAside] = useState<boolean>(false); const [showAside, setShowAside] = useState<boolean>(false);
const asideDisplay = (): void => { const asideDisplay = (): void => {
setShowAside((prev) => !prev); setShowAside((prev) => !prev);
@@ -30,17 +34,21 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
// return child; // return child;
// }); // });
const logoutUser = () => {
navigate(RouteHandler.letsGetStarted, {replace:true})
}
return ( return (
<div className="w-full max-w-[2000px] mx-auto h-screen flex bg-[#020202] text-black"> <div className="w-full max-w-[2000px] mx-auto h-screen flex bg-[#020202] text-black">
<aside className="max-w-[18.75rem] w-full bg-white hidden md:block border-r-2 border-[#E6E6E6]"> <aside className="max-w-[18.75rem] w-full bg-white hidden md:block border-r-2 border-[#E6E6E6]">
<Aside /> <Aside logoutUser={logoutUser} />
</aside> </aside>
<aside <aside
className={`max-w-[18.75rem] w-full md:hidden bg-white border-r-2 border-[#E6E6E6] fixed top-0 bottom-0 z-50 transition-all duration-500 ${ className={`max-w-[18.75rem] w-full md:hidden bg-white border-r-2 border-[#E6E6E6] fixed top-0 bottom-0 z-50 transition-all duration-500 ${
showAside ? "left-0" : "-left-[200%]" showAside ? "left-0" : "-left-[200%]"
}`} }`}
> >
<Aside asideDisplay={asideDisplay} /> <Aside logoutUser={logoutUser} asideDisplay={asideDisplay} />
</aside> </aside>
<main className="dash-bg-image bg-[#F9F9F9] relative w-full overflow-y-auto overflow-x-hidden"> <main className="dash-bg-image bg-[#F9F9F9] relative w-full overflow-y-auto overflow-x-hidden">