Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| df5b4c89a4 | |||
| a37a5c24f5 | |||
| 890452af63 | |||
| 69b6850002 | |||
| dd8290af9a | |||
| 306ab06142 | |||
| 4d258a965b | |||
| f63171273e | |||
| b4bf96e841 | |||
| e20b7e32f1 | |||
| 6bd533c7ca | |||
| 408777353d | |||
| a2e039eab4 | |||
| 8d6cc5861e | |||
| 18967d720c | |||
| 044b2ef917 | |||
| 4f7fdfb2ba | |||
| ab389d6632 | |||
| 29538e3b6e | |||
| dd2df0d695 | |||
| a97db9a661 | |||
| 135cbce348 | |||
| 814bfe041a | |||
| d90d515f60 | |||
| e93a3dea68 | |||
| a50d5ec82d | |||
| 333ada0a1c | |||
| bb718953ad | |||
| a31b36686d | |||
| 00f4e1b565 | |||
| 6d302def04 | |||
| 82dd11a772 | |||
| 7e9c395f4a | |||
| 2cb5c471f6 | |||
| 4b008f6785 | |||
| f632099128 | |||
| 122eb31732 | |||
| 378ff4a625 | |||
| f88b6df24c |
@@ -3,4 +3,11 @@ DIGIFI_PORT=5173
|
||||
# Social Links
|
||||
FACEBOOK_URL=https://www.facebook.com
|
||||
TWITTER_URL=https://twitter.com
|
||||
INSTAGRAM_URL=https://www.instagram.com
|
||||
INSTAGRAM_URL=https://www.instagram.com
|
||||
|
||||
# BACKEND END POINTS
|
||||
VITE_USERS_ENDPOINT='https://digifi-apidev.chiefsoft.net/digiusers/v1'
|
||||
|
||||
# ENQUIRIES CONTACTS
|
||||
VITE_CALL_ENDPOINT='09099000000'
|
||||
VITE_EMAIL_ENDPOINT='fcmbloan@support.com'
|
||||
+4
-1
@@ -3,4 +3,7 @@ DIGIFI_PORT=5173
|
||||
# Social Links
|
||||
VITE_FACEBOOK_URL=https://www.facebook.com
|
||||
VITE_TWITTER_URL=https://twitter.com
|
||||
VITE_INSTAGRAM_URL=https://www.instagram.com
|
||||
VITE_INSTAGRAM_URL=https://www.instagram.com
|
||||
|
||||
# BACKEND END POINTS
|
||||
VITE_USERS_ENDPOINT='https://digifi-apidev.chiefsoft.net/digiusers/v1'
|
||||
+4
-1
@@ -3,4 +3,7 @@ DIGIFI_PORT=5173
|
||||
# Social Links
|
||||
FACEBOOK_URL=https://www.facebook.com
|
||||
TWITTER_URL=https://twitter.com
|
||||
INSTAGRAM_URL=https://www.instagram.com
|
||||
INSTAGRAM_URL=https://www.instagram.com
|
||||
|
||||
# BACKEND END POINTS
|
||||
VITE_USERS_ENDPOINT='https://digifi-apidev.chiefsoft.net/digiusers/v1'
|
||||
+7
-2
@@ -11,8 +11,13 @@ services:
|
||||
ports:
|
||||
- 6030:5173
|
||||
expose:
|
||||
- "5173"
|
||||
- "5173"
|
||||
extra_hosts:
|
||||
- digifi-apidev.chiefsoft.net:10.10.33.15
|
||||
- backend.wrenchboard.api.test:10.10.33.15
|
||||
environment:
|
||||
- PORT=${DIGIFI_PORT}
|
||||
tty: true
|
||||
stdin_open: true
|
||||
volumes:
|
||||
src:
|
||||
src:
|
||||
|
||||
Generated
+100
@@ -9,10 +9,12 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^2.2.1",
|
||||
"axios": "^1.6.8",
|
||||
"clsx": "2.1.0",
|
||||
"formik": "2.4.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^5.0.1",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "6.3.0",
|
||||
"react-select": "^5.8.0",
|
||||
@@ -1805,6 +1807,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.18",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz",
|
||||
@@ -1842,6 +1849,16 @@
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.6.8",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
|
||||
"integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-macros": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||
@@ -2030,6 +2047,17 @@
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
@@ -2124,6 +2152,14 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
@@ -2550,6 +2586,25 @@
|
||||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
||||
@@ -2565,6 +2620,19 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formik": {
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmjs.org/formik/-/formik-2.4.5.tgz",
|
||||
@@ -3078,6 +3146,25 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
@@ -3532,6 +3619,11 @@
|
||||
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
|
||||
"integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@@ -3588,6 +3680,14 @@
|
||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz",
|
||||
"integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^2.2.1",
|
||||
"axios": "^1.6.8",
|
||||
"clsx": "2.1.0",
|
||||
"formik": "2.4.5",
|
||||
"react": "^18.2.0",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
@@ -3,20 +3,20 @@ import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
type Props = {
|
||||
handleNextStep:()=>any
|
||||
handleNextStep:(value:{})=>any
|
||||
}
|
||||
|
||||
const initialValues = {
|
||||
amount: "",
|
||||
duration: "",
|
||||
id: "",
|
||||
loan_amount: "",
|
||||
payment_month: "",
|
||||
sales_agent: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
duration: Yup.string()
|
||||
payment_month: Yup.string()
|
||||
.required("Required"),
|
||||
amount: Yup.string()
|
||||
loan_amount: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
@@ -24,16 +24,14 @@ const validationSchema = Yup.object().shape({
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
id: Yup.string()
|
||||
.required("Required")
|
||||
sales_agent: Yup.string()
|
||||
});
|
||||
|
||||
export default function DashboardFormInit({handleNextStep}:Props) {
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
const handleSubmit = (values:{}) => {
|
||||
handleNextStep(values)
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -51,40 +49,40 @@ export default function DashboardFormInit({handleNextStep}:Props) {
|
||||
<div className="mt-[3.25rem] flex flex-col gap-9">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="amount"
|
||||
name="loan_amount"
|
||||
label="How Much Do You Want To Apply For?"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
|
||||
placeholder="350,000"
|
||||
value={props.values.amount}
|
||||
value={props.values.loan_amount}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.amount && props.touched.amount) ? props.errors.amount : ''}
|
||||
error={(props.errors.loan_amount && props.touched.loan_amount) ? props.errors.loan_amount : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="duration"
|
||||
name="payment_month"
|
||||
label="For How Many Months?"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={duration}
|
||||
selectValue={props.values.duration}
|
||||
selectOptions={paymentMonth}
|
||||
selectValue={props.values.payment_month}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.duration && props.touched.duration) ? props.errors.duration : ''}
|
||||
error={(props.errors.payment_month && props.touched.payment_month) ? props.errors.payment_month : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="id"
|
||||
name="sales_agent"
|
||||
label="Direct sales agent ID ( Optional )"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
floatLabel='Enter agent ID'
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="Agent ID"
|
||||
value={props.values.id}
|
||||
value={props.values.sales_agent}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.id && props.touched.id) ? props.errors.id : ''}
|
||||
error={(props.errors.sales_agent && props.touched.sales_agent) ? props.errors.sales_agent : ''}
|
||||
/>
|
||||
<Button
|
||||
className="my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
|
||||
@@ -106,7 +104,7 @@ interface SelectOption {
|
||||
}
|
||||
|
||||
|
||||
const duration: SelectOption = {
|
||||
const paymentMonth: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Please Select" },
|
||||
|
||||
@@ -10,12 +10,14 @@ interface DashboardHomeProps {}
|
||||
|
||||
const DashboardHome: FC<DashboardHomeProps> = () => {
|
||||
const [step, setStep] = React.useState(1);
|
||||
const [applicationDetails, setApplicationDetails] = React.useState({});
|
||||
|
||||
const handleNextStep = () => {
|
||||
const handleNextStep = (values:{}={}) => {
|
||||
if (step < 7) {
|
||||
setStep(step + 1);
|
||||
}
|
||||
};
|
||||
setApplicationDetails((prev:{}) => ({...prev, ...values}))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
@@ -24,8 +26,9 @@ const DashboardHome: FC<DashboardHomeProps> = () => {
|
||||
{step === 3 && <DashboardHomeDetail handleNextStep={handleNextStep} />}
|
||||
{step === 4 && <DashboardHomeEmploymentInfo handleNextStep={handleNextStep} />}
|
||||
{step === 5 && <DashboardHomeRefereeInfo handleNextStep={handleNextStep} />}
|
||||
{step === 6 && <DashboardHomeAttestation handleNextStep={handleNextStep} />}
|
||||
{step === 6 && <DashboardHomeAttestation handleNextStep={handleNextStep} applicationDetails={applicationDetails} />}
|
||||
{step === 7 && <DashboardHomeIntro step={step} handleNextStep={handleNextStep} />}
|
||||
{/* <DashboardHomeAttestation handleNextStep={handleNextStep} applicationDetails={applicationDetails} /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import React, { FC } from "react";
|
||||
import NairaBag from "../../assets/images/dashboard/naira-bag.png";
|
||||
import { Button } from "../";
|
||||
import React, { FC, useState, useEffect } from 'react';
|
||||
import NairaBag from '../../assets/images/dashboard/naira-bag.png';
|
||||
import { Button, Icons } from '../';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PendingList from '../paginated-list/PendingList';
|
||||
import { PendingTableList } from '../../core/models';
|
||||
import { NewDateTimeFormatter } from '../../lib/NewDateTimeFormatter';
|
||||
import { getUserPendingLoanList } from '../../core/apiRequest';
|
||||
|
||||
export interface DashBoardCardProps {
|
||||
title?: string;
|
||||
@@ -50,7 +55,7 @@ export const DashBoardCard: React.FC<DashBoardCardProps> = ({
|
||||
)}
|
||||
{desc && (
|
||||
<p className={`text-lg text-left ${descClass && descClass}`}>
|
||||
{desc}{" "}
|
||||
{desc}{' '}
|
||||
{descSpan && (
|
||||
<span className={`${descSpanClass && descSpanClass}`}>
|
||||
{descSpan}
|
||||
@@ -68,51 +73,138 @@ export const DashBoardCard: React.FC<DashBoardCardProps> = ({
|
||||
};
|
||||
|
||||
interface DashboardHomeIntroProps {
|
||||
handleNextStep: any;
|
||||
step?:number|string
|
||||
handleNextStep: (value: {}) => any;
|
||||
step?: number | string;
|
||||
}
|
||||
|
||||
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({ handleNextStep, step }) => {
|
||||
return (
|
||||
<>
|
||||
{step == 1 ?
|
||||
<>
|
||||
<h1 className="font-bold my-5 text-2xl">Hello, Olanrewaju</h1>
|
||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Begin your application and get up to "
|
||||
descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
descSpanClass="font-bold"
|
||||
btnTitle="Apply here"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
onClick={handleNextStep}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
:
|
||||
<>
|
||||
<h1 className="font-bold my-5 text-2xl">Welcome Back, Olanrewaju</h1>
|
||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Your loan application has been reviewed and accepted, please confirm for disbursement."
|
||||
// descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
// descSpanClass="font-bold"
|
||||
btnTitle="View and accept"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
// onClick={handleNextStep}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({
|
||||
handleNextStep,
|
||||
step,
|
||||
}) => {
|
||||
const { userDetails } = useSelector((state: any) => state?.userDetails); // CHECKS IF USER Details are avaliable
|
||||
|
||||
const [userLoanList, setUserLoanList] = useState<{
|
||||
loading: boolean;
|
||||
data: PendingTableList;
|
||||
}>({ loading: true, data: [] });
|
||||
|
||||
useEffect(() => {
|
||||
let token = localStorage.getItem('token');
|
||||
let uid = localStorage.getItem('uid');
|
||||
if (!token || !uid) {
|
||||
return;
|
||||
}
|
||||
</>
|
||||
getUserPendingLoanList(uid)
|
||||
.then((res) => {
|
||||
console.log('RES', res);
|
||||
console.log('RES', userLoanList);
|
||||
if (!res || !res.data.loans) {
|
||||
setUserLoanList({ loading: false, data: [] });
|
||||
return;
|
||||
}
|
||||
setUserLoanList({ loading: false, data: res?.data?.loans });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
setUserLoanList({ loading: false, data: [] });
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
{step == 1 ? (
|
||||
<>
|
||||
<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 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Begin your application and get up to "
|
||||
descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
descSpanClass="font-bold"
|
||||
btnTitle="Apply here"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
onClick={() => handleNextStep({})}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<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 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Your loan application has been reviewed and accepted, please confirm for disbursement."
|
||||
// descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
// descSpanClass="font-bold"
|
||||
btnTitle="View and accept"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
// onClick={handleNextStep}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{userLoanList.loading ? null : (
|
||||
<div className="mt-5 w-full">
|
||||
<PendingList
|
||||
data={userLoanList.data}
|
||||
itemsPerPage={5}
|
||||
tableTitle="Current Applications"
|
||||
>
|
||||
{(data: any) => (
|
||||
<div className="w-full p-4 rounded-lg shadow-lg bg-white overflow-x-auto min-h-[250px] max-h-[450px]">
|
||||
<table className="text-[12px] sm:text-base w-full table-auto">
|
||||
<thead>
|
||||
<tr className="text-left border-b-2">
|
||||
<th className="px-1 py-4">Date</th>
|
||||
<th className="px-1 py-4 text-right">Amount</th>
|
||||
<th className="px-1 py-4 text-center min-w-[110px]">
|
||||
Payment Term
|
||||
</th>
|
||||
<th className="px-1 py-4 text-center">Status</th>
|
||||
<th className="px-1 py-4 text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((item: any, index: any) => (
|
||||
<tr key={index || item} className="even:bg-slate-100">
|
||||
<td className="px-1 py-2">
|
||||
{NewDateTimeFormatter(item?.added)}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-right">
|
||||
{item?.loan_amount}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-center">
|
||||
{item?.payment_month}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-center">
|
||||
{item?.status}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-right">
|
||||
<button className="px-2 py-1 border-2 border-black">
|
||||
View
|
||||
<Icons name="arrow-right" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</PendingList>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,34 +2,49 @@ import { Button, InputCompOne, Stepper } from '../../shared/index';
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
import { applyForLoan } from '../../../core/apiRequest';
|
||||
|
||||
// import { useNavigate } from "react-router-dom";
|
||||
// import { RouteHandler } from '../../../router/routes';
|
||||
|
||||
type Props = {
|
||||
handleNextStep:()=>any
|
||||
handleNextStep:(value:{})=>any
|
||||
applicationDetails: {}
|
||||
}
|
||||
|
||||
const initialValues = {
|
||||
account_number: "",
|
||||
account: "",
|
||||
checked: false
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
account_number: Yup.string()
|
||||
account: Yup.string()
|
||||
.required("Required"),
|
||||
checked: Yup.bool() // use bool instead of boolean
|
||||
.oneOf([true], "You must accept the terms and conditions")
|
||||
});
|
||||
|
||||
export default function DashboardHomeAttestation({handleNextStep}:Props) {
|
||||
export default function DashboardHomeAttestation({handleNextStep, applicationDetails}:Props) {
|
||||
// let navigate = useNavigate();
|
||||
// const navigateToProfile = () => navigate(RouteHandler.dashboardProfile);
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
//FUNCTION TO HANDLE LOAN APPLICATION
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
delete values.checked
|
||||
applyForLoan({...applicationDetails, disbursement: values}).then(res=>{
|
||||
console.log('APPLY FOR LOAN', res)
|
||||
handleNextStep({disbursement: values})
|
||||
console.log('ApplicationDetails', {...applicationDetails, disbursement: values})
|
||||
}).catch(err=>{
|
||||
console.log(err)
|
||||
})
|
||||
// applyForLoan(payload).then(res=>{
|
||||
// console.log('APPLY FOR LOAN', res)
|
||||
// // handleNextStep({disbursement: values})
|
||||
// }).catch(err=>{
|
||||
// console.log(err)
|
||||
// })
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -50,15 +65,15 @@ export default function DashboardHomeAttestation({handleNextStep}:Props) {
|
||||
<div className="flex items-center gap-[4.125rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="account_number"
|
||||
name="account"
|
||||
floatLabel="Disbursement account number"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="0102547896"
|
||||
value={props.values.account_number}
|
||||
value={props.values.account}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.account_number && props.touched.account_number) ? props.errors.account_number : ''}
|
||||
error={(props.errors.account && props.touched.account) ? props.errors.account : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='max-w-[25.875rem]'>
|
||||
@@ -87,3 +102,46 @@ export default function DashboardHomeAttestation({handleNextStep}:Props) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// const payload = {
|
||||
// "loan_amount": "100000",
|
||||
// "payment_month": "18",
|
||||
// "sales_agent": "Testing1234",
|
||||
// "gender": "male",
|
||||
// "address": "World bank housing Estate, Umuahia",
|
||||
// "marital_status": "single",
|
||||
// "state": "abia",
|
||||
// "email": "test5070@gmail.com",
|
||||
// "country": "NG",
|
||||
// "employment": {
|
||||
// "job_title": "Information Officer",
|
||||
// "name": "Testing Testing",
|
||||
// "sector": "private (non academic)",
|
||||
// "industry": "engineering",
|
||||
// "resumption_date": "2024-04-05",
|
||||
// "email": "test50700@gmail.com",
|
||||
// "annual_income": "600000",
|
||||
// "monthly_salary": "50000",
|
||||
// "salary_payment_date": "2024-04-19",
|
||||
// "employment_id": "2555566",
|
||||
// "highest_eductaion": "b.sc + professional qualification"
|
||||
// },
|
||||
// "loan_reference": [
|
||||
// {
|
||||
// "fullname": "John Mike",
|
||||
// "relationship": "Brother",
|
||||
// "phone_number": "07055566611",
|
||||
// "email": "refone@gmail.com",
|
||||
// "bvn": "11111111111"
|
||||
// },
|
||||
// {
|
||||
// "fullname": "Mary Paul",
|
||||
// "relationship": "Brother",
|
||||
// "phone_number": "07055577711",
|
||||
// "email": "reftwo@gmail.com",
|
||||
// "bvn": "22222222222"
|
||||
// }
|
||||
// ],
|
||||
// disbursement:{account: '1122334456'}
|
||||
// }
|
||||
@@ -4,7 +4,7 @@ import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
type Props = {
|
||||
handleNextStep:()=>any
|
||||
handleNextStep:(value:{})=>any
|
||||
}
|
||||
|
||||
const initialValues = {
|
||||
@@ -12,7 +12,8 @@ const initialValues = {
|
||||
address: "",
|
||||
marital_status: "",
|
||||
state: "",
|
||||
email:""
|
||||
email:"",
|
||||
country:""
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
@@ -28,14 +29,15 @@ const validationSchema = Yup.object().shape({
|
||||
email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
country: Yup.string()
|
||||
.required("Required"),
|
||||
});
|
||||
|
||||
export default function DashboardHomeDetail({handleNextStep}:Props) {
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
handleNextStep(values)
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -103,18 +105,32 @@ export default function DashboardHomeDetail({handleNextStep}:Props) {
|
||||
error={(props.errors.state && props.touched.state) ? props.errors.state : ''}
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="email"
|
||||
label="Email address"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="johndoe@gmail.com"
|
||||
value={props.values.email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.email && props.touched.email) ? props.errors.email : ''}
|
||||
/>
|
||||
<div className="flex items-center gap-[4.125rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="email"
|
||||
label="Email address"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="johndoe@gmail.com"
|
||||
value={props.values.email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.email && props.touched.email) ? props.errors.email : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="country"
|
||||
label="Select your country"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={country}
|
||||
selectValue={props.values.country}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.country && props.touched.country) ? props.errors.country : ''}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
|
||||
text="Next"
|
||||
@@ -163,4 +179,12 @@ const state: SelectOption = {
|
||||
{ value: "imo", label: "Imo" },
|
||||
{ value: "lagos", label: "Lagos" },
|
||||
]
|
||||
}
|
||||
|
||||
const country: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Please Select" },
|
||||
{ value: "NG", label: "Nigeria" },
|
||||
]
|
||||
}
|
||||
@@ -4,36 +4,36 @@ import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
type Props = {
|
||||
handleNextStep:()=>any
|
||||
handleNextStep:(value:{})=>any
|
||||
}
|
||||
|
||||
const initialValues = {
|
||||
job_title: "",
|
||||
employer_name: "",
|
||||
job_sector: "",
|
||||
name: "",
|
||||
sector: "",
|
||||
industry: "",
|
||||
date_of_resumption: "",
|
||||
employer_email:"",
|
||||
resumption_date: "",
|
||||
email:"",
|
||||
annual_income: "",
|
||||
monthly_salary: "",
|
||||
salary_payment_date: "",
|
||||
employee_id: "",
|
||||
qualification: ""
|
||||
employment_id: "",
|
||||
highest_eductaion: ""
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
job_title: Yup.string()
|
||||
.required("Required"),
|
||||
employer_name: Yup.string()
|
||||
name: Yup.string()
|
||||
.required("Required"),
|
||||
job_sector: Yup.string()
|
||||
sector: Yup.string()
|
||||
.required("Required"),
|
||||
industry: Yup.string()
|
||||
.required("Required"),
|
||||
date_of_resumption: Yup.string()
|
||||
resumption_date: Yup.string()
|
||||
.required("Required"),
|
||||
employer_email: Yup.string()
|
||||
email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
annual_income: Yup.string()
|
||||
@@ -54,9 +54,9 @@ const validationSchema = Yup.object().shape({
|
||||
}),
|
||||
salary_payment_date: Yup.string()
|
||||
.required("Required"),
|
||||
employee_id: Yup.string()
|
||||
employment_id: Yup.string()
|
||||
.required("Required"),
|
||||
qualification: Yup.string()
|
||||
highest_eductaion: Yup.string()
|
||||
.required("Required"),
|
||||
});
|
||||
|
||||
@@ -65,8 +65,7 @@ export default function DashboardHomeEmploymentInfo({handleNextStep}:Props) {
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
handleNextStep({employment: values})
|
||||
};
|
||||
|
||||
|
||||
@@ -99,29 +98,29 @@ export default function DashboardHomeEmploymentInfo({handleNextStep}:Props) {
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="employer_name"
|
||||
name="name"
|
||||
floatLabel="Employer name"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="Mr. Mark John"
|
||||
value={props.values.employer_name}
|
||||
value={props.values.name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employer_name && props.touched.employer_name) ? props.errors.employer_name : ''}
|
||||
error={(props.errors.name && props.touched.name) ? props.errors.name : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[4.125rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="job_sector"
|
||||
name="sector"
|
||||
floatLabel="Job Sector"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={jobSector}
|
||||
selectValue={props.values.job_sector}
|
||||
selectValue={props.values.sector}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.job_sector && props.touched.job_sector) ? props.errors.job_sector : ''}
|
||||
error={(props.errors.sector && props.touched.sector) ? props.errors.sector : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
@@ -139,28 +138,28 @@ export default function DashboardHomeEmploymentInfo({handleNextStep}:Props) {
|
||||
<div className="flex items-center gap-[4.125rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="date_of_resumption"
|
||||
name="resumption_date"
|
||||
floatLabel="Date of resumption"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputType='date'
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="12/12/2015"
|
||||
value={props.values.date_of_resumption}
|
||||
value={props.values.resumption_date}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.date_of_resumption && props.touched.date_of_resumption) ? props.errors.date_of_resumption : ''}
|
||||
error={(props.errors.resumption_date && props.touched.resumption_date) ? props.errors.resumption_date : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="employer_email"
|
||||
name="email"
|
||||
floatLabel="Employers official email"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="example@gmail.com"
|
||||
value={props.values.employer_email}
|
||||
value={props.values.email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employer_email && props.touched.employer_email) ? props.errors.employer_email : ''}
|
||||
error={(props.errors.email && props.touched.email) ? props.errors.email : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[4.125rem]">
|
||||
@@ -205,28 +204,28 @@ export default function DashboardHomeEmploymentInfo({handleNextStep}:Props) {
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="employee_id"
|
||||
name="employment_id"
|
||||
floatLabel="Employee ID"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="LS/001/005"
|
||||
value={props.values.employee_id}
|
||||
value={props.values.employment_id}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employee_id && props.touched.employee_id) ? props.errors.employee_id : ''}
|
||||
error={(props.errors.employment_id && props.touched.employment_id) ? props.errors.employment_id : ''}
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="qualification"
|
||||
name="highest_eductaion"
|
||||
floatLabel="Highest level of education"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={qualification}
|
||||
selectValue={props.values.qualification}
|
||||
selectOptions={highestEductaion}
|
||||
selectValue={props.values.highest_eductaion}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.qualification && props.touched.qualification) ? props.errors.qualification : ''}
|
||||
error={(props.errors.highest_eductaion && props.touched.highest_eductaion) ? props.errors.highest_eductaion : ''}
|
||||
/>
|
||||
<Button
|
||||
className="my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
|
||||
@@ -266,7 +265,7 @@ const industry: SelectOption = {
|
||||
]
|
||||
}
|
||||
|
||||
const qualification: SelectOption = {
|
||||
const highestEductaion: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Please Select" },
|
||||
|
||||
@@ -4,18 +4,18 @@ import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
type Props = {
|
||||
handleNextStep:()=>any
|
||||
handleNextStep:(value:{})=>any
|
||||
}
|
||||
|
||||
const initialValues = {
|
||||
ref_name: "",
|
||||
ref_email: "",
|
||||
ref_number: "",
|
||||
ref_phone_number: "",
|
||||
ref_relationship: "",
|
||||
ref_bvn: "",
|
||||
ref_two_name: "",
|
||||
ref_two_email: "",
|
||||
ref_two_number: "",
|
||||
ref_two_phone_number: "",
|
||||
ref_two_relationship: "",
|
||||
ref_two_bvn: "",
|
||||
};
|
||||
@@ -27,31 +27,60 @@ const validationSchema = Yup.object().shape({
|
||||
ref_email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
ref_number: Yup.string()
|
||||
ref_phone_number: Yup.string()
|
||||
.required("Required"),
|
||||
ref_relationship: Yup.string()
|
||||
.required("Required"),
|
||||
ref_bvn: Yup.string()
|
||||
.required("Required"),
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
ref_two_name: Yup.string()
|
||||
.required("Required"),
|
||||
ref_two_email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
ref_two_number: Yup.string()
|
||||
ref_two_phone_number: Yup.string()
|
||||
.required("Required"),
|
||||
ref_two_relationship: Yup.string()
|
||||
.required("Required"),
|
||||
ref_two_bvn: Yup.string()
|
||||
.required("Required"),
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
});
|
||||
|
||||
export default function DashboardHomeRefereeInfo({handleNextStep}:Props) {
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
let refOne = {
|
||||
fullname: values.ref_name,
|
||||
relationship: values.ref_relationship,
|
||||
phone_number: values.ref_phone_number,
|
||||
email: values.ref_email,
|
||||
bvn: values.ref_bvn
|
||||
}
|
||||
let refTwo = {
|
||||
fullname: values.ref_two_name,
|
||||
relationship: values.ref_two_relationship,
|
||||
phone_number: values.ref_two_phone_number,
|
||||
email: values.ref_two_email,
|
||||
bvn: values.ref_two_bvn
|
||||
}
|
||||
handleNextStep({loan_reference:[refOne, refTwo]})
|
||||
};
|
||||
|
||||
|
||||
@@ -99,15 +128,15 @@ export default function DashboardHomeRefereeInfo({handleNextStep}:Props) {
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="ref_number"
|
||||
name="ref_phone_number"
|
||||
floatLabel="Phone number"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="07000000000"
|
||||
value={props.values.ref_number}
|
||||
value={props.values.ref_phone_number}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_number && props.touched.ref_number) ? props.errors.ref_number : ''}
|
||||
error={(props.errors.ref_phone_number && props.touched.ref_phone_number) ? props.errors.ref_phone_number : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
@@ -164,15 +193,15 @@ export default function DashboardHomeRefereeInfo({handleNextStep}:Props) {
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="ref_two_number"
|
||||
name="ref_two_phone_number"
|
||||
floatLabel="Phone number"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="07000000000"
|
||||
value={props.values.ref_two_number}
|
||||
value={props.values.ref_two_phone_number}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_two_number && props.touched.ref_two_number) ? props.errors.ref_two_number : ''}
|
||||
error={(props.errors.ref_two_phone_number && props.touched.ref_two_phone_number) ? props.errors.ref_two_phone_number : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import DebitAccount from "./DebitAccount";
|
||||
|
||||
|
||||
const ApplicantsAttestation: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,61 +1,87 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import InputDetails from "./IntroDetails";
|
||||
import OTPSection from "./OtpSection";
|
||||
import SpouseDetails from "./SpouseDetails";
|
||||
import { Button } from "..";
|
||||
import React from "react";
|
||||
|
||||
// interface Option {
|
||||
// value: string;
|
||||
// label: string;
|
||||
// }
|
||||
import { Button, InputCompOne } from "..";
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
const initialValues = {
|
||||
title: "",
|
||||
marital_status: "",
|
||||
agent_id: "",
|
||||
bvn: "",
|
||||
first_name: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
surname: "",
|
||||
dob: "",
|
||||
second_name: "",
|
||||
spouse_bvn: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
title: Yup.string()
|
||||
.required("Required"),
|
||||
marital_status: Yup.string()
|
||||
.required("Required"),
|
||||
agent_id: Yup.string()
|
||||
.required("Required"),
|
||||
bvn: Yup.string()
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
first_name: Yup.string()
|
||||
.required("Required"),
|
||||
phone: Yup.string()
|
||||
.required("Required"),
|
||||
email: Yup.string()
|
||||
.required("Required")
|
||||
.email("Wrong email format"),
|
||||
surname: Yup.string()
|
||||
.required("Required"),
|
||||
dob: Yup.string()
|
||||
.required("Required"),
|
||||
});
|
||||
|
||||
interface BasicInfoProps {
|
||||
inputValues: {
|
||||
title: string;
|
||||
marital: string;
|
||||
agentId: string;
|
||||
bvn: string;
|
||||
firstName: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
surname: string;
|
||||
dob: string;
|
||||
secondName: string;
|
||||
spouseBVN: string;
|
||||
};
|
||||
setInputValues: React.Dispatch<React.SetStateAction<any>>;
|
||||
handleNextStep: any;
|
||||
}
|
||||
|
||||
const BasicInfo: React.FC<BasicInfoProps> = ({
|
||||
inputValues,
|
||||
setInputValues,
|
||||
handleNextStep,
|
||||
}) => {
|
||||
const [hideOTPComponent, setHideOTPComponent] = useState<boolean>(false);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
// const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target as HTMLInputElement;
|
||||
setInputValues((prev: typeof inputValues) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
// const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
// const { name, value } = e.target as HTMLInputElement;
|
||||
|
||||
const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
const { name, value } = e.target as HTMLInputElement;
|
||||
// if (name === "bvn") {
|
||||
// const isNumeric = /^[0-9]+$/.test(value);
|
||||
|
||||
if (name === "bvn") {
|
||||
const isNumeric = /^[0-9]+$/.test(value);
|
||||
// if (isNumeric) {
|
||||
// if (value.length === 10) {
|
||||
// setHideOTPComponent(false);
|
||||
// } else {
|
||||
// setHideOTPComponent(true);
|
||||
// }
|
||||
// } else {
|
||||
// console.log("Invalid BVN");
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
if (isNumeric) {
|
||||
if (value.length === 10) {
|
||||
setHideOTPComponent(false);
|
||||
} else {
|
||||
setHideOTPComponent(true);
|
||||
}
|
||||
} else {
|
||||
console.log("Invalid BVN");
|
||||
}
|
||||
}
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -64,38 +90,222 @@ const BasicInfo: React.FC<BasicInfoProps> = ({
|
||||
<h1 className="font-semibold text-[2.375rem] text-[#5C2684] my-[.5rem]">
|
||||
Let’s Get You Started
|
||||
</h1>
|
||||
<form>
|
||||
<InputDetails
|
||||
inputValues={inputValues}
|
||||
handleChange={handleChange}
|
||||
handleInput={handleInput}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
{!hideOTPComponent && (
|
||||
<>
|
||||
<OTPSection
|
||||
inputValues={inputValues}
|
||||
handleChange={handleChange}
|
||||
handleInput={handleInput}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
<SpouseDetails
|
||||
inputValues={inputValues}
|
||||
handleChange={handleChange}
|
||||
handleInput={handleInput}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
<Button
|
||||
className="mt-8 btn-R bg-[#5A2C82]"
|
||||
text="Enter"
|
||||
type="button"
|
||||
onClick={handleNextStep}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props)=>(
|
||||
<Form>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
BASIC INFORMATION
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-2">
|
||||
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
|
||||
<InputCompOne
|
||||
parentInputClass="max-w-[224px] w-full"
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="title"
|
||||
label="Title"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
select={true}
|
||||
selectClass="w-full h-[36px] rounded-[6px]"
|
||||
selectOptions={titleOptions}
|
||||
selectValue={props.values.title}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.title && props.touched.title) ? props.errors.title : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentInputClass="max-w-[224px] w-full"
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="marital_status"
|
||||
label="Marital Status"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
select={true}
|
||||
selectClass="w-full h-[36px] rounded-[6px]"
|
||||
selectOptions={maritalStatusOptions}
|
||||
selectValue={props.values.marital_status}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.marital_status && props.touched.marital_status) ? props.errors.marital_status : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentInputClass="max-w-[224px] w-full"
|
||||
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
|
||||
name="agent_id"
|
||||
label="Direct Sales Agent ID"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
select={true}
|
||||
selectClass="w-full h-[36px] rounded-[6px]"
|
||||
selectOptions={{loading: false, data:[{ value: "", label: "Select" }, { value: "dd", label: "AB001" }]}}
|
||||
selectValue={props.values.agent_id}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.agent_id && props.touched.agent_id) ? props.errors.agent_id : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
label="BVN"
|
||||
name="bvn"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
placeholder="Enter your BVN"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px] gap-[2px]"
|
||||
input={true}
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] rounded-[6px]"
|
||||
value={props.values.bvn}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.bvn && props.touched.bvn) ? props.errors.bvn : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="First Name"
|
||||
name="first_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.first_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.first_name && props.touched.first_name) ? props.errors.first_name : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Phone Number"
|
||||
name="phone"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.phone}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.phone && props.touched.phone) ? props.errors.phone : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Email Address"
|
||||
name="email"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.email && props.touched.email) ? props.errors.email : ''}
|
||||
/>
|
||||
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Surname"
|
||||
name="surname"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem] px-3"
|
||||
value={props.values.surname}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.surname && props.touched.surname) ? props.errors.surname : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Date of Birth"
|
||||
name="dob"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputType='date'
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem] px-3"
|
||||
value={props.values.dob}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.dob && props.touched.dob) ? props.errors.dob : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Second Name"
|
||||
name="second_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem] px-3"
|
||||
value={props.values.second_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.second_name && props.touched.second_name) ? props.errors.second_name : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5 mt-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
SPOUSE DETAILS ( If not applicable, please move to the next stage )
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-2">
|
||||
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="BVN"
|
||||
name="spouse_bvn"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.spouse_bvn}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.spouse_bvn && props.touched.spouse_bvn) ? props.errors.spouse_bvn : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<>
|
||||
<Button
|
||||
className="mt-8 btn-R bg-[#5A2C82]"
|
||||
text="Enter"
|
||||
type="submit"
|
||||
/>
|
||||
</>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BasicInfo;
|
||||
|
||||
|
||||
|
||||
interface SelectOption {
|
||||
loading: boolean;
|
||||
data: {value: string;
|
||||
label: string}[]
|
||||
}
|
||||
|
||||
const maritalStatusOptions: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Select" },
|
||||
{ value: "single", label: "Single" },
|
||||
{ value: "married", label: "Married" },
|
||||
{ value: "divorced", label: "Divorced" },
|
||||
{ value: "widowed", label: "Widowed" },
|
||||
]
|
||||
}
|
||||
|
||||
const titleOptions: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Select" },
|
||||
{ value: "ms", label: "Ms" },
|
||||
{ value: "mr", label: "Mr" },
|
||||
{ value: "miss", label: "Miss" },
|
||||
{ value: "mrs", label: "Mrs" },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,8 +3,40 @@ import {useNavigate} from 'react-router-dom'
|
||||
import { Button, InputCompOne } from "..";
|
||||
import { RouteHandler } from "../../router/routes";
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
const initialValues = {
|
||||
disburse_account: "",
|
||||
bank_name: "",
|
||||
account_name: "",
|
||||
account_number: "",
|
||||
checked: false
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
disburse_account: Yup.string()
|
||||
.required("Required"),
|
||||
bank_name: Yup.string()
|
||||
.required("Required"),
|
||||
account_name: Yup.string()
|
||||
.required("Required"),
|
||||
account_number: Yup.string()
|
||||
.required("Required"),
|
||||
checked: Yup.bool() // use bool instead of boolean
|
||||
.oneOf([true], "You must accept the terms and conditions")
|
||||
});
|
||||
|
||||
const DebitAccount: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
navigate(RouteHandler.letsGetStarted, {replace:true})
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full rounded py-3 mb-9 bg-[#5C2684] px-5">
|
||||
@@ -12,78 +44,101 @@ const DebitAccount: React.FC = () => {
|
||||
CREDIT ACCOUNT ( Your account to receive your loan )
|
||||
</p>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[29.4375rem] w-full my-5 ml-5"
|
||||
label="Disbursement Account Number "
|
||||
name="disbursementAccountNumber"
|
||||
labelSpan="( Your FCMB Account )"
|
||||
labelSpanClass="text-[12px] text-[#5C2684] ml-1"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] px-[2px] rounded-[6px]"
|
||||
/>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props)=>(
|
||||
<Form>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[29.4375rem] w-full my-5 ml-5"
|
||||
label="Disbursement Account Number "
|
||||
name="disburse_account"
|
||||
labelSpan="( Your FCMB Account )"
|
||||
labelSpanClass="text-[12px] text-[#5C2684] ml-1"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] rounded-[6px]"
|
||||
value={props.values.disburse_account}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.disburse_account && props.touched.disburse_account) ? props.errors.disburse_account : ''}
|
||||
/>
|
||||
|
||||
<div className="mt-9 flex flex-col gap-9">
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
DEBIT ACCOUNT ( Your salary account for monthly repayment )
|
||||
</p>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[471px] w-full ml-5"
|
||||
label="Bank Name"
|
||||
name="bankName"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] px-[2px] rounded-[6px]"
|
||||
/>
|
||||
<div className="mt-9 flex flex-col gap-9">
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
DEBIT ACCOUNT ( Your salary account for monthly repayment )
|
||||
</p>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[471px] w-full ml-5"
|
||||
label="Bank Name"
|
||||
name="bank_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] rounded-[6px]"
|
||||
value={props.values.bank_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.bank_name && props.touched.bank_name) ? props.errors.bank_name : ''}
|
||||
/>
|
||||
|
||||
<div className="flex items-center gap-[59px]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[471px] w-full ml-5"
|
||||
label="Account Number"
|
||||
name="accountNumber"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] px-[2px] rounded-[6px]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[471px] w-full ml-5"
|
||||
label="Account Name"
|
||||
name="accountName"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] px-[2px] rounded-[6px]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[59px]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[471px] w-full ml-5"
|
||||
label="Account Number"
|
||||
name="account_number"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] rounded-[6px]"
|
||||
value={props.values.account_number}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.account_number && props.touched.account_number) ? props.errors.account_number : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[471px] w-full ml-5"
|
||||
label="Account Name"
|
||||
name="account_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[36px] bg-[#EFEFEF] rounded-[6px]"
|
||||
value={props.values.account_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.account_name && props.touched.account_name) ? props.errors.account_name : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="max-w-[578px] flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
// checked={true}
|
||||
defaultChecked
|
||||
// onChange={onChange}
|
||||
className="form-checkbox h-[25px] w-[25px] rounded-sm text-[#5c2684] "
|
||||
style={{ backgroundColor: "#5C2684" }}
|
||||
/>
|
||||
<label className="ml-2 text-gray-700">
|
||||
I have read, understood and accept the{" "}
|
||||
<span className="text-[#4545CB]">applicant's attestation</span> and
|
||||
all the <span className="text-[#4545CB]">terms and conditions</span>{" "}
|
||||
for FCMB premium salary loan.
|
||||
</label>
|
||||
</div>
|
||||
<Button
|
||||
className="my-8 max-w-[33.875rem] btn-R bg-[#5A2C82] w-full h-11"
|
||||
text="Apply"
|
||||
type="button"
|
||||
onClick={()=>navigate(RouteHandler.letsGetStarted, {replace:true})}
|
||||
/>
|
||||
</div>
|
||||
<div className="max-w-[578px] flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
// checked={true}
|
||||
|
||||
name='checked'
|
||||
onChange={props.handleChange}
|
||||
className="form-checkbox h-[25px] w-[25px] rounded-sm text-[#5c2684] "
|
||||
style={{ backgroundColor: "#5C2684" }}
|
||||
/>
|
||||
<label className="ml-2 text-gray-700">
|
||||
I have read, understood and accept the{" "}
|
||||
<span className="text-[#4545CB]">applicant's attestation</span> and
|
||||
all the <span className="text-[#4545CB]">terms and conditions</span>{" "}
|
||||
for FCMB premium salary loan.
|
||||
</label>
|
||||
{props.errors.checked && props.touched.checked && <span className='text-[10px] text-red-500'>{props.errors.checked}</span>}
|
||||
</div>
|
||||
<Button
|
||||
className="my-8 max-w-[33.875rem] btn-R bg-[#5A2C82] w-full h-11"
|
||||
text="Apply"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
import React from "react";
|
||||
import { InputCompOne } from "..";
|
||||
|
||||
const EmploymentDetails: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
EMPLOYMENT DETAILS
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[17.9375rem] w-full"
|
||||
label="Job Title"
|
||||
name="jobTitle"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<div className="flex items-center gap-[3.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Employer’s Name"
|
||||
name="employerName"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Employer’s Official Email"
|
||||
name="employerOfficialEmail"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[9rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[17.9375rem] w-full"
|
||||
label="Resumption Date"
|
||||
name="resumptionDate"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[17.9375rem] w-full"
|
||||
label="Employee ID."
|
||||
name="employeeID"
|
||||
labelSpan="Upload your work ID"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[3.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Salary ( Gross annual income )"
|
||||
name="salaryGross"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Salary ( Net monthly Income )"
|
||||
name="salaryNet"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Salary Payment Date"
|
||||
name="salary-payment-date"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmploymentDetails;
|
||||
@@ -1,35 +1,9 @@
|
||||
import React from "react";
|
||||
import BasicInfo from "./BasicInfo";
|
||||
import YourAreAlmostThere from "./YourAreAlmostThere";
|
||||
import LoanAmountComp from "./LoanAmountComp";
|
||||
import ApplicantsAttestation from "./ApplicantsAttestation";
|
||||
|
||||
const GetStarted = ({handleNextStep, step}:{handleNextStep:any, step:string|number|any}) => {
|
||||
// const [step, setStep] = React.useState(1);
|
||||
|
||||
// const handleNextStep = () => {
|
||||
// if (step < 5) {
|
||||
// setStep(step + 1);
|
||||
// }
|
||||
// };
|
||||
|
||||
// const handlePreviousStep: React.MouseEvent<HTMLButtonElement> = () => {
|
||||
// setStep(step - 1);
|
||||
// };
|
||||
|
||||
const [inputValues, setInputValues] = React.useState({
|
||||
title: "",
|
||||
marital: "",
|
||||
agentId: "",
|
||||
bvn: "",
|
||||
firstName: "",
|
||||
phone: "",
|
||||
email: "",
|
||||
surname: "",
|
||||
dob: "",
|
||||
secondName: "",
|
||||
spouseBVN: "",
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="w-full flex items-center justify-center">
|
||||
@@ -38,8 +12,6 @@ const GetStarted = ({handleNextStep, step}:{handleNextStep:any, step:string|numb
|
||||
<main>
|
||||
{step === 2 && (
|
||||
<BasicInfo
|
||||
inputValues={inputValues}
|
||||
setInputValues={setInputValues}
|
||||
handleNextStep={handleNextStep}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
import React from "react";
|
||||
import InputCompOne from "../shared/InputCompOne";
|
||||
|
||||
interface SelectOption {
|
||||
loading: boolean;
|
||||
data: {value: string;
|
||||
label: string}[]
|
||||
}
|
||||
|
||||
interface InputSectionProps {
|
||||
inputValues: {
|
||||
title: string;
|
||||
marital: string;
|
||||
agentId: string;
|
||||
bvn: string;
|
||||
};
|
||||
handleChange: (e: React.FormEvent<HTMLInputElement>) => void;
|
||||
handleInput: (e: React.FormEvent<HTMLInputElement>) => void;
|
||||
inputRef: React.RefObject<HTMLInputElement>;
|
||||
}
|
||||
|
||||
const InputSection: React.FC<InputSectionProps> = ({
|
||||
inputValues,
|
||||
handleChange,
|
||||
handleInput,
|
||||
inputRef,
|
||||
}) => {
|
||||
const basicInfoInputFields = [
|
||||
{
|
||||
label: "Title",
|
||||
name: "title",
|
||||
parentInputClass: "max-w-[224px] w-full",
|
||||
labelClass:
|
||||
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]",
|
||||
select: true,
|
||||
selectClass: "w-full h-[36px] rounded-[6px]",
|
||||
selectOptions: titleOptions,
|
||||
value: inputValues.title,
|
||||
},
|
||||
{
|
||||
label: "Marital Status",
|
||||
name: "marital",
|
||||
parentInputClass: "max-w-[224px] w-full",
|
||||
labelClass:
|
||||
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]",
|
||||
select: true,
|
||||
selectClass: "w-full h-[36px] rounded-[6px]",
|
||||
selectOptions: maritalStatusOptions,
|
||||
value: inputValues.marital,
|
||||
onInput: handleInput,
|
||||
},
|
||||
{
|
||||
label: "Direct Sales Agent ID",
|
||||
name: "agentId",
|
||||
parentInputClass: "max-w-[224px] w-full",
|
||||
labelClass:
|
||||
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]",
|
||||
select: true,
|
||||
selectClass: "w-full h-[36px] rounded-[6px]",
|
||||
selectOptions: {loading: false, data:[{ value: "", label: "Select" }]},
|
||||
value: inputValues.agentId,
|
||||
onInput: handleInput,
|
||||
},
|
||||
{
|
||||
label: "BVN",
|
||||
name: "bvn",
|
||||
parentInputClass: " w-full",
|
||||
labelSpan: "( To get your BVN, dial *565*0# )",
|
||||
labelSpanClass: "text-[11px] text-[#7a7373]",
|
||||
placeholder: "Enter your BVN",
|
||||
labelClass:
|
||||
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px] gap-[2px]",
|
||||
input: true,
|
||||
inputClass: "w-full h-[36px] bg-[#EFEFEF] px-[2px] rounded-[6px]",
|
||||
value: inputValues.bvn,
|
||||
onInput: handleInput,
|
||||
maxLength: 10,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
BASIC INFORMATION
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-2">
|
||||
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
|
||||
{basicInfoInputFields.map((field, index) => (
|
||||
<InputCompOne
|
||||
key={index}
|
||||
label={field.label}
|
||||
name={field.name}
|
||||
parentInputClass={field.parentInputClass}
|
||||
labelClass={field.labelClass}
|
||||
select={field.select}
|
||||
selectClass={field.selectClass}
|
||||
selectOptions={field.selectOptions}
|
||||
value={field.value}
|
||||
onChange={handleChange}
|
||||
onInput={field.onInput}
|
||||
placeholder={field.placeholder}
|
||||
labelSpan={field.labelSpan}
|
||||
labelSpanClass={field.labelSpanClass}
|
||||
input={field.input}
|
||||
inputClass={field.inputClass}
|
||||
maxLength={field.maxLength}
|
||||
ref={inputRef}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputSection;
|
||||
|
||||
const maritalStatusOptions: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Select" },
|
||||
{ value: "single", label: "Single" },
|
||||
{ value: "married", label: "Married" },
|
||||
{ value: "divorced", label: "Divorced" },
|
||||
{ value: "widowed", label: "Widowed" },
|
||||
]
|
||||
}
|
||||
|
||||
const titleOptions: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Select" },
|
||||
{ value: "ms", label: "Ms" },
|
||||
{ value: "mr", label: "Mr" },
|
||||
{ value: "miss", label: "Miss" },
|
||||
{ value: "mrs", label: "Mrs" },
|
||||
]
|
||||
}
|
||||
@@ -1,20 +1,56 @@
|
||||
import React from "react";
|
||||
import { Button, InputCompOne } from "..";
|
||||
|
||||
interface SliderProps {
|
||||
handleSliderChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
value: number;
|
||||
}
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
const initialValues = {
|
||||
monthly_salary: "",
|
||||
loan_amount: "",
|
||||
duration: 6
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
duration: Yup.number()
|
||||
.required("Required"),
|
||||
monthly_salary: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
loan_amount: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
});
|
||||
|
||||
// interface SliderProps {
|
||||
// handleSliderChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
// value: number;
|
||||
// }
|
||||
|
||||
interface LoanAmountProps {
|
||||
handleNextStep: any;
|
||||
}
|
||||
|
||||
const LoanAmountComp: React.FC<LoanAmountProps> = ({ handleNextStep }) => {
|
||||
const [value, setValue] = React.useState(6);
|
||||
// const [value, setValue] = React.useState(6);
|
||||
|
||||
const handleSliderChange = (e: any) => {
|
||||
setValue(e.target.value);
|
||||
// const handleSliderChange = (e: any) => {
|
||||
// setValue(e.target.value);
|
||||
// };
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -35,95 +71,132 @@ const LoanAmountComp: React.FC<LoanAmountProps> = ({ handleNextStep }) => {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-[45px] justify-center ml-[40px] mb-[40px]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[29.4375rem] w-full"
|
||||
label="Your Monthly Salary*"
|
||||
name="salary"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[51px] bg-[#EFEFEF] rounded-[6px] placeholder:text-green-600 placeholder:font-bold px-4"
|
||||
placeholder="150,000"
|
||||
/>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props)=>(
|
||||
<Form>
|
||||
<div className="flex flex-col gap-[45px] justify-center ml-[40px] mb-[40px]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[29.4375rem] w-full"
|
||||
label="Your Monthly Salary*"
|
||||
name="monthly_salary"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[51px] bg-[#EFEFEF] rounded-[6px] placeholder:text-green-600 placeholder:font-bold px-4"
|
||||
placeholder="150,000"
|
||||
value={props.values.monthly_salary}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.monthly_salary && props.touched.monthly_salary) ? props.errors.monthly_salary : ''}
|
||||
/>
|
||||
|
||||
<div className="w-full border-[.1875rem] rounded-xl border-black min-h-[884px] py-4 px-8 max-w-[784px]">
|
||||
<p className="leading-[22px] tracking-[3%] text-[#5C2684] w-[729px] mb-[2.625rem]">
|
||||
The maximum amount you can apply for on this offer is based on the
|
||||
information you shared with us in your loan application. We have
|
||||
made this offer to suit your monthly remuneration and to enable you
|
||||
pay your loan on-time
|
||||
</p>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[45.8125rem] w-full mb-3"
|
||||
label="How much do you want to apply for?"
|
||||
name="loan"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[51px] bg-[#EFEFEF] rounded-[6px] placeholder:text-green-600 placeholder:font-bold px-9"
|
||||
placeholder="350,000"
|
||||
/>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className=" h-[68px] flex flex-col py-1 px-[13px] shadow-md text-[#5C2684]">
|
||||
<span>Minimum Offer:</span>
|
||||
<p>
|
||||
<b>N</b>100,000
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-full border-[.1875rem] rounded-xl border-black min-h-[884px] py-4 px-8 max-w-[784px]">
|
||||
<p className="leading-[22px] tracking-[3%] text-[#5C2684] w-[729px] mb-[2.625rem]">
|
||||
The maximum amount you can apply for on this offer is based on the
|
||||
information you shared with us in your loan application. We have
|
||||
made this offer to suit your monthly remuneration and to enable you
|
||||
pay your loan on-time
|
||||
</p>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[45.8125rem] w-full mb-3"
|
||||
label="How much do you want to apply for?"
|
||||
name="loan_amount"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[18px] leading-[21.7808px] tracking-[2%] text-[#5C2684] mb-[2px]"
|
||||
input
|
||||
inputClass="w-full h-[51px] bg-[#EFEFEF] rounded-[6px] placeholder:text-green-600 placeholder:font-bold px-9"
|
||||
placeholder="350,000"
|
||||
value={props.values.loan_amount}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.loan_amount && props.touched.loan_amount) ? props.errors.loan_amount : ''}
|
||||
/>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className=" h-[68px] flex flex-col py-1 px-[13px] shadow-md text-[#5C2684]">
|
||||
<span>Minimum Offer:</span>
|
||||
<p>
|
||||
<b>N</b>100,000
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="h-[68px] flex flex-col py-1 px-[13px] shadow-md text-[#5C2684]">
|
||||
<span>Maximum Offer:</span>
|
||||
<p>
|
||||
<b>N</b>500,000
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-[68px] flex flex-col py-1 px-[13px] shadow-md text-[#5C2684]">
|
||||
<span>Maximum Offer:</span>
|
||||
<p>
|
||||
<b>N</b>500,000
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Slider handleSliderChange={handleSliderChange} value={value} />
|
||||
<>
|
||||
<div className="flex flex-col items-start mt-11 mb-16">
|
||||
<p className="text-lg font-semibold">For how many months? <span className='text-[10px] text-red-500'>{(props.errors.duration && props.touched.duration) ? props.errors.duration : ''}</span></p>
|
||||
<div className="w-full">
|
||||
<input
|
||||
type="range"
|
||||
min="6"
|
||||
max="24"
|
||||
value={props.values.duration}
|
||||
onChange={props.handleChange}
|
||||
className="slider w-full h-2 bg-gray-300 rounded-lg appearance-none cursor-pointer"
|
||||
style={{
|
||||
background: `linear-gradient(90deg, #6B21A8 ${
|
||||
((props.values.duration - 6) / 18) * 100
|
||||
}%, #D1D5DB ${((props.values.duration - 6) / 18) * 100}%)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 text-lg font-semibold text-gray-700 w-full flex items-center text-center justify-center">
|
||||
{props.values.duration} months
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
<div className="w-full flex items-center justify-center flex-col">
|
||||
<div className="w-[279px] h-[130px] mb-[76px] flex items-center justify-center flex-col">
|
||||
<p className="text-[#FBB700]">Your Monthly Repayment</p>
|
||||
<p>N</p>
|
||||
</div>
|
||||
<Button
|
||||
className="max-w-[462px] w-full bg-[#5C2684] rounded h-[2.75rem]"
|
||||
text="Submit"
|
||||
type="button"
|
||||
onClick={handleNextStep}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full flex items-center justify-center flex-col">
|
||||
<div className="w-[279px] h-[130px] mb-[76px] flex items-center justify-center flex-col">
|
||||
<p className="text-[#FBB700]">Your Monthly Repayment</p>
|
||||
<p>N</p>
|
||||
</div>
|
||||
<Button
|
||||
className="max-w-[462px] w-full bg-[#5C2684] rounded h-[2.75rem]"
|
||||
text="Submit"
|
||||
type='submit'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoanAmountComp;
|
||||
|
||||
const Slider: React.FC<SliderProps> = ({ handleSliderChange, value }) => {
|
||||
return (
|
||||
<div className="flex flex-col items-start mt-11 mb-16">
|
||||
<p className="text-lg font-semibold">For how many months?</p>
|
||||
<div className="w-full">
|
||||
<input
|
||||
type="range"
|
||||
min="6"
|
||||
max="24"
|
||||
value={value}
|
||||
onChange={handleSliderChange}
|
||||
className="slider w-full h-2 bg-gray-300 rounded-lg appearance-none cursor-pointer"
|
||||
style={{
|
||||
background: `linear-gradient(90deg, #6B21A8 ${
|
||||
((value - 6) / 18) * 100
|
||||
}%, #D1D5DB ${((value - 6) / 18) * 100}%)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-4 text-lg font-semibold text-gray-700 w-full flex items-center text-center justify-center">
|
||||
{value} months
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
// const Slider: React.FC<SliderProps> = ({ handleSliderChange, value }) => {
|
||||
// return (
|
||||
// <div className="flex flex-col items-start mt-11 mb-16">
|
||||
// <p className="text-lg font-semibold">For how many months?</p>
|
||||
// <div className="w-full">
|
||||
// <input
|
||||
// type="range"
|
||||
// min="6"
|
||||
// max="24"
|
||||
// value={value}
|
||||
// onChange={handleSliderChange}
|
||||
// className="slider w-full h-2 bg-gray-300 rounded-lg appearance-none cursor-pointer"
|
||||
// style={{
|
||||
// background: `linear-gradient(90deg, #6B21A8 ${
|
||||
// ((value - 6) / 18) * 100
|
||||
// }%, #D1D5DB ${((value - 6) / 18) * 100}%)`,
|
||||
// }}
|
||||
// />
|
||||
// </div>
|
||||
// <div className="mt-4 text-lg font-semibold text-gray-700 w-full flex items-center text-center justify-center">
|
||||
// {value} months
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
import React from "react";
|
||||
import InputCompOne from "../shared/InputCompOne";
|
||||
|
||||
interface OTPSectionProps {
|
||||
inputValues: {
|
||||
firstName: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
surname: string;
|
||||
dob: string;
|
||||
secondName: string;
|
||||
};
|
||||
handleChange: (e: React.FormEvent<HTMLInputElement>) => void;
|
||||
handleInput: (e: React.FormEvent<HTMLInputElement>) => void;
|
||||
inputRef: React.RefObject<HTMLInputElement>;
|
||||
}
|
||||
|
||||
const OTPSection: React.FC<OTPSectionProps> = ({
|
||||
inputValues,
|
||||
handleChange,
|
||||
handleInput,
|
||||
inputRef,
|
||||
}) => {
|
||||
return (
|
||||
<div className="mt-5">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="First Name"
|
||||
name="firstName"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
value={inputValues.firstName}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Phone Number"
|
||||
name="phone"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
value={inputValues.phone}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Email Address"
|
||||
name="email"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
value={inputValues.email}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Surname"
|
||||
name="surname"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem] px-3"
|
||||
value={inputValues.surname}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Date of Birth"
|
||||
name="dob"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem] px-3"
|
||||
value={inputValues.dob}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Second Name"
|
||||
name="secondName"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem] px-3"
|
||||
value={inputValues.secondName}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OTPSection;
|
||||
@@ -1,126 +0,0 @@
|
||||
import React from "react";
|
||||
import { InputCompOne } from "..";
|
||||
|
||||
const ReferenceDetails: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
REFERENCE DETAILS ( Must be 18 years and above )
|
||||
</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex flex-col gap-[3.4375rem]">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Name"
|
||||
name="referenceName"
|
||||
labelSpan="1st reference"
|
||||
labelSpanClass="text-[12px] text-[#5C2684] ml-1"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Relationship with He/She"
|
||||
name="referenceRelationship"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Phone Number"
|
||||
name="referencePhoneNumber"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Email Address"
|
||||
name="referenceEmail"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="BVN"
|
||||
name="ReferenceBvn"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Name"
|
||||
name="referenceName2"
|
||||
labelSpan="2nd reference"
|
||||
labelSpanClass="text-[12px] text-[#5C2684] ml-[4px]"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Relationship with He/She"
|
||||
name="referenceRelationship2"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Phone Number"
|
||||
name="referencePhoneNumber2"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Email Address"
|
||||
name="referenceEmail2"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="BVN"
|
||||
name="ReferenceBvn2"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReferenceDetails;
|
||||
@@ -1,49 +0,0 @@
|
||||
import React from "react";
|
||||
import { InputCompOne } from "..";
|
||||
|
||||
interface SpouseDetailsProps {
|
||||
inputValues: {
|
||||
spouseBVN: string;
|
||||
};
|
||||
handleChange: (e: React.FormEvent<HTMLInputElement>) => void;
|
||||
handleInput: (e: React.FormEvent<HTMLInputElement>) => void;
|
||||
inputRef: React.RefObject<HTMLInputElement>;
|
||||
}
|
||||
|
||||
const SpouseDetails: React.FC<SpouseDetailsProps> = ({
|
||||
inputValues,
|
||||
handleChange,
|
||||
handleInput,
|
||||
inputRef,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5 mt-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
SPOUSE DETAILS ( If not applicable, please move to the next stage )
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-8 grid grid-cols-2">
|
||||
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="BVN"
|
||||
name="spouseBVN"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
value={inputValues.spouseBVN}
|
||||
onChange={handleChange}
|
||||
onInput={handleInput}
|
||||
ref={inputRef}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpouseDetails;
|
||||
@@ -1,29 +1,400 @@
|
||||
import React from "react";
|
||||
// import { useNavigate } from "react-router-dom";
|
||||
import EmploymentDetails from "./EmploymentDetails";
|
||||
import ReferenceDetails from "./ReferenceDetails";
|
||||
import { Button } from "..";
|
||||
import { Button, InputCompOne } from "..";
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
const initialValues = {
|
||||
job_title: "",
|
||||
employer_name: "",
|
||||
employer_email:"",
|
||||
date_of_resumption: "",
|
||||
employee_id: "",
|
||||
annual_income: "",
|
||||
monthly_salary: "",
|
||||
salary_payment_date: "",
|
||||
ref_name: "",
|
||||
ref_email: "",
|
||||
ref_number: "",
|
||||
ref_relationship: "",
|
||||
ref_bvn: "",
|
||||
ref_two_name: "",
|
||||
ref_two_email: "",
|
||||
ref_two_number: "",
|
||||
ref_two_relationship: "",
|
||||
ref_two_bvn: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
job_title: Yup.string()
|
||||
.required("Required"),
|
||||
employer_name: Yup.string()
|
||||
.required("Required"),
|
||||
date_of_resumption: Yup.string()
|
||||
.required("Required"),
|
||||
employer_email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
annual_income: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
monthly_salary: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
salary_payment_date: Yup.string()
|
||||
.required("Required"),
|
||||
employee_id: Yup.string()
|
||||
.required("Required"),
|
||||
ref_name: Yup.string()
|
||||
.required("Required"),
|
||||
ref_email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
ref_number: Yup.string()
|
||||
.required("Required"),
|
||||
ref_relationship: Yup.string()
|
||||
.required("Required"),
|
||||
ref_bvn: Yup.string()
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
ref_two_name: Yup.string()
|
||||
.required("Required"),
|
||||
ref_two_email: Yup.string()
|
||||
.email("Invalid")
|
||||
.required("Required"),
|
||||
ref_two_number: Yup.string()
|
||||
.required("Required"),
|
||||
ref_two_relationship: Yup.string()
|
||||
.required("Required"),
|
||||
ref_two_bvn: Yup.string()
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
});
|
||||
|
||||
interface YourAreAlmostThereProps {
|
||||
handleNextStep: any;
|
||||
}
|
||||
|
||||
const YourAreAlmostThere: React.FC<YourAreAlmostThereProps> = ({ handleNextStep }) => {
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:any) => {
|
||||
console.log(values)
|
||||
handleNextStep()
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="font-semibold text-[2.375rem] text-[#5C2684] my-[.5rem]">
|
||||
You’re almost there
|
||||
</h1>
|
||||
<form action="" className="flex flex-col gap-6">
|
||||
<EmploymentDetails />
|
||||
<ReferenceDetails />
|
||||
<Button
|
||||
className="my-8 max-w-[20.3125rem] btn-R bg-[#5A2C82]"
|
||||
text="Continue"
|
||||
type="button"
|
||||
onClick={handleNextStep}
|
||||
/>
|
||||
</form>
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props)=>(
|
||||
<Form>
|
||||
<div className="flex flex-col gap-6">
|
||||
<>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
EMPLOYMENT DETAILS
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[17.9375rem] w-full"
|
||||
label="Job Title"
|
||||
name="job_title"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.job_title}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.job_title && props.touched.job_title) ? props.errors.job_title : ''}
|
||||
/>
|
||||
<div className="flex items-center gap-[3.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Employer’s Name"
|
||||
name="employer_name"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.employer_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employer_name && props.touched.employer_name) ? props.errors.employer_name : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Employer’s Official Email"
|
||||
name="employer_email"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.employer_email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employer_email && props.touched.employer_email) ? props.errors.employer_email : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[9rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[17.9375rem] w-full"
|
||||
label="Resumption Date"
|
||||
name="date_of_resumption"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputType='date'
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.date_of_resumption}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.date_of_resumption && props.touched.date_of_resumption) ? props.errors.date_of_resumption : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[17.9375rem] w-full"
|
||||
label="Employee ID."
|
||||
name="employee_id"
|
||||
labelSpan="Upload your work ID"
|
||||
labelSpanClass="text-[11px] text-[#7a7373]"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.employee_id}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employee_id && props.touched.employee_id) ? props.errors.employee_id : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[3.6875rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Salary ( Gross annual income )"
|
||||
name="annual_income"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.annual_income}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.annual_income && props.touched.annual_income) ? props.errors.annual_income : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[23.1875rem] w-full"
|
||||
label="Salary ( Net monthly Income )"
|
||||
name="monthly_salary"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.monthly_salary}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.monthly_salary && props.touched.monthly_salary) ? props.errors.monthly_salary : ''}
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem]"
|
||||
label="Salary Payment Date"
|
||||
name="salary_payment_date"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputType='date'
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.salary_payment_date}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.salary_payment_date && props.touched.salary_payment_date) ? props.errors.salary_payment_date : ''}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
||||
<>
|
||||
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
|
||||
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
|
||||
REFERENCE DETAILS ( Must be 18 years and above )
|
||||
</p>
|
||||
</div>
|
||||
<div className="">
|
||||
<div className="flex flex-col gap-[3.4375rem]">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Name"
|
||||
name="ref_name"
|
||||
labelSpan="1st reference"
|
||||
labelSpanClass="text-[12px] text-[#5C2684] ml-1"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
value={props.values.ref_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_name && props.touched.ref_name) ? props.errors.ref_name : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Relationship with He/She"
|
||||
name="ref_relationship"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] px-[.125rem] rounded-[.375rem]"
|
||||
value={props.values.ref_relationship}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_relationship && props.touched.ref_relationship) ? props.errors.ref_relationship : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Phone Number"
|
||||
name="ref_number"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_number}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_number && props.touched.ref_number) ? props.errors.ref_number : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Email Address"
|
||||
name="ref_email"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_email && props.touched.ref_email) ? props.errors.ref_email : ''}
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="BVN"
|
||||
name="ref_bvn"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_bvn}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_bvn && props.touched.ref_bvn) ? props.errors.ref_bvn : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Name"
|
||||
name="ref_two_name"
|
||||
labelSpan="2nd reference"
|
||||
labelSpanClass="text-[12px] text-[#5C2684] ml-[4px]"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_two_name}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_two_name && props.touched.ref_two_name) ? props.errors.ref_two_name : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Relationship with He/She"
|
||||
name="ref_two_relationship"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_two_relationship}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_two_relationship && props.touched.ref_two_relationship) ? props.errors.ref_two_relationship : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-[6.5625rem]">
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Phone Number"
|
||||
name="ref_two_number"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_two_number}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_two_number && props.touched.ref_two_number) ? props.errors.ref_two_number : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="Email Address"
|
||||
name="ref_two_email"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_two_email}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_two_email && props.touched.ref_two_email) ? props.errors.ref_two_email : ''}
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="max-w-[20.3125rem] w-full"
|
||||
label="BVN"
|
||||
name="ref_two_bvn"
|
||||
parentInputClass="w-full"
|
||||
labelClass="font-bold text-[1.125rem] leading-[1.3613rem] tracking-[2%] text-[#5C2684] mb-[.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[2.25rem] bg-[#EFEFEF] rounded-[.375rem]"
|
||||
value={props.values.ref_two_bvn}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.ref_two_bvn && props.touched.ref_two_bvn) ? props.errors.ref_two_bvn : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
<Button
|
||||
className="my-8 max-w-[20.3125rem] btn-R bg-[#5A2C82]"
|
||||
text="Continue"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ const Header: React.FC<HiddenMenuItems> = ({
|
||||
<div className="flex flex-col-reverse lg:flex-col grow lg:grow-0 justify-between items-end">
|
||||
<ul className="flex gap-0 lg:gap-[10px] items-center justify-end w-full flex-wrap">
|
||||
{[
|
||||
{ text: "Open An Account", href: RouteHandler.getStarted },
|
||||
{ text: "Open An Account", href: RouteHandler.letsGetStarted },
|
||||
{
|
||||
text: "Internet Banking",
|
||||
href: RouteHandler.businessBanking,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FaCaretDown } from "react-icons/fa";
|
||||
import { FaCaretDown, FaCaretRight } from "react-icons/fa";
|
||||
|
||||
import dashIcon from "../../assets/images/dashboard/dashDefault.svg";
|
||||
type Props = {
|
||||
@@ -111,6 +111,8 @@ export default function Icons({ name, fillColor, className }: Props) {
|
||||
</svg>
|
||||
) :name == 'arrow-down'?
|
||||
<FaCaretDown className={`text-xl ${className && className}`} />
|
||||
:name == 'arrow-right'?
|
||||
<FaCaretRight className={`text-xl ${className && className}`} />
|
||||
:name == "dash-icon" ? (
|
||||
<img src={dashIcon} alt="dash-icon" />
|
||||
) : null}
|
||||
|
||||
@@ -1,32 +1,42 @@
|
||||
import React from "react";
|
||||
import * as Yup from "yup";
|
||||
import { Form, Formik } from "formik";
|
||||
import { InputCompOne } from "..";
|
||||
import {useNavigate} from 'react-router-dom'
|
||||
import { RouteHandler } from "../../router/routes";
|
||||
import React from 'react';
|
||||
import * as Yup from 'yup';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { InputCompOne } from '..';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { RouteHandler } from '../../router/routes';
|
||||
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { updateUserDetails } from '../../store/UserDetails';
|
||||
|
||||
import { validateBVN, verifyOTP } from '../../core/apiRequest';
|
||||
import { RequestStatus } from '../../core/models';
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
bvn: Yup.string()
|
||||
.required("BVN is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, "must be 11 digits")
|
||||
.max(11, "must be 11 digits"),
|
||||
.required('BVN is required')
|
||||
.test('no-e', 'Invalid number', (value: any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(11, 'must be 11 digits')
|
||||
.max(11, 'must be 11 digits'),
|
||||
otp: Yup.string()
|
||||
.required("OTP is required")
|
||||
.test("no-e", "Invalid number", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(5, "must be 5 digits")
|
||||
.max(5, "must be 5 digits"),
|
||||
// .when('require_otp', {
|
||||
// is: true,
|
||||
// then: Yup.string().required("OTP is required")
|
||||
// })
|
||||
// .required("OTP is required")
|
||||
.test('no-e', 'Invalid number', (value: any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.min(5, 'must be 5 digits')
|
||||
.max(5, 'must be 5 digits'),
|
||||
// .test("no-e", "must be 11 characters", (value:any) => {
|
||||
// if (value.length < 11) {
|
||||
// return false;
|
||||
@@ -41,123 +51,208 @@ let initialValues = {
|
||||
otp: '',
|
||||
};
|
||||
|
||||
type ValidBVN = {
|
||||
verification_id: string;
|
||||
valid: undefined | boolean;
|
||||
};
|
||||
|
||||
const LetsGetStarted: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
// const [pinValues, setPinValues] = React.useState({
|
||||
// bvn: "",
|
||||
// otp: "",
|
||||
// });
|
||||
// const otpInputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
const [hideOTPComponent, setHideOTPComponent] = React.useState<boolean>(true);
|
||||
const firstInputRef = React.useRef<HTMLInputElement>(null);
|
||||
const secondInputRef = React.useRef<HTMLInputElement>(null);
|
||||
const [requestStatusBVN, setRequestStatusBVN] = React.useState<RequestStatus>(
|
||||
{ loading: false, status: undefined, message: '' }
|
||||
);
|
||||
|
||||
// const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// let { name, value } = e.target as HTMLInputElement;
|
||||
const [requestStatusOTP, setRequestStatusOTP] = React.useState<RequestStatus>(
|
||||
{ loading: false, status: undefined, message: '' }
|
||||
);
|
||||
|
||||
// setPinValues((prev) => ({ ...prev, [name]: value }));
|
||||
// };
|
||||
const [bvnIsValid, setBvnIsValid] = React.useState<ValidBVN>({
|
||||
verification_id: '',
|
||||
valid: undefined,
|
||||
});
|
||||
|
||||
const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
let { name, value } = e.target as HTMLInputElement;
|
||||
|
||||
if (name === "bvn") {
|
||||
const regex = /^[0-9]+$/;
|
||||
|
||||
if (regex.test(value)) {
|
||||
if (value?.length == 11) {
|
||||
setHideOTPComponent(false);
|
||||
// secondInputRef.current?.focus();
|
||||
} else setHideOTPComponent(true);
|
||||
} else {
|
||||
console.log("object not found");
|
||||
}
|
||||
}
|
||||
// e: React.FormEvent<HTMLInputElement>
|
||||
// let { value } = e.target as HTMLInputElement;
|
||||
const bvnValidation = (values: any) => {
|
||||
// Function to Validate BVN
|
||||
let bvn = values.bvn;
|
||||
setRequestStatusBVN({ loading: true, status: false, message: '' });
|
||||
validateBVN({ bvn })
|
||||
.then((res) => {
|
||||
if (!res || !res.data.call_return) {
|
||||
setBvnIsValid({ verification_id: '', valid: false });
|
||||
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) => {
|
||||
console.log('values', values)
|
||||
navigate(RouteHandler.dashboardHome, {replace:true})
|
||||
const handleSubmit = (values: any) => {
|
||||
// Function to VERIFY OTP AND LOGIN USER
|
||||
setRequestStatusOTP({ loading: true, status: false, message: '' });
|
||||
// console.log('values', values)
|
||||
verifyOTP({ ...values, verification_id: bvnIsValid.verification_id })
|
||||
.then((res) => {
|
||||
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?.customer[0]?.uid);
|
||||
dispatch(updateUserDetails({ ...res?.data?.customer[0] }));
|
||||
navigate(RouteHandler.dashboardHome, { replace: true });
|
||||
})
|
||||
.catch((err) => {
|
||||
setRequestStatusOTP({
|
||||
loading: false,
|
||||
status: false,
|
||||
message: 'something went wrong, try again',
|
||||
});
|
||||
console.log(err);
|
||||
return setTimeout(() => {
|
||||
setRequestStatusOTP({ loading: false, status: false, message: '' });
|
||||
}, 4000);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={bvnIsValid.valid ? handleSubmit : bvnValidation}
|
||||
>
|
||||
{(props:any) => (
|
||||
<Form className="">
|
||||
<div className="w-full">
|
||||
<div className="containerMode flex justify-between gap-1 xl:gap-8 flex-col">
|
||||
<div className="my-[4rem] flex items-center justify-center w-full">
|
||||
<h1 className="font-bold text-[2.375rem] text-[#5C2684] my-[.5rem] text-center">
|
||||
Let’s Get You Started
|
||||
</h1>
|
||||
</div>
|
||||
<div className="mx-auto flex flex-col gap-8 max-w-[31.625rem] ">
|
||||
<InputCompOne
|
||||
parentClass="flex flex-col gap-2"
|
||||
label="Enter Your BVN "
|
||||
name="bvn"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[13px] text-[#5a5a5a] font-semibold"
|
||||
placeholder="Enter your BVN"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#282828] mb-[2px] flex item-center gap-[4px]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
||||
value={props.values.bvn}
|
||||
onChange={props.handleChange}
|
||||
onInput={handleInput}
|
||||
ref={firstInputRef}
|
||||
maxLength={11}
|
||||
error={(props.errors.bvn && props.touched.bvn) && props.errors.bvn}
|
||||
/>
|
||||
{!hideOTPComponent && (
|
||||
<InputCompOne
|
||||
parentClass="flex flex-col gap-2"
|
||||
label="Enter OTP "
|
||||
name="otp"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( Please check your BVN phone number for verification pin )"
|
||||
labelSpanClass="text-[13px] text-[#5a5a5a] font-semibold"
|
||||
placeholder="Enter your OTP"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#282828] mb-[2px] flex item-center gap-[4px]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
||||
value={props.values.otp}
|
||||
onChange={props.handleChange}
|
||||
onInput={handleInput}
|
||||
ref={secondInputRef}
|
||||
maxLength={11}
|
||||
error={(props.errors.otp && props.touched.otp) && props.errors.otp}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
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"
|
||||
disabled={!props.values.otp}
|
||||
>
|
||||
Enter
|
||||
</button>
|
||||
{(props: any) => (
|
||||
<Form className="">
|
||||
<div className="w-full">
|
||||
<div className="containerMode flex justify-between gap-1 xl:gap-8 flex-col">
|
||||
<div className="my-[4rem] flex items-center justify-center w-full">
|
||||
<h1 className="font-bold text-[2.375rem] text-[#5C2684] my-[.5rem] text-center">
|
||||
Let’s Get You Started
|
||||
</h1>
|
||||
</div>
|
||||
<div className="mx-auto flex flex-col gap-8 max-w-[31.625rem] ">
|
||||
<div className="w-full">
|
||||
<InputCompOne
|
||||
parentClass="flex flex-col gap-2"
|
||||
label="Enter Your BVN "
|
||||
name="bvn"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( To get your BVN, dial *565*0# )"
|
||||
labelSpanClass="text-[13px] text-[#5a5a5a] font-semibold"
|
||||
placeholder="Enter your BVN"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#282828] mb-[2px] flex item-center gap-[4px]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
||||
value={props.values.bvn}
|
||||
onChange={props.handleChange}
|
||||
error={
|
||||
props.errors.bvn && props.touched.bvn && props.errors.bvn
|
||||
}
|
||||
maxLength={11}
|
||||
/>
|
||||
<p
|
||||
className={`p-2 ${
|
||||
!requestStatusBVN.status
|
||||
? 'text-red-500'
|
||||
: 'text-emerald-500'
|
||||
}`}
|
||||
>
|
||||
{requestStatusBVN.loading
|
||||
? 'verifying...'
|
||||
: requestStatusBVN.message}
|
||||
</p>
|
||||
</div>
|
||||
{bvnIsValid.valid && (
|
||||
<InputCompOne
|
||||
parentClass="flex flex-col gap-2"
|
||||
label="Enter OTP "
|
||||
name="otp"
|
||||
parentInputClass="w-full"
|
||||
labelSpan="( Please check your BVN phone number for verification pin )"
|
||||
labelSpanClass="text-[13px] text-[#5a5a5a] font-semibold"
|
||||
placeholder="Enter your OTP"
|
||||
labelClass="font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#282828] mb-[2px] flex item-center gap-[4px]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] rounded bg-[#EFEFEF] px-4"
|
||||
value={props.values.otp}
|
||||
onChange={props.handleChange}
|
||||
error={
|
||||
props.errors.otp && props.touched.otp && props.errors.otp
|
||||
}
|
||||
maxLength={5}
|
||||
/>
|
||||
)}
|
||||
<button
|
||||
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"
|
||||
disabled={
|
||||
requestStatusBVN.loading ||
|
||||
(!props.values.otp && bvnIsValid.valid)
|
||||
}
|
||||
>
|
||||
Enter
|
||||
</button>
|
||||
|
||||
{hideOTPComponent ? (
|
||||
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
|
||||
***Every personal information attached to your BVN is safe and
|
||||
secure. It is only important for us to verify your information and
|
||||
also give you access to your application profile/account.
|
||||
<p
|
||||
className={`p-2 ${
|
||||
!requestStatusOTP.status
|
||||
? 'text-red-500'
|
||||
: 'text-emerald-500'
|
||||
}`}
|
||||
>
|
||||
{requestStatusOTP.message}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
|
||||
***Did not receive OTP? Click to resend
|
||||
</p>
|
||||
)}
|
||||
|
||||
{bvnIsValid.valid || bvnIsValid.valid == undefined ? (
|
||||
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
|
||||
***Every personal information attached to your BVN is safe
|
||||
and secure. It is only important for us to verify your
|
||||
information and also give you access to your application
|
||||
profile/account.
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
|
||||
***Did not receive OTP? Click to resend
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import { ReactNode, useEffect, useState } from "react";
|
||||
import { PendingTableList } from "../../core/models";
|
||||
|
||||
type PaginatedListProps = {
|
||||
data: PendingTableList,
|
||||
itemsPerPage?: number,
|
||||
filterItem?: string[],
|
||||
tableTitle?: string,
|
||||
titleClass?:string,
|
||||
children: (data:PendingTableList) => ReactNode;
|
||||
}
|
||||
|
||||
export default function PendingList({
|
||||
data,
|
||||
itemsPerPage = 5,
|
||||
filterItem,
|
||||
tableTitle,
|
||||
titleClass,
|
||||
children,
|
||||
}:PaginatedListProps) {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [filteredData, setFilteredData] = useState(data);
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const [newData, setNewData] = useState<any>([]);
|
||||
|
||||
const numberOfSelection = itemsPerPage;
|
||||
|
||||
const handlePrev = () => {
|
||||
if (currentPage != 0) {
|
||||
setCurrentPage((prev) => prev - numberOfSelection);
|
||||
}
|
||||
};
|
||||
const handleNext = () => {
|
||||
if (currentPage < data.length) {
|
||||
setCurrentPage((prev) => prev + numberOfSelection);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = ({ target: { value } }:{target: {value:string}}, name:string) => {
|
||||
setSearchTerm(value);
|
||||
let newFilteredData:any = data.filter((item:any) =>
|
||||
item[name].toLowerCase().startsWith(value.toLowerCase())
|
||||
);
|
||||
setFilteredData(newFilteredData);
|
||||
setCurrentPage(0);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setNewData(
|
||||
filteredData?.slice(currentPage, numberOfSelection + currentPage)
|
||||
);
|
||||
}, [currentPage, filteredData]);
|
||||
|
||||
useEffect(()=>{
|
||||
setCurrentPage(0)
|
||||
},[itemsPerPage])
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<h1 className={`text-2xl mb-5 font-semibold ${titleClass && titleClass}`}>{tableTitle}</h1>
|
||||
|
||||
{data.length > 0 && filterItem && (
|
||||
<div className="mb-10 flex justify-end items-center gap-2">
|
||||
{filterItem.map((item, index) => (
|
||||
<label
|
||||
key={index}
|
||||
className="flex flex-col sm:flex-row items-center gap-2 text-slate-600 dark:text-slate-100 transition-all duration-500"
|
||||
>
|
||||
Search by {item[0].toUpperCase() + item.slice(1)}
|
||||
<input
|
||||
name={item}
|
||||
type="text"
|
||||
className="py-1 px-2 text-sm min-w-[100px] text-black dark:text-white bg-white dark:bg-slate-800 rounded-full border-0 outline-none ring-1 ring-slate-300 dark:ring-white transition-all duration-500"
|
||||
value={searchTerm}
|
||||
onChange={(e) => {
|
||||
handleSearch(e, item);
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{children(newData)}
|
||||
|
||||
{/* show prev and next button if data exist */}
|
||||
{(data.length > 0 && data.length > itemsPerPage) && (
|
||||
<div className="mt-5 md:mt-10 w-full flex gap-4 justify-center items-center">
|
||||
<button
|
||||
onClick={handlePrev}
|
||||
className={`w-6 h-6 md:w-12 md:h-12 text-sm md:text-lg rounded-full flex justify-center items-center transition-all duration-300 ${
|
||||
currentPage == 0
|
||||
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400 pointer-events-none"
|
||||
: "text-slate-600 border-slate-600 dark:text-white dark:border-white"
|
||||
}`}
|
||||
>
|
||||
<
|
||||
</button>
|
||||
|
||||
{data.length && data.map((item, index)=>{
|
||||
item = item
|
||||
if(index%itemsPerPage == 0 && index >= currentPage && index <= currentPage+itemsPerPage){
|
||||
return (
|
||||
<button
|
||||
key={index}
|
||||
onClick={handleNext}
|
||||
className={`w-6 h-6 md:w-12 md:h-12 text-sm md:text-lg rounded-full flex justify-center items-center border transition-all duration-300 ${
|
||||
currentPage != index
|
||||
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400"
|
||||
: "text-slate-600 border-slate-600 dark:text-white dark:border-white pointer-events-none"
|
||||
}`}
|
||||
>
|
||||
{index/itemsPerPage +1}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
})}
|
||||
|
||||
<button
|
||||
onClick={handleNext}
|
||||
className={`w-6 h-6 md:w-12 md:h-12 text-sm md:text-lg rounded-full flex justify-center items-center transition-all duration-300 ${
|
||||
currentPage + numberOfSelection >= data.length
|
||||
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400 pointer-events-none"
|
||||
: "text-slate-600 border-slate-600 dark:text-white dark:border-white"
|
||||
}`}
|
||||
>
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -58,7 +58,7 @@ const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
|
||||
return (
|
||||
<div className={parentClass}>
|
||||
{label && (
|
||||
<label htmlFor={label ? label : floatLabel} className={`flex gap-2 items-center ${labelClass}`}>
|
||||
<label htmlFor={label ? label : floatLabel} className={`flex gap-2 items-center flex-wrap ${labelClass}`}>
|
||||
{label}
|
||||
{labelSpan && <span className={labelSpanClass}>{labelSpan}</span>}
|
||||
{error && label && <span className='text-[10px] text-red-500'>{error}</span>}
|
||||
|
||||
@@ -9,7 +9,7 @@ const Stepper: React.FC<StepperProps> = ({ step = 0 }) => {
|
||||
|
||||
return (
|
||||
<div className="flex justify-between items-center gap-5">
|
||||
{[...Array(6)].map((_, index) => (
|
||||
{[...Array(5)].map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`w-[1.875rem] border-[.1875rem] rounded-sm ${(step === index
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { postAuxEnd, getAuxEnd } from "./axiosCall";
|
||||
|
||||
// FUNCTION TO START BVN VALIDATION
|
||||
export const validateBVN = (postData:any) => {
|
||||
let reqData = {
|
||||
...postData
|
||||
}
|
||||
return postAuxEnd('/bvn', reqData)
|
||||
}
|
||||
|
||||
|
||||
// FUNCTION TO VERIFY OTP AND LOGIN
|
||||
export const verifyOTP = (postData:any) => {
|
||||
let reqData = {
|
||||
...postData
|
||||
}
|
||||
return postAuxEnd('/bvn/verify', reqData)
|
||||
}
|
||||
|
||||
// FUNCTION TO APPLY FOR LOAN
|
||||
export const applyForLoan = (postData:any) => {
|
||||
let reqData = {
|
||||
customer_uid: localStorage.getItem('uid'),
|
||||
...postData
|
||||
}
|
||||
return postAuxEnd('/loan/apply', reqData)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET USER BY CUSTOMER UID
|
||||
export const getUserByID = (uid:string) => {
|
||||
let reqData = {
|
||||
// customer_uid: localStorage.getItem('uid'),
|
||||
}
|
||||
return getAuxEnd(`/profile?uid=${uid}`, reqData)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET USER BY CUSTOMER UID
|
||||
export const getUserPendingLoanList = (uid:string) => {
|
||||
let reqData = {
|
||||
// customer_uid: localStorage.getItem('uid'),
|
||||
}
|
||||
return getAuxEnd(`/dash?uid=${uid}`, reqData)
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import axios from "axios";
|
||||
|
||||
export function postAuxEnd(uri: string, reqData: any): Promise<any> {
|
||||
const endPoint = import.meta.env.VITE_USERS_ENDPOINT + uri;
|
||||
const formData = new FormData();
|
||||
for (let value in reqData) {
|
||||
if (typeof reqData[value] === "object") {
|
||||
// for (let innerValue in reqData[value]) {
|
||||
// let innerReqData = reqData[value]
|
||||
// console.log('SAMPLE',innerReqData)
|
||||
// formData.append(reqData[value][innerValue], reqData[value][innerValue]);
|
||||
// }
|
||||
// formData.append(value, JSON.stringify(reqData[value]));
|
||||
formData.append(value, reqData[value]);
|
||||
} else {
|
||||
formData.append(value, reqData[value]);
|
||||
}
|
||||
}
|
||||
return axios
|
||||
.post(endPoint, 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-------------------------------------------------------"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function getAuxEnd(uri: string, reqData: any): Promise<any> {
|
||||
const endPoint = import.meta.env.VITE_USERS_ENDPOINT + uri;
|
||||
const formData = new FormData();
|
||||
for (let value in reqData) {
|
||||
formData.append(value, reqData[value]);
|
||||
}
|
||||
return axios
|
||||
.get(endPoint, reqData)
|
||||
.then((response: {}) => {
|
||||
// if (response.data.internal_return == "-9999") {
|
||||
// localStorage.clear();
|
||||
// window.location.href = `/login?sessionExpired=true`;
|
||||
// }
|
||||
return response;
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(
|
||||
"ERROR3-------------------------------------------------------", error
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
export interface RequestStatus {
|
||||
loading?:boolean
|
||||
status?:boolean | undefined
|
||||
message?:string
|
||||
name?:string
|
||||
data?:{}[] | [any] | {}
|
||||
}
|
||||
|
||||
|
||||
export interface User {
|
||||
firstname?:string
|
||||
lastname?:string
|
||||
last_login?:string
|
||||
message?:string
|
||||
token?:string
|
||||
customer_uid?:string
|
||||
call_return?:string
|
||||
}
|
||||
|
||||
|
||||
export type PendingTableList = {
|
||||
status?: string | boolean;
|
||||
application_uid?: string
|
||||
added?: string
|
||||
loan_amount?: string
|
||||
payment_month?: string
|
||||
}[];
|
||||
@@ -1,32 +1,63 @@
|
||||
import { useState } from "react";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import Logo from "../../assets/icons/logo.svg";
|
||||
import { Icons } from "../../components";
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
import Logo from '../../assets/icons/logo.svg';
|
||||
import { Icons } from '../../components';
|
||||
import { contactDetails } from '../../utils/data';
|
||||
|
||||
type Props = {
|
||||
asideDisplay?: () => void;
|
||||
logoutUser: () => void;
|
||||
};
|
||||
|
||||
export default function Aside({ asideDisplay }: Props) {
|
||||
export default function Aside({ asideDisplay, logoutUser }: Props) {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [openNestedLink, setOpenNestedLink] = useState<{ name: string | null }>(
|
||||
{ name: "" }
|
||||
{ name: '' }
|
||||
);
|
||||
|
||||
const handleOpenNestedLink = (e: any) => {
|
||||
if (!e || !e.target) {
|
||||
return setOpenNestedLink({ name: "" });
|
||||
return setOpenNestedLink({ name: '' });
|
||||
}
|
||||
if (openNestedLink.name && openNestedLink.name == e.target.name) {
|
||||
setOpenNestedLink({ name: "" });
|
||||
setOpenNestedLink({ name: '' });
|
||||
} else {
|
||||
setOpenNestedLink({ name: e.target.name });
|
||||
}
|
||||
};
|
||||
|
||||
// Track user activity
|
||||
useEffect(() => {
|
||||
let timeout: number;
|
||||
|
||||
const resetTimeout = () => {
|
||||
clearTimeout(timeout);
|
||||
timeout = window.setTimeout(() => {
|
||||
// Logout user after 7 minutes of inactivity
|
||||
logoutUser();
|
||||
}, 7 * 60 * 1000); // 7 minutes in milliseconds
|
||||
};
|
||||
|
||||
const handleUserActivity = () => {
|
||||
resetTimeout();
|
||||
};
|
||||
|
||||
// Attach event listeners to track user activity
|
||||
document.addEventListener('mousemove', handleUserActivity);
|
||||
document.addEventListener('keypress', handleUserActivity);
|
||||
|
||||
// Initialize timeout
|
||||
resetTimeout();
|
||||
|
||||
// Clear timeout and remove event listeners on component unmount
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
document.removeEventListener('mousemove', handleUserActivity);
|
||||
document.removeEventListener('keypress', handleUserActivity);
|
||||
};
|
||||
}, [logoutUser]);
|
||||
|
||||
return (
|
||||
<div className="py-5 px-10 flex flex-col h-full bg-inherit">
|
||||
<Link to="/">
|
||||
@@ -46,8 +77,8 @@ export default function Aside({ asideDisplay }: Props) {
|
||||
onClick={(e) => handleOpenNestedLink(e)}
|
||||
className={`py-2 pl-2 text-left relative w-full overflow-hidden rounded-lg flex justify-between items-center z-10 bg-inherit ${
|
||||
allNestedLinks.includes(pathname)
|
||||
? " text-[#5C2684]"
|
||||
: " text-[#585858]"
|
||||
? ' text-[#5C2684]'
|
||||
: ' text-[#585858]'
|
||||
}`}
|
||||
>
|
||||
{link.name}
|
||||
@@ -61,8 +92,8 @@ export default function Aside({ asideDisplay }: Props) {
|
||||
<div
|
||||
className={`transition-all duration-300 w-full z-1 ${
|
||||
openNestedLink.name == link.name
|
||||
? "relative top-0"
|
||||
: "absolute -top-[500px]"
|
||||
? 'relative top-0'
|
||||
: 'absolute -top-[500px]'
|
||||
}`}
|
||||
>
|
||||
{link.nestedLink.map((nextLink, index) => (
|
||||
@@ -71,17 +102,17 @@ export default function Aside({ asideDisplay }: Props) {
|
||||
asideDisplay && asideDisplay();
|
||||
}}
|
||||
key={index}
|
||||
to={nextLink.link ? nextLink.link : "#"}
|
||||
to={nextLink.link ? nextLink.link : '#'}
|
||||
className={`w-full my-1 flex items-center gap-2 py-2 pl-5 text-base font-medium ${
|
||||
pathname == nextLink.link
|
||||
? " text-[#5C2684]"
|
||||
: "text-[#585858]"
|
||||
? ' text-[#5C2684]'
|
||||
: 'text-[#585858]'
|
||||
}`}
|
||||
>
|
||||
<Icons
|
||||
name={nextLink.icon}
|
||||
fillColor={`${
|
||||
pathname == nextLink.link ? "#5C2684" : "#585858"
|
||||
pathname == nextLink.link ? '#5C2684' : '#585858'
|
||||
}`}
|
||||
/>
|
||||
{nextLink.name}
|
||||
@@ -97,14 +128,14 @@ export default function Aside({ asideDisplay }: Props) {
|
||||
asideDisplay && asideDisplay();
|
||||
}}
|
||||
key={index}
|
||||
to={link.link ? link.link : "#"}
|
||||
to={link.link ? link.link : '#'}
|
||||
className={`w-full my-4 flex items-center gap-2 py-2 pl-5 rounded-lg text-base font-medium ${
|
||||
pathname == link.link ? "text-[#5C2684]" : "text-[#585858]"
|
||||
pathname == link.link ? 'text-[#5C2684]' : 'text-[#585858]'
|
||||
}`}
|
||||
>
|
||||
<Icons
|
||||
name={link.icon}
|
||||
fillColor={`${pathname == link.link ? "#5C2684" : "#585858"}`}
|
||||
fillColor={`${pathname == link.link ? '#5C2684' : '#585858'}`}
|
||||
/>
|
||||
{link.name}
|
||||
</Link>
|
||||
@@ -115,24 +146,30 @@ export default function Aside({ asideDisplay }: Props) {
|
||||
<div className="w-full flex justify-center items-center flex-col gap-3">
|
||||
<button
|
||||
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
|
||||
</button>
|
||||
|
||||
|
||||
<div className="flex flex-col gap-[.4375rem] text-[.75rem]">
|
||||
<p className="font-extrabold tracking-[3%] text-[#FBB700] underline">
|
||||
For more enquiries and support
|
||||
</p>
|
||||
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
|
||||
{/* <p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
|
||||
Call: 09099000000
|
||||
</p>
|
||||
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
|
||||
Email: fcmbloan@support.com
|
||||
</p>
|
||||
</p> */}
|
||||
{contactDetails.map(({ name, value }) => (
|
||||
<p
|
||||
key={name}
|
||||
className="font-extrabold tracking-[3%] text-[#5A5A5A]"
|
||||
>
|
||||
{name}: {value}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -150,29 +187,34 @@ type AsideLinksType = {
|
||||
}[];
|
||||
|
||||
const asideLinks: AsideLinksType = [
|
||||
{ name: "Dashboard", link: "/dashboard/home", icon: "dash-icon", nestedLink: [] },
|
||||
{
|
||||
name: "Your Profile",
|
||||
link: "/dashboard/profile",
|
||||
icon: "dash-icon",
|
||||
name: 'Dashboard',
|
||||
link: '/dashboard/home',
|
||||
icon: 'dash-icon',
|
||||
nestedLink: [],
|
||||
},
|
||||
{
|
||||
name: "Employment Details",
|
||||
link: "/dashboard/verification",
|
||||
icon: "dash-icon",
|
||||
name: 'Your Profile',
|
||||
link: '/dashboard/profile',
|
||||
icon: 'dash-icon',
|
||||
nestedLink: [],
|
||||
},
|
||||
{
|
||||
name: "Reference Details",
|
||||
link: "/dashboard/payments",
|
||||
icon: "dash-icon",
|
||||
name: 'Employment Details',
|
||||
link: '/dashboard/verification',
|
||||
icon: 'dash-icon',
|
||||
nestedLink: [],
|
||||
},
|
||||
{
|
||||
name: "Agreements",
|
||||
link: "/dashboard/legals",
|
||||
icon: "dash-icon",
|
||||
name: 'Reference Details',
|
||||
link: '/dashboard/payments',
|
||||
icon: 'dash-icon',
|
||||
nestedLink: [],
|
||||
},
|
||||
{
|
||||
name: 'Agreements',
|
||||
link: '/dashboard/legals',
|
||||
icon: 'dash-icon',
|
||||
nestedLink: [],
|
||||
},
|
||||
// {name: 'Nested Link', icon: 'home', nestedLink:[
|
||||
|
||||
@@ -1,11 +1,61 @@
|
||||
|
||||
import {useState, useEffect} from 'react'
|
||||
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 { getUserByID } from '../../core/apiRequest';
|
||||
|
||||
import Logo from '../../assets/images/logo.png'
|
||||
|
||||
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')
|
||||
let uid = localStorage.getItem('uid')
|
||||
if(!token || !uid){
|
||||
navigate(RouteHandler.letsGetStarted, {replace:true})
|
||||
return
|
||||
}
|
||||
const getUser = () => { // FUNCTION TO GET USER BY ID
|
||||
// let data = {firstname:'firstname', lastname:'lastname', uid:'28273737646466464'}
|
||||
getUserByID(uid).then(res=>{
|
||||
if(!res.data.call_return || !Object.keys(res.data.customer).length){
|
||||
navigate(RouteHandler.letsGetStarted, {replace:true})
|
||||
return
|
||||
}
|
||||
setLoading(false)
|
||||
dispatch(updateUserDetails(res.data.customer));
|
||||
}).catch(err=>{
|
||||
navigate(RouteHandler.letsGetStarted, {replace:true})
|
||||
console.log('USER ERROR', err)
|
||||
})
|
||||
}
|
||||
if(!Object.keys(userDetails).length){
|
||||
getUser()
|
||||
}
|
||||
},[])
|
||||
|
||||
return (
|
||||
<DashboardLayout>
|
||||
<Outlet />
|
||||
</DashboardLayout>
|
||||
<>
|
||||
{loading && !Object.keys(userDetails).length ?
|
||||
<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>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
import { ReactNode, useState, useEffect } from "react";
|
||||
import { RouteHandler } from "../../router/routes";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import Aside from "./Aside";
|
||||
|
||||
export default function DashboardLayout({ children }: { children: ReactNode }) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [showAside, setShowAside] = useState<boolean>(false);
|
||||
const asideDisplay = (): void => {
|
||||
setShowAside((prev) => !prev);
|
||||
@@ -30,17 +34,22 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
||||
// return child;
|
||||
// });
|
||||
|
||||
const logoutUser = () => {
|
||||
localStorage.clear()
|
||||
navigate(RouteHandler.letsGetStarted, {replace:true})
|
||||
}
|
||||
|
||||
return (
|
||||
<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 />
|
||||
<Aside logoutUser={logoutUser} />
|
||||
</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 ${
|
||||
showAside ? "left-0" : "-left-[200%]"
|
||||
}`}
|
||||
>
|
||||
<Aside asideDisplay={asideDisplay} />
|
||||
<Aside logoutUser={logoutUser} asideDisplay={asideDisplay} />
|
||||
</aside>
|
||||
<main className="dash-bg-image bg-[#F9F9F9] relative w-full overflow-y-auto overflow-x-hidden">
|
||||
|
||||
@@ -74,8 +83,8 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div className="flex p-5 relative">
|
||||
<div className="w-full p-5">{children}</div>
|
||||
<div className="flex p-2 md:p-5 relative">
|
||||
<div className="w-full p-2 md:p-5">{children}</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ interface GetStartedLayoutProps {
|
||||
const GetStartedLayout: React.FC<GetStartedLayoutProps> = ({ children }) => {
|
||||
return (
|
||||
<div className="containerMode mb-[5.4375rem]">
|
||||
<div className='sticky top-0 bg-white'>
|
||||
<div className='sticky z-50 top-0 bg-white'>
|
||||
<Header hideSidebar={true} hideMenu={true} />
|
||||
</div>
|
||||
<div className="flex flex-col min-h-[70vh] justify-between">
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
export function NewDateTimeFormatter(isoDateString:any, addHour = true) {
|
||||
const date = new Date(isoDateString);
|
||||
if (addHour) {
|
||||
date.setTime(date.getTime() + 1 * 60 * 60 * 1000);
|
||||
}
|
||||
const formattedDate = date.toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
// second: "2-digit",
|
||||
hour12: true,
|
||||
timeZone: "UTC",
|
||||
});
|
||||
return formattedDate;
|
||||
}
|
||||
+6
-1
@@ -4,10 +4,15 @@ import { BrowserRouter } from "react-router-dom";
|
||||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
|
||||
import { Provider } from "react-redux";
|
||||
import store from "./store/store";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>
|
||||
</BrowserRouter>
|
||||
</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,
|
||||
},
|
||||
});
|
||||
+291
-286
@@ -1,556 +1,561 @@
|
||||
import FBook from "../assets/icons/facebook.svg";
|
||||
import Twitter from "../assets/icons/twitter.svg";
|
||||
import Instagram from "../assets/icons/instagram.svg";
|
||||
import FBookWhite from "../assets/images/socials/facebook.svg";
|
||||
import LinkedInWhite from "../assets/images/socials/linkedin.svg";
|
||||
import XWhite from "../assets/images/socials/twitterx.svg";
|
||||
import WhatsappWhite from "../assets/images/socials/whatsapp.svg";
|
||||
import YoutubeWhite from "../assets/images/socials/youtube.svg";
|
||||
import InstagramWhite from "../assets/images/socials/instagram.svg";
|
||||
import { RouteHandler } from "../router/routes";
|
||||
import FBook from '../assets/icons/facebook.svg';
|
||||
import Twitter from '../assets/icons/twitter.svg';
|
||||
import Instagram from '../assets/icons/instagram.svg';
|
||||
import FBookWhite from '../assets/images/socials/facebook.svg';
|
||||
import LinkedInWhite from '../assets/images/socials/linkedin.svg';
|
||||
import XWhite from '../assets/images/socials/twitterx.svg';
|
||||
import WhatsappWhite from '../assets/images/socials/whatsapp.svg';
|
||||
import YoutubeWhite from '../assets/images/socials/youtube.svg';
|
||||
import InstagramWhite from '../assets/images/socials/instagram.svg';
|
||||
import { RouteHandler } from '../router/routes';
|
||||
|
||||
let process = import.meta.env;
|
||||
|
||||
export const top_header_data = [
|
||||
{ id: 1, name: "HOME", href: RouteHandler.homepage },
|
||||
{ id: 2, name: "PERSONAL", href: RouteHandler.personalBanking },
|
||||
{ id: 3, name: "BUSINESS", href: RouteHandler.businessBanking },
|
||||
{ id: 4, name: "CORPORATE", href: RouteHandler.cooperateBanking },
|
||||
{ id: 1, name: 'HOME', href: RouteHandler.homepage },
|
||||
{ id: 2, name: 'PERSONAL', href: RouteHandler.personalBanking },
|
||||
{ id: 3, name: 'BUSINESS', href: RouteHandler.businessBanking },
|
||||
{ id: 4, name: 'CORPORATE', href: RouteHandler.cooperateBanking },
|
||||
];
|
||||
|
||||
export const lowerMenuItems = [
|
||||
{
|
||||
id: 1,
|
||||
name: "PERSONAL BANKING",
|
||||
linkPath: "/personal-banking",
|
||||
name: 'PERSONAL BANKING',
|
||||
linkPath: '/personal-banking',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "BUSINESS BANKING",
|
||||
linkPath: "/business-banking",
|
||||
name: 'BUSINESS BANKING',
|
||||
linkPath: '/business-banking',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "CORPORATE BANKING",
|
||||
linkPath: "/cooperate-banking",
|
||||
name: 'CORPORATE BANKING',
|
||||
linkPath: '/cooperate-banking',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "GROUP & SUBSIDIARIES",
|
||||
linkPath: "",
|
||||
name: 'GROUP & SUBSIDIARIES',
|
||||
linkPath: '',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "ABOUT US",
|
||||
linkPath: "/about-us",
|
||||
name: 'ABOUT US',
|
||||
linkPath: '/about-us',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "MY BANK AND I",
|
||||
linkPath: "",
|
||||
name: 'MY BANK AND I',
|
||||
linkPath: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const _lowerMenuItems = [
|
||||
{
|
||||
name: "PERSONAL BANKING",
|
||||
linkPath: "/personal-banking",
|
||||
name: 'PERSONAL BANKING',
|
||||
linkPath: '/personal-banking',
|
||||
subItems: [
|
||||
{
|
||||
name: "CURRENT ACCOUNTS",
|
||||
linkPath: "/current-accounts",
|
||||
name: 'CURRENT ACCOUNTS',
|
||||
linkPath: '/current-accounts',
|
||||
subItems: [
|
||||
{
|
||||
name: "CLASSIC CURRENT ACCOUNT",
|
||||
linkPath: "/personal-classic-current-account",
|
||||
name: 'CLASSIC CURRENT ACCOUNT',
|
||||
linkPath: '/personal-classic-current-account',
|
||||
},
|
||||
{
|
||||
name: "PREMIUM CURRENT ACCOUNT",
|
||||
linkPath: "/premium-current-account",
|
||||
name: 'PREMIUM CURRENT ACCOUNT',
|
||||
linkPath: '/premium-current-account',
|
||||
},
|
||||
{
|
||||
name: "PERSONAL BUSINESS ACCOUNT",
|
||||
linkPath: "/personal-business-account",
|
||||
name: 'PERSONAL BUSINESS ACCOUNT',
|
||||
linkPath: '/personal-business-account',
|
||||
},
|
||||
{
|
||||
name: "DOMICILIARY CURRENT ACCOUNT",
|
||||
linkPath: "/domiciliary-current-account",
|
||||
name: 'DOMICILIARY CURRENT ACCOUNT',
|
||||
linkPath: '/domiciliary-current-account',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "SAVINGS ACCOUNTS",
|
||||
linkPath: "/savings-accounts",
|
||||
name: 'SAVINGS ACCOUNTS',
|
||||
linkPath: '/savings-accounts',
|
||||
subItems: [
|
||||
{ name: "FCMB EASY ACCOUNT", linkPath: "/easy-account" },
|
||||
{ name: "KIDS (0-17 YRS)", linkPath: "/kids" },
|
||||
{ name: "FLEXX (18-30 YRS)", linkPath: "/flexx-account" },
|
||||
{ name: 'FCMB EASY ACCOUNT', linkPath: '/easy-account' },
|
||||
{ name: 'KIDS (0-17 YRS)', linkPath: '/kids' },
|
||||
{ name: 'FLEXX (18-30 YRS)', linkPath: '/flexx-account' },
|
||||
{
|
||||
name: "CLASSIC SAVINGS ACCOUNT",
|
||||
linkPath: "/classic-savings-account",
|
||||
name: 'CLASSIC SAVINGS ACCOUNT',
|
||||
linkPath: '/classic-savings-account',
|
||||
},
|
||||
{
|
||||
name: "PREMIUM SAVINGS ACCOUNT",
|
||||
linkPath: "/fcmb-premium-savings-account",
|
||||
name: 'PREMIUM SAVINGS ACCOUNT',
|
||||
linkPath: '/fcmb-premium-savings-account',
|
||||
},
|
||||
{
|
||||
name: "FCMB SALARY SAVINGS ACCOUNT",
|
||||
linkPath: "/fcmb-salary-savings-account",
|
||||
name: 'FCMB SALARY SAVINGS ACCOUNT',
|
||||
linkPath: '/fcmb-salary-savings-account',
|
||||
},
|
||||
{
|
||||
name: "DOMICILIARY SAVINGS ACCOUNT",
|
||||
linkPath: "/domiciliary-savings-account",
|
||||
name: 'DOMICILIARY SAVINGS ACCOUNT',
|
||||
linkPath: '/domiciliary-savings-account',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "INVESTMENTS",
|
||||
linkPath: "/investment-accounts",
|
||||
name: 'INVESTMENTS',
|
||||
linkPath: '/investment-accounts',
|
||||
subItems: [
|
||||
{ name: "FIXED DEPOSITS", linkPath: "/fixed-deposits" },
|
||||
{ name: "GRO (App)", linkPath: "/GRO" },
|
||||
{ name: "GRO (Web)", linkPath: "https://www.investwithgro.com/" },
|
||||
{ name: 'FIXED DEPOSITS', linkPath: '/fixed-deposits' },
|
||||
{ name: 'GRO (App)', linkPath: '/GRO' },
|
||||
{ name: 'GRO (Web)', linkPath: 'https://www.investwithgro.com/' },
|
||||
{
|
||||
name: "I-NEST SAVING",
|
||||
linkPath: "https://i-nest.fcmb.com/#/welcome",
|
||||
name: 'I-NEST SAVING',
|
||||
linkPath: 'https://i-nest.fcmb.com/#/welcome',
|
||||
},
|
||||
{ name: "CALL DEPOSITS", linkPath: "/call-deposits" },
|
||||
{ name: 'CALL DEPOSITS', linkPath: '/call-deposits' },
|
||||
{
|
||||
name: "EDUCATION INVESTMENT PLAN",
|
||||
linkPath: "/education-investment",
|
||||
name: 'EDUCATION INVESTMENT PLAN',
|
||||
linkPath: '/education-investment',
|
||||
},
|
||||
{
|
||||
name: "MUTUAL FUNDS",
|
||||
linkPath: "https://www.fcmbassetmanagement.com/mutual-funds/",
|
||||
name: 'MUTUAL FUNDS',
|
||||
linkPath: 'https://www.fcmbassetmanagement.com/mutual-funds/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "LOANS AND CREDIT CARDS",
|
||||
linkPath: "/loans-and-credit-cards",
|
||||
name: 'LOANS AND CREDIT CARDS',
|
||||
linkPath: '/loans-and-credit-cards',
|
||||
subItems: [
|
||||
{ name: "FASTCASH", linkPath: "/fastcash" },
|
||||
{ name: "SALARY PLUS LOAN", linkPath: "/salary-plus-loan" },
|
||||
{ name: "PREMIUM SALARY LOAN", linkPath: "/premium-salary-loan" },
|
||||
{ name: "AUTO LOAN", linkPath: "/auto-loan" },
|
||||
{ name: "AIRTIME LOAN", linkPath: "/airtime-loan" },
|
||||
{ name: "CREDIT CARDS", linkPath: "/credit-cards" },
|
||||
{ name: 'FASTCASH', linkPath: '/fastcash' },
|
||||
{ name: 'SALARY PLUS LOAN', linkPath: '/salary-plus-loan' },
|
||||
{ name: 'PREMIUM SALARY LOAN', linkPath: '/premium-salary-loan' },
|
||||
{ name: 'AUTO LOAN', linkPath: '/auto-loan' },
|
||||
{ name: 'AIRTIME LOAN', linkPath: '/airtime-loan' },
|
||||
{ name: 'CREDIT CARDS', linkPath: '/credit-cards' },
|
||||
{
|
||||
name: "EASYLIFT LOAN",
|
||||
linkPath: "https://easyliftloanform.fcmb.com",
|
||||
name: 'EASYLIFT LOAN',
|
||||
linkPath: 'https://easyliftloanform.fcmb.com',
|
||||
},
|
||||
{ name: "MORTGAGE", linkPath: "http://mortgage.fcmb.com/" },
|
||||
{ name: 'MORTGAGE', linkPath: 'http://mortgage.fcmb.com/' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "NON-RESIDENT NIGERIAN (NRN) BANKING",
|
||||
linkPath: "https://www.fcmb.com/non-resident-nigerian",
|
||||
name: 'NON-RESIDENT NIGERIAN (NRN) BANKING',
|
||||
linkPath: 'https://www.fcmb.com/non-resident-nigerian',
|
||||
},
|
||||
{
|
||||
name: "WAYS TO BANK",
|
||||
linkPath: "/ways-to-bank",
|
||||
name: 'WAYS TO BANK',
|
||||
linkPath: '/ways-to-bank',
|
||||
subItems: [
|
||||
{ name: "FCMB MOBILE", linkPath: "/fcmb-mobile" },
|
||||
{ name: 'FCMB MOBILE', linkPath: '/fcmb-mobile' },
|
||||
{
|
||||
name: "RETAIL INTERNET BANKING",
|
||||
linkPath: "https://ibank.fcmb.com/",
|
||||
name: 'RETAIL INTERNET BANKING',
|
||||
linkPath: 'https://ibank.fcmb.com/',
|
||||
},
|
||||
{ name: "USSD BANKING", linkPath: "/ussd" },
|
||||
{ name: "OUR BRANCH NETWORK", linkPath: "/branch-network" },
|
||||
{ name: "OUR ATM NETWORK", linkPath: "/atm-network" },
|
||||
{ name: "FLASHMECASH", linkPath: "/flashme-cash" },
|
||||
{ name: "OUR CARDS", linkPath: "/our-cards" },
|
||||
{ name: "FCMB ELECTRONIC CHANNELS", linkPath: "/e-channels" },
|
||||
{ name: "AGENT BANKING", linkPath: "/agent-banking" },
|
||||
{ name: 'USSD BANKING', linkPath: '/ussd' },
|
||||
{ name: 'OUR BRANCH NETWORK', linkPath: '/branch-network' },
|
||||
{ name: 'OUR ATM NETWORK', linkPath: '/atm-network' },
|
||||
{ name: 'FLASHMECASH', linkPath: '/flashme-cash' },
|
||||
{ name: 'OUR CARDS', linkPath: '/our-cards' },
|
||||
{ name: 'FCMB ELECTRONIC CHANNELS', linkPath: '/e-channels' },
|
||||
{ name: 'AGENT BANKING', linkPath: '/agent-banking' },
|
||||
{
|
||||
name: "FCMB SECURE COMMUNICATION",
|
||||
linkPath: "/secure-communication",
|
||||
name: 'FCMB SECURE COMMUNICATION',
|
||||
linkPath: '/secure-communication',
|
||||
},
|
||||
{ name: "TEMI", linkPath: "/temi" },
|
||||
{ name: 'TEMI', linkPath: '/temi' },
|
||||
],
|
||||
},
|
||||
{ name: "BANCASSURANCE", linkPath: "/bancassurance" },
|
||||
{ name: 'BANCASSURANCE', linkPath: '/bancassurance' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "BUSINESS BANKING",
|
||||
linkPath: "/business-banking",
|
||||
name: 'BUSINESS BANKING',
|
||||
linkPath: '/business-banking',
|
||||
subItems: [
|
||||
{
|
||||
name: "PROPOSITIONS",
|
||||
linkPath: "",
|
||||
name: 'PROPOSITIONS',
|
||||
linkPath: '',
|
||||
subItems: [
|
||||
{ name: "SHEVENTURES", linkPath: "/she-ventures" },
|
||||
{ name: "BUSINESS ZONE", linkPath: "https://businesszone.fcmb.com/" },
|
||||
{ name: 'SHEVENTURES', linkPath: '/she-ventures' },
|
||||
{ name: 'BUSINESS ZONE', linkPath: 'https://businesszone.fcmb.com/' },
|
||||
{
|
||||
name: "FOOD BUSINESS SUPPORT",
|
||||
linkPath: "https://www.fcmb.com/food-business-support/",
|
||||
name: 'FOOD BUSINESS SUPPORT',
|
||||
linkPath: 'https://www.fcmb.com/food-business-support/',
|
||||
},
|
||||
{ name: "SCHOOL BUSINESS SUPPORT", linkPath: "/school-support" },
|
||||
{ name: 'SCHOOL BUSINESS SUPPORT', linkPath: '/school-support' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "CURRENT ACCOUNTS",
|
||||
linkPath: "/business-current-accounts",
|
||||
name: 'CURRENT ACCOUNTS',
|
||||
linkPath: '/business-current-accounts',
|
||||
subItems: [
|
||||
{
|
||||
name: "CORPORATE CURRENT ACCOUNT",
|
||||
linkPath: "/corporate-current-account",
|
||||
name: 'CORPORATE CURRENT ACCOUNT',
|
||||
linkPath: '/corporate-current-account',
|
||||
},
|
||||
{ name: "FCMB BUSINESS ACCOUNT", linkPath: "/fcmb-business-account" },
|
||||
{ name: 'FCMB BUSINESS ACCOUNT', linkPath: '/fcmb-business-account' },
|
||||
{
|
||||
name: "DOMICILIARY CURRENT ACCOUNT",
|
||||
linkPath: "/business-domiciliary-current-account",
|
||||
name: 'DOMICILIARY CURRENT ACCOUNT',
|
||||
linkPath: '/business-domiciliary-current-account',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "SAVINGS ACCOUNTS",
|
||||
linkPath: "/node/178",
|
||||
name: 'SAVINGS ACCOUNTS',
|
||||
linkPath: '/node/178',
|
||||
subItems: [
|
||||
{
|
||||
name: "BUSINESS SAVINGS ACCOUNT",
|
||||
linkPath: "/business-savings-account",
|
||||
name: 'BUSINESS SAVINGS ACCOUNT',
|
||||
linkPath: '/business-savings-account',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "LOANS",
|
||||
linkPath: "/business-loans",
|
||||
name: 'LOANS',
|
||||
linkPath: '/business-loans',
|
||||
subItems: [
|
||||
{
|
||||
name: "SME DEVELOPMENT FINANCE FACILITY",
|
||||
linkPath: "/sme-development-finance-facility",
|
||||
name: 'SME DEVELOPMENT FINANCE FACILITY',
|
||||
linkPath: '/sme-development-finance-facility',
|
||||
},
|
||||
{
|
||||
name: "SME ASSET FINANCE FACILITY",
|
||||
linkPath: "/sme-asset-finance-facility",
|
||||
name: 'SME ASSET FINANCE FACILITY',
|
||||
linkPath: '/sme-asset-finance-facility',
|
||||
},
|
||||
{
|
||||
name: "SME WORKING CAPITAL FACILITY",
|
||||
linkPath: "/sme-working-capital-facility",
|
||||
name: 'SME WORKING CAPITAL FACILITY',
|
||||
linkPath: '/sme-working-capital-facility',
|
||||
},
|
||||
{ name: "QUICK LOAN", linkPath: "/quick-loan" },
|
||||
{ name: 'QUICK LOAN', linkPath: '/quick-loan' },
|
||||
{
|
||||
name: "SME INVOICE DISCOUNTING FINANCE (IDF) FACILITY",
|
||||
linkPath: "/invoice-discounting-loan",
|
||||
name: 'SME INVOICE DISCOUNTING FINANCE (IDF) FACILITY',
|
||||
linkPath: '/invoice-discounting-loan',
|
||||
},
|
||||
{
|
||||
name: "SME LOCAL PURCHASE ORDER (LPO) FINANCE FACILITY",
|
||||
linkPath: "/local-purchase-order-loan",
|
||||
name: 'SME LOCAL PURCHASE ORDER (LPO) FINANCE FACILITY',
|
||||
linkPath: '/local-purchase-order-loan',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ name: "BONDS & GUARANTEES", linkPath: "/bonds-and-guarantees" },
|
||||
{ name: "INTERVENTION FUNDS", linkPath: "/intervention-funds" },
|
||||
{ name: "TRADE SERVICE", linkPath: "/trade-service" },
|
||||
{ name: 'BONDS & GUARANTEES', linkPath: '/bonds-and-guarantees' },
|
||||
{ name: 'INTERVENTION FUNDS', linkPath: '/intervention-funds' },
|
||||
{ name: 'TRADE SERVICE', linkPath: '/trade-service' },
|
||||
{
|
||||
name: "PAYMENT & COLLECTION",
|
||||
linkPath: "/payment-and-collection",
|
||||
name: 'PAYMENT & COLLECTION',
|
||||
linkPath: '/payment-and-collection',
|
||||
subItems: [
|
||||
{ name: "COLLECTION SOLUTIONS", linkPath: "/collection-solutions" },
|
||||
{ name: "PAYMENT SOLUTIONS", linkPath: "/payment-solutions" },
|
||||
{ name: 'COLLECTION SOLUTIONS', linkPath: '/collection-solutions' },
|
||||
{ name: 'PAYMENT SOLUTIONS', linkPath: '/payment-solutions' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "WAYS TO BANK",
|
||||
linkPath: "/business-ways-to-bank",
|
||||
name: 'WAYS TO BANK',
|
||||
linkPath: '/business-ways-to-bank',
|
||||
subItems: [
|
||||
{
|
||||
name: "BUSINESS INTERNET BANKING",
|
||||
linkPath: "https://ibank.fcmb.com/corporate/BbgLoginScreenUI.aspx",
|
||||
name: 'BUSINESS INTERNET BANKING',
|
||||
linkPath: 'https://ibank.fcmb.com/corporate/BbgLoginScreenUI.aspx',
|
||||
},
|
||||
{
|
||||
name: "CORPORATE INTERNET BANKING",
|
||||
linkPath: "https://www.fcmbonline.com/",
|
||||
name: 'CORPORATE INTERNET BANKING',
|
||||
linkPath: 'https://www.fcmbonline.com/',
|
||||
},
|
||||
{ name: "OUR ATM NETWORK", linkPath: "/atm-network2" },
|
||||
{ name: "FCMB ONLINE", linkPath: "/fcmb-online-business" },
|
||||
{ name: 'OUR ATM NETWORK', linkPath: '/atm-network2' },
|
||||
{ name: 'FCMB ONLINE', linkPath: '/fcmb-online-business' },
|
||||
{
|
||||
name: "FCMB ELECTRONIC CHANNELS",
|
||||
linkPath: "https://www.fcmb.com/e-channels",
|
||||
name: 'FCMB ELECTRONIC CHANNELS',
|
||||
linkPath: 'https://www.fcmb.com/e-channels',
|
||||
},
|
||||
{ name: "FCMB BUSINESS APP", linkPath: "/FCMB-business-app" },
|
||||
{ name: 'FCMB BUSINESS APP', linkPath: '/FCMB-business-app' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "CORPORATE BANKING",
|
||||
linkPath: "/cooperate-banking",
|
||||
name: 'CORPORATE BANKING',
|
||||
linkPath: '/cooperate-banking',
|
||||
subItems: [
|
||||
{
|
||||
name: "FOREIGN EXCHANGE SERVICES",
|
||||
linkPath: "/foreign-exchange-services",
|
||||
name: 'FOREIGN EXCHANGE SERVICES',
|
||||
linkPath: '/foreign-exchange-services',
|
||||
},
|
||||
{ name: "TRADE SERVICES", linkPath: "/node/166" },
|
||||
{ name: "CASH MANAGEMENT SOLUTIONS", linkPath: "/cash-management" },
|
||||
{ name: "CORPORATE FINANCE", linkPath: "/corporate-finance" },
|
||||
{ name: 'TRADE SERVICES', linkPath: '/node/166' },
|
||||
{ name: 'CASH MANAGEMENT SOLUTIONS', linkPath: '/cash-management' },
|
||||
{ name: 'CORPORATE FINANCE', linkPath: '/corporate-finance' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "GROUP & SUBSIDIARIES",
|
||||
linkPath: "",
|
||||
name: 'GROUP & SUBSIDIARIES',
|
||||
linkPath: '',
|
||||
subItems: [
|
||||
{ name: "FCMB GROUP PLC", linkPath: "https://www.fcmbgroup.com/" },
|
||||
{ name: 'FCMB GROUP PLC', linkPath: 'https://www.fcmbgroup.com/' },
|
||||
{
|
||||
name: "CSL STOCKBROKERS",
|
||||
linkPath: "https://www.cslstockbrokers.com/",
|
||||
name: 'CSL STOCKBROKERS',
|
||||
linkPath: 'https://www.cslstockbrokers.com/',
|
||||
},
|
||||
{
|
||||
name: "FCMB CAPITAL MARKETS",
|
||||
linkPath: "https://www.fcmbcapitalmarketsng.com/",
|
||||
name: 'FCMB CAPITAL MARKETS',
|
||||
linkPath: 'https://www.fcmbcapitalmarketsng.com/',
|
||||
},
|
||||
{
|
||||
name: "FCMB ASSET MANAGEMENT",
|
||||
linkPath: "https://www.fcmbassetmanagement.com/index/",
|
||||
name: 'FCMB ASSET MANAGEMENT',
|
||||
linkPath: 'https://www.fcmbassetmanagement.com/index/',
|
||||
},
|
||||
{
|
||||
name: "FCMB MICROFINANCE BANK",
|
||||
linkPath: "/fcmb-microfinance-initiative",
|
||||
name: 'FCMB MICROFINANCE BANK',
|
||||
linkPath: '/fcmb-microfinance-initiative',
|
||||
},
|
||||
{ name: "FCMB UK", linkPath: "http://www.fcmbuk.com/" },
|
||||
{ name: 'FCMB UK', linkPath: 'http://www.fcmbuk.com/' },
|
||||
{
|
||||
name: "FCMB PENSIONS LIMITED",
|
||||
linkPath: "https://www.fcmbpensions.com/",
|
||||
name: 'FCMB PENSIONS LIMITED',
|
||||
linkPath: 'https://www.fcmbpensions.com/',
|
||||
},
|
||||
{
|
||||
name: "CREDIT DIRECT LIMITED",
|
||||
linkPath: "https://www.creditdirect.ng",
|
||||
name: 'CREDIT DIRECT LIMITED',
|
||||
linkPath: 'https://www.creditdirect.ng',
|
||||
},
|
||||
{ name: "FCMB TRUSTEES", linkPath: "http://fcmbtrustees.com/" },
|
||||
{ name: 'FCMB TRUSTEES', linkPath: 'http://fcmbtrustees.com/' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ABOUT US",
|
||||
linkPath: "/about-us",
|
||||
name: 'ABOUT US',
|
||||
linkPath: '/about-us',
|
||||
subItems: [
|
||||
{
|
||||
name: "OUR VISION/MISSION/VALUES",
|
||||
linkPath: "/about-us/vision-mision-core-values",
|
||||
name: 'OUR VISION/MISSION/VALUES',
|
||||
linkPath: '/about-us/vision-mision-core-values',
|
||||
},
|
||||
{ name: "OUR HISTORY", linkPath: "/about-us/our-history" },
|
||||
{ name: 'OUR HISTORY', linkPath: '/about-us/our-history' },
|
||||
{
|
||||
name: "INVESTOR RELATIONS",
|
||||
linkPath: "http://www.fcmbgroup.com/investor-relations",
|
||||
name: 'INVESTOR RELATIONS',
|
||||
linkPath: 'http://www.fcmbgroup.com/investor-relations',
|
||||
},
|
||||
{ name: "CSR", linkPath: "/corporate-social-responsibility/index.html" },
|
||||
{ name: "SUSTAINABILITY", linkPath: "/sustainability/index.html" },
|
||||
{ name: "OUR LEADERSHIP", linkPath: "/about-us/our-leadership" },
|
||||
{ name: "BOARD OF DIRECTORS", linkPath: "/about-us/board-of-directors" },
|
||||
{ name: 'CSR', linkPath: '/corporate-social-responsibility/index.html' },
|
||||
{ name: 'SUSTAINABILITY', linkPath: '/sustainability/index.html' },
|
||||
{ name: 'OUR LEADERSHIP', linkPath: '/about-us/our-leadership' },
|
||||
{ name: 'BOARD OF DIRECTORS', linkPath: '/about-us/board-of-directors' },
|
||||
{
|
||||
name: "MEDIA RELATIONS",
|
||||
linkPath: "/media-relations",
|
||||
name: 'MEDIA RELATIONS',
|
||||
linkPath: '/media-relations',
|
||||
subItems: [
|
||||
{ name: "PRESS RELEASES", linkPath: "/press-releases" },
|
||||
{ name: "MEDIA STATEMENTS", linkPath: "/press-statements" },
|
||||
{ name: 'PRESS RELEASES', linkPath: '/press-releases' },
|
||||
{ name: 'MEDIA STATEMENTS', linkPath: '/press-statements' },
|
||||
],
|
||||
},
|
||||
{ name: "AWARDS AND RECOGNITION", linkPath: "/awards" },
|
||||
{ name: 'AWARDS AND RECOGNITION', linkPath: '/awards' },
|
||||
{
|
||||
name: "OUR POLICY",
|
||||
linkPath: "/our-policies",
|
||||
name: 'OUR POLICY',
|
||||
linkPath: '/our-policies',
|
||||
subItems: [
|
||||
{ name: "BUSINESS CONTINUITY", linkPath: "/business-continuity" },
|
||||
{ name: 'BUSINESS CONTINUITY', linkPath: '/business-continuity' },
|
||||
{
|
||||
name: "CORPORATE GOVERNANCE POLICY",
|
||||
linkPath: "/corporate-governance",
|
||||
name: 'CORPORATE GOVERNANCE POLICY',
|
||||
linkPath: '/corporate-governance',
|
||||
},
|
||||
{ name: "PRIVACY POLICY", linkPath: "/privacy-policy" },
|
||||
{ name: "QUALITY POLICY", linkPath: "/quality-policy" },
|
||||
{ name: 'PRIVACY POLICY', linkPath: '/privacy-policy' },
|
||||
{ name: 'QUALITY POLICY', linkPath: '/quality-policy' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "MY BANK AND I",
|
||||
linkPath: "",
|
||||
name: 'MY BANK AND I',
|
||||
linkPath: '',
|
||||
subItems: [
|
||||
{ name: "TELEPHONE SELF SERVICE", linkPath: "/telephone-self-service" },
|
||||
{ name: 'TELEPHONE SELF SERVICE', linkPath: '/telephone-self-service' },
|
||||
{
|
||||
name: "CURRENT CAMPAIGNS/PROMOS",
|
||||
linkPath: "/current-campaigns-promos",
|
||||
name: 'CURRENT CAMPAIGNS/PROMOS',
|
||||
linkPath: '/current-campaigns-promos',
|
||||
subItems: [
|
||||
{
|
||||
name: "BOOK YOUR FLIGHTS AND PAY IN INSTALMENTS WITH FCMB",
|
||||
linkPath: "/247travels",
|
||||
name: 'BOOK YOUR FLIGHTS AND PAY IN INSTALMENTS WITH FCMB',
|
||||
linkPath: '/247travels',
|
||||
},
|
||||
{ name: "REFER AND WIN", linkPath: "/refer-and-win" },
|
||||
{ name: "CARD DISCOUNTS", linkPath: "/card-discounts" },
|
||||
{ name: 'REFER AND WIN', linkPath: '/refer-and-win' },
|
||||
{ name: 'CARD DISCOUNTS', linkPath: '/card-discounts' },
|
||||
{
|
||||
name: "FLEXX WRITING CHALLENGE",
|
||||
linkPath: "https://flexxzone.fcmb.com/writing-challenge/",
|
||||
name: 'FLEXX WRITING CHALLENGE',
|
||||
linkPath: 'https://flexxzone.fcmb.com/writing-challenge/',
|
||||
},
|
||||
{
|
||||
name: "FLEXXPRENEUR",
|
||||
name: 'FLEXXPRENEUR',
|
||||
linkPath:
|
||||
"https://flexxzone.fcmb.com/2020/07/flexxpreneur-is-back-2/",
|
||||
'https://flexxzone.fcmb.com/2020/07/flexxpreneur-is-back-2/',
|
||||
},
|
||||
{
|
||||
name: "3-MONTH FREE BANKING",
|
||||
linkPath: "https://www.fcmb.com/campaign/smebanking",
|
||||
name: '3-MONTH FREE BANKING',
|
||||
linkPath: 'https://www.fcmb.com/campaign/smebanking',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ name: "CAREERS", linkPath: "/career" },
|
||||
{ name: "CUSTOMER FEEDBACK", linkPath: "/customer-feedback" },
|
||||
{ name: "CUSTOMER SERVICE", linkPath: "/customer-service" },
|
||||
{ name: 'CAREERS', linkPath: '/career' },
|
||||
{ name: 'CUSTOMER FEEDBACK', linkPath: '/customer-feedback' },
|
||||
{ name: 'CUSTOMER SERVICE', linkPath: '/customer-service' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const socialsIcons = [
|
||||
{ name: "facebook", image: FBook, link: process.VITE_FACEBOOK_URL },
|
||||
{ name: "twitter", image: Twitter, link: process.VITE_TWITTER_URL },
|
||||
{ name: "instagram", image: Instagram, link: process.VITE_INSTAGRAM_URL },
|
||||
{ name: 'facebook', image: FBook, link: process.VITE_FACEBOOK_URL },
|
||||
{ name: 'twitter', image: Twitter, link: process.VITE_TWITTER_URL },
|
||||
{ name: 'instagram', image: Instagram, link: process.VITE_INSTAGRAM_URL },
|
||||
];
|
||||
|
||||
export const footerItems = [
|
||||
{
|
||||
category: "PERSONAL BANKING",
|
||||
category: 'PERSONAL BANKING',
|
||||
subItems: [
|
||||
{ text: "CURRENT ACCOUNTS", href: "/current-accounts" },
|
||||
{ text: "SAVINGS ACCOUNTS", href: "/savings-accounts" },
|
||||
{ text: "INVESTMENTS", href: "/investment-accounts" },
|
||||
{ text: "LOANS AND CREDIT CARDS", href: "/loans-and-credit-cards" },
|
||||
{ text: 'CURRENT ACCOUNTS', href: '/current-accounts' },
|
||||
{ text: 'SAVINGS ACCOUNTS', href: '/savings-accounts' },
|
||||
{ text: 'INVESTMENTS', href: '/investment-accounts' },
|
||||
{ text: 'LOANS AND CREDIT CARDS', href: '/loans-and-credit-cards' },
|
||||
{
|
||||
text: "NON-RESIDENT NIGERIAN (NRN) BANKING",
|
||||
href: "https://www.fcmb.com/non-resident-nigerian",
|
||||
text: 'NON-RESIDENT NIGERIAN (NRN) BANKING',
|
||||
href: 'https://www.fcmb.com/non-resident-nigerian',
|
||||
},
|
||||
{ text: "WAYS TO BANK", href: "/ways-to-bank" },
|
||||
{ text: "BANCASSURANCE", href: "/bancassurance" },
|
||||
{ text: 'WAYS TO BANK', href: '/ways-to-bank' },
|
||||
{ text: 'BANCASSURANCE', href: '/bancassurance' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: "BUSINESS BANKING",
|
||||
category: 'BUSINESS BANKING',
|
||||
subItems: [
|
||||
{ text: "PROPOSITIONS", href: "" },
|
||||
{ text: "CURRENT ACCOUNTS", href: "/business-current-accounts" },
|
||||
{ text: "SAVINGS ACCOUNTS", href: "/node/178" },
|
||||
{ text: "LOANS", href: "/business-loans" },
|
||||
{ text: "BONDS & GUARANTEES", href: "/bonds-and-guarantees" },
|
||||
{ text: "INTERVENTION FUNDS", href: "/intervention-funds" },
|
||||
{ text: "TRADE SERVICE", href: "/trade-service" },
|
||||
{ text: "PAYMENT & COLLECTION", href: "/payment-and-collection" },
|
||||
{ text: "WAYS TO BANK", href: "/business-ways-to-bank" },
|
||||
{ text: 'PROPOSITIONS', href: '' },
|
||||
{ text: 'CURRENT ACCOUNTS', href: '/business-current-accounts' },
|
||||
{ text: 'SAVINGS ACCOUNTS', href: '/node/178' },
|
||||
{ text: 'LOANS', href: '/business-loans' },
|
||||
{ text: 'BONDS & GUARANTEES', href: '/bonds-and-guarantees' },
|
||||
{ text: 'INTERVENTION FUNDS', href: '/intervention-funds' },
|
||||
{ text: 'TRADE SERVICE', href: '/trade-service' },
|
||||
{ text: 'PAYMENT & COLLECTION', href: '/payment-and-collection' },
|
||||
{ text: 'WAYS TO BANK', href: '/business-ways-to-bank' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: "COOPORATE BANKING",
|
||||
category: 'COOPORATE BANKING',
|
||||
subItems: [
|
||||
{ text: "FOREIGN EXCHANGE SERVICES", href: "/foreign-exchange-services" },
|
||||
{ text: "TRADE SERVICES", href: "/node/166" },
|
||||
{ text: "CASH MANAGEMENT SOLUTIONS", href: "/cash-management" },
|
||||
{ text: "COOPORATE FINANCE", href: "/corporate-finance" },
|
||||
{ text: 'FOREIGN EXCHANGE SERVICES', href: '/foreign-exchange-services' },
|
||||
{ text: 'TRADE SERVICES', href: '/node/166' },
|
||||
{ text: 'CASH MANAGEMENT SOLUTIONS', href: '/cash-management' },
|
||||
{ text: 'COOPORATE FINANCE', href: '/corporate-finance' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: "GROUP & SUBSIDIARIES",
|
||||
category: 'GROUP & SUBSIDIARIES',
|
||||
subItems: [
|
||||
{ text: "FCMB GROUP PLC", href: "https://www.fcmbgroup.com/" },
|
||||
{ text: "CSL STOCKBROKERS", href: "https://www.cslstockbrokers.com/" },
|
||||
{ text: 'FCMB GROUP PLC', href: 'https://www.fcmbgroup.com/' },
|
||||
{ text: 'CSL STOCKBROKERS', href: 'https://www.cslstockbrokers.com/' },
|
||||
{
|
||||
text: "FCMB CAPITAL MARKETS",
|
||||
href: "https://www.fcmbcapitalmarketsng.com/",
|
||||
text: 'FCMB CAPITAL MARKETS',
|
||||
href: 'https://www.fcmbcapitalmarketsng.com/',
|
||||
},
|
||||
{
|
||||
text: "FCMB ASSET MANAGEMENT",
|
||||
href: "https://www.fcmbassetmanagement.com/index/",
|
||||
text: 'FCMB ASSET MANAGEMENT',
|
||||
href: 'https://www.fcmbassetmanagement.com/index/',
|
||||
},
|
||||
{ text: "FCMB MICROFINANCE BANK", href: "/fcmb-microfinance-initiative" },
|
||||
{ text: "FCMB UK", href: "http://www.fcmbuk.com/" },
|
||||
{ text: "FCMB PENSIONS LIMITED", href: "https://www.fcmbpensions.com/" },
|
||||
{ text: "CREDIT DIRECT LIMITED", href: "https://www.creditdirect.ng" },
|
||||
{ text: "FCMB TRUSTEES", href: "http://fcmbtrustees.com/" },
|
||||
{ text: 'FCMB MICROFINANCE BANK', href: '/fcmb-microfinance-initiative' },
|
||||
{ text: 'FCMB UK', href: 'http://www.fcmbuk.com/' },
|
||||
{ text: 'FCMB PENSIONS LIMITED', href: 'https://www.fcmbpensions.com/' },
|
||||
{ text: 'CREDIT DIRECT LIMITED', href: 'https://www.creditdirect.ng' },
|
||||
{ text: 'FCMB TRUSTEES', href: 'http://fcmbtrustees.com/' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: "ABOUT US",
|
||||
category: 'ABOUT US',
|
||||
subItems: [
|
||||
{
|
||||
text: "OUR VISION/MISSION/VALUES",
|
||||
href: "/about-us/vision-mision-core-values",
|
||||
text: 'OUR VISION/MISSION/VALUES',
|
||||
href: '/about-us/vision-mision-core-values',
|
||||
},
|
||||
{ text: "OUR HISTORY", href: "/about-us/our-history" },
|
||||
{ text: 'OUR HISTORY', href: '/about-us/our-history' },
|
||||
{
|
||||
text: "INVESTOR RELATIONS",
|
||||
href: "http://www.fcmbgroup.com/investor-relations",
|
||||
text: 'INVESTOR RELATIONS',
|
||||
href: 'http://www.fcmbgroup.com/investor-relations',
|
||||
},
|
||||
{ text: "CSR", href: "/corporate-social-responsibility/index.html" },
|
||||
{ text: "SUSTAINABILITY", href: "/sustainability/index.html" },
|
||||
{ text: "OUR LEADERSHIP", href: "/about-us/our-leadership" },
|
||||
{ text: "BOARD OF DIRECTORS", href: "/about-us/board-of-directors" },
|
||||
{ text: "MEDIA RELATIONS", href: "/media-relations" },
|
||||
{ text: "AWARDS AND RECOGNITION", href: "/awards" },
|
||||
{ text: "OUR POLICY", href: "/our-policies" },
|
||||
{ text: 'CSR', href: '/corporate-social-responsibility/index.html' },
|
||||
{ text: 'SUSTAINABILITY', href: '/sustainability/index.html' },
|
||||
{ text: 'OUR LEADERSHIP', href: '/about-us/our-leadership' },
|
||||
{ text: 'BOARD OF DIRECTORS', href: '/about-us/board-of-directors' },
|
||||
{ text: 'MEDIA RELATIONS', href: '/media-relations' },
|
||||
{ text: 'AWARDS AND RECOGNITION', href: '/awards' },
|
||||
{ text: 'OUR POLICY', href: '/our-policies' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: "MY BANK AND I",
|
||||
category: 'MY BANK AND I',
|
||||
subItems: [
|
||||
{ text: "TELEPHONE SELF SERVICE", href: "/telephone-self-service" },
|
||||
{ text: "CURRENT CAMPAIGNS/PROMOS", href: "/current-campaigns-promos" },
|
||||
{ text: "CAREERS", href: "/career" },
|
||||
{ text: "CUSTOMER FEEDBACK", href: "/customer-feedback" },
|
||||
{ text: "CUSTOMER SERVICE", href: "/customer-service" },
|
||||
{ text: 'TELEPHONE SELF SERVICE', href: '/telephone-self-service' },
|
||||
{ text: 'CURRENT CAMPAIGNS/PROMOS', href: '/current-campaigns-promos' },
|
||||
{ text: 'CAREERS', href: '/career' },
|
||||
{ text: 'CUSTOMER FEEDBACK', href: '/customer-feedback' },
|
||||
{ text: 'CUSTOMER SERVICE', href: '/customer-service' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const footerSocialLinks = [
|
||||
{
|
||||
href: "https://www.facebook.com/FcmbMyBank/",
|
||||
href: 'https://www.facebook.com/FcmbMyBank/',
|
||||
icon: FBookWhite,
|
||||
},
|
||||
{
|
||||
href: "https://twitter.com/myfcmb/",
|
||||
href: 'https://twitter.com/myfcmb/',
|
||||
icon: XWhite,
|
||||
},
|
||||
{
|
||||
href: "https://www.linkedin.com/company/first-city-monument-bank-ltd/",
|
||||
href: 'https://www.linkedin.com/company/first-city-monument-bank-ltd/',
|
||||
icon: LinkedInWhite,
|
||||
},
|
||||
{
|
||||
href: "https://www.youtube.com/user/fcmbplc",
|
||||
href: 'https://www.youtube.com/user/fcmbplc',
|
||||
icon: YoutubeWhite,
|
||||
},
|
||||
{
|
||||
href: "https://www.instagram.com/myfcmb/",
|
||||
href: 'https://www.instagram.com/myfcmb/',
|
||||
icon: InstagramWhite,
|
||||
},
|
||||
{
|
||||
href: "https://api.whatsapp.com/send?phone=09099999814",
|
||||
href: 'https://api.whatsapp.com/send?phone=09099999814',
|
||||
icon: WhatsappWhite,
|
||||
},
|
||||
];
|
||||
|
||||
export const footerCustomerLinks = [
|
||||
{
|
||||
text: "PRIVACY POLICY",
|
||||
href: "https://www.fcmb.com/privacy-policy",
|
||||
text: 'PRIVACY POLICY',
|
||||
href: 'https://www.fcmb.com/privacy-policy',
|
||||
},
|
||||
{
|
||||
text: "PRESS RELEASES",
|
||||
href: "/press-releases",
|
||||
text: 'PRESS RELEASES',
|
||||
href: '/press-releases',
|
||||
},
|
||||
{
|
||||
text: "SHARE PRICE",
|
||||
href: "/",
|
||||
text: 'SHARE PRICE',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
text: "WHISTLE BLOWER",
|
||||
href: "/fcmb-whistle-blower-form",
|
||||
text: 'WHISTLE BLOWER',
|
||||
href: '/fcmb-whistle-blower-form',
|
||||
},
|
||||
{
|
||||
text: "FRAUD PREVENTION",
|
||||
href: "/customer-service",
|
||||
text: 'FRAUD PREVENTION',
|
||||
href: '/customer-service',
|
||||
},
|
||||
{
|
||||
text: "AML",
|
||||
href: "/customer-service",
|
||||
text: 'AML',
|
||||
href: '/customer-service',
|
||||
},
|
||||
{
|
||||
text: "CAREERS",
|
||||
href: "/career",
|
||||
text: 'CAREERS',
|
||||
href: '/career',
|
||||
},
|
||||
];
|
||||
|
||||
export const contactDetails = [
|
||||
{ name: 'Call', value: import.meta.env.VITE_CALL_ENDPOINT },
|
||||
{ name: 'Email', value: import.meta.env.VITE_EMAIL_ENDPOINT },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user