Compare commits

..

53 Commits

Author SHA1 Message Date
victorAnumudu c60f49dc90 added bank name in env variable 2024-06-28 23:40:05 +01:00
ameye 157151e6d1 Merge branch 'employer_uid_payload_update' of DigiFi/digifi-www into master 2024-06-13 15:06:02 +00:00
victorAnumudu 2f7f482293 updated apply loan payload for employer uid 2024-06-13 15:00:24 +01:00
ameye ee86d40bcc Merge branch 'employer-uid' of DigiFi/digifi-www into master 2024-06-11 18:36:57 +00:00
victorAnumudu 409acd300d employer uid payload added 2024-06-11 19:01:16 +01:00
ameye fc7edec093 Merge branch 'employer-info-update' of DigiFi/digifi-www into master 2024-06-10 19:15:14 +00:00
victorAnumudu 4637944fbd changed layout structure 2024-06-10 20:13:13 +01:00
tokslaw cc44af7e55 Merge branch 'auto_logout_FIX_CONFLICT' of DigiFi/digifi-www into master 2024-05-15 15:21:17 +00:00
Elias df5b4c89a4 fix merge conflict:auto logout after 7mins 2024-05-15 15:34:25 +01:00
ameye a37a5c24f5 Merge branch 'update_env' of DigiFi/digifi-www into master 2024-05-15 08:55:09 +00:00
ameye 890452af63 Merge branch 'bvn_code_max_input' of DigiFi/digifi-www into master 2024-05-15 08:55:02 +00:00
ameye 69b6850002 Merge branch 'action_btn_to_extreme_right' of DigiFi/digifi-www into master 2024-05-15 08:54:57 +00:00
Elias dd8290af9a action button moved to extreme right 2024-05-14 12:34:15 +01:00
Elias 306ab06142 Merge branch 'master' into update_env 2024-05-14 11:56:57 +01:00
tokslaw 4d258a965b Merge branch 'layout-padding' of DigiFi/digifi-www into master 2024-05-09 17:29:13 +00:00
Elias f63171273e max input length: bvn & code 2024-05-07 15:19:40 +01:00
Elias b4bf96e841 include contact details in .env 2024-05-07 14:33:46 +01:00
victorAnumudu e20b7e32f1 adjusted layout padding on mobile view 2024-05-06 19:00:56 +01:00
ameye 6bd533c7ca Merge branch 'pending-loan-list' of DigiFi/digifi-www into master 2024-05-06 16:51:12 +00:00
victorAnumudu 408777353d pending loan list added 2024-05-06 16:52:00 +01:00
victorAnumudu a2e039eab4 initial commit 2024-05-06 14:44:42 +01:00
ameye 8d6cc5861e Merge branch 'link-path' of DigiFi/digifi-www into master 2024-05-06 12:23:07 +00:00
victorAnumudu 18967d720c link path corrected 2024-05-06 12:27:16 +01:00
ameye 044b2ef917 Merge branch 'bug-fix' of DigiFi/digifi-www into master 2024-05-03 16:59:47 +00:00
ameye 4f7fdfb2ba Merge branch 'agent-id' of DigiFi/digifi-www into master 2024-05-03 16:59:43 +00:00
victorAnumudu ab389d6632 load profile bug fix 2024-05-03 17:57:32 +01:00
victorAnumudu 29538e3b6e made agent id optional 2024-05-02 10:09:36 +01:00
ameye dd2df0d695 Merge branch 'get-user-details' of DigiFi/digifi-www into master 2024-05-01 16:52:44 +00:00
victorAnumudu a97db9a661 added get user by ID API 2024-05-01 17:33:41 +01:00
ameye 135cbce348 Merge branch 'loan-application-submit' of DigiFi/digifi-www into master 2024-04-30 19:13:50 +00:00
victorAnumudu 814bfe041a added endpoint for loan application 2024-04-30 19:03:22 +01:00
ameye d90d515f60 Merge branch 'loan-application-details' of DigiFi/digifi-www into master 2024-04-30 10:57:52 +00:00
victorAnumudu e93a3dea68 collected laon application details 2024-04-30 01:02:48 +01:00
ameye a50d5ec82d Merge branch 'logout-implemented' of DigiFi/digifi-www into master 2024-04-27 23:33:38 +00:00
victorAnumudu 333ada0a1c implemented logout 2024-04-27 23:52:11 +01:00
ameye bb718953ad Merge branch 'verify-bvn-bug' of DigiFi/digifi-www into master 2024-04-27 01:41:59 +00:00
victorAnumudu a31b36686d verify bvn auto api calling bug fixed 2024-04-27 02:36:40 +01:00
CHIEFSOFT\ameye 00f4e1b565 extra host 2024-04-26 19:31:33 -04:00
ameye 6d302def04 Merge branch 'added-axios-package' of DigiFi/digifi-www into master 2024-04-26 23:18:29 +00:00
victorAnumudu 82dd11a772 added axios package and api for start bvn verification 2024-04-26 23:41:41 +01:00
ameye 7e9c395f4a Merge branch 'form-validation-contd' of DigiFi/digifi-www into master 2024-04-24 12:32:27 +00:00
victorAnumudu 2cb5c471f6 form validation with formik 2024-04-24 11:42:04 +01:00
ameye 4b008f6785 Merge branch 'input-validation' of DigiFi/digifi-www into master 2024-04-23 18:50:24 +00:00
ameye f632099128 Merge branch 'docker-compose-props' of DigiFi/digifi-www into master 2024-04-23 18:50:20 +00:00
ameye 122eb31732 Merge branch 'header-z-index' of DigiFi/digifi-www into master 2024-04-23 18:50:17 +00:00
victorAnumudu 0207bf631a started input validation on forms 2024-04-23 19:25:50 +01:00
victorAnumudu 378ff4a625 added props to docker compose file 2024-04-23 15:41:54 +01:00
victorAnumudu f88b6df24c increase z-index level for the header component 2024-04-23 11:36:18 +01:00
ameye fe759c6d0a Merge branch 'select-input' of DigiFi/digifi-www into master 2024-04-23 10:26:53 +00:00
victorAnumudu 104295bdb2 select input added where necessary 2024-04-22 22:38:35 +01:00
ameye 44933d4362 Merge branch 'loan-application-process' of DigiFi/digifi-www into master 2024-04-22 17:08:37 +00:00
victorAnumudu 9ce7110a5d added steps to loan application 2024-04-22 15:42:40 +01:00
ameye 085b2d4aaa Merge branch 'get-started-page' of DigiFi/digifi-www into master 2024-04-22 11:39:10 +00:00
48 changed files with 3411 additions and 1383 deletions
+12 -1
View File
@@ -3,4 +3,15 @@ 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'
#BANK NAME
VITE_BANK_NAME='First City Monument Bank'
VITE_BANK_NAME_SHORT='FCMB'
+8 -1
View File
@@ -3,4 +3,11 @@ 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'
#BANK NAME
VITE_BANK_NAME='First City Monument Bank'
VITE_BANK_NAME_SHORT='FCMB'
+8 -1
View File
@@ -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'
#BANK NAME
VITE_BANK_NAME='First City Monument Bank'
VITE_BANK_NAME_SHORT='FCMB'
+7 -2
View File
@@ -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:
+100
View File
@@ -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",
+2
View File
@@ -11,10 +11,12 @@
},
"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",
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

+105 -40
View File
@@ -1,51 +1,116 @@
import { Button, InputCompOne, Stepper } from "..";
import { useNavigate } from "react-router-dom";
import { RouteHandler } from "../../router/routes";
import {Formik, Form} from 'formik'
import * as Yup from "yup";
export default function DashboardFormInit() {
let navigate = useNavigate();
type Props = {
handleNextStep:(value:{})=>any
}
const initialValues = {
loan_amount: "",
payment_month: "",
sales_agent: "",
};
// To get the validation schema
const validationSchema = Yup.object().shape({
payment_month: Yup.string()
.required("Required"),
loan_amount: Yup.string()
.required("Required")
.test("no-e", "Invalid", (value:any) => {
if (value && /^[0-9]*$/.test(value) == false) {
return false;
}
return true;
}),
sales_agent: Yup.string()
});
export default function DashboardFormInit({handleNextStep}:Props) {
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:{}) => {
handleNextStep(values)
};
const navigateToProfile = () => navigate(RouteHandler.dashboardProfile);
return (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={0} />
</div>
<div className="mt-[3.25rem] flex flex-col gap-9">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
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]"
placeholder="350,000"
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="For How Many Months?"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="12 Months"
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="Direct sales agent ID ( Optional )"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Agent ID"
/>
<Button
className="my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
text="Next"
type="button"
onClick={navigateToProfile}
/>
</div>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(props)=>(
<Form>
<div className="mt-[3.25rem] flex flex-col gap-9">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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.loan_amount}
onChange={props.handleChange}
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="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={paymentMonth}
selectValue={props.values.payment_month}
onChange={props.handleChange}
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="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.sales_agent}
onChange={props.handleChange}
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"
text="Next"
type="submit"
/>
</div>
</Form>
)}
</Formik>
</div>
);
}
interface SelectOption {
loading: boolean;
data: {value: string;
label: string}[]
}
const paymentMonth: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "6", label: "6 Months" },
{ value: "12", label: "12 Months" },
{ value: "18", label: "18 Months" },
{ value: "24", label: "24 Months" },
]
}
+17 -5
View File
@@ -1,22 +1,34 @@
import React, { FC } from "react";
import DashboardHomeIntro from "./DashboardHomeIntro";
import DashboardFormInit from "./DashboardFormInit";
import DashboardHomeDetail from "./home/DashboardHomeDetail";
import DashboardHomeEmploymentInfo from "./home/DashboardHomeEmploymentInfo";
import DashboardHomeRefereeInfo from "./home/DashboardHomeRefereeInfo";
import DashboardHomeAttestation from "./home/DashboardHomeAttestation";
interface DashboardHomeProps {}
const DashboardHome: FC<DashboardHomeProps> = () => {
const [step, setStep] = React.useState(1);
const [applicationDetails, setApplicationDetails] = React.useState({});
const handleNextStep = () => {
if (step < 2) {
const handleNextStep = (values:{}={}) => {
if (step < 7) {
setStep(step + 1);
}
};
setApplicationDetails((prev:{}) => ({...prev, ...values}))
}
return (
<div className="w-full">
{step === 1 && <DashboardHomeIntro handleNextStep={handleNextStep} />}
{step === 2 && <DashboardFormInit />}
{step === 1 && <DashboardHomeIntro step={step} handleNextStep={handleNextStep} />}
{step === 2 && <DashboardFormInit handleNextStep={handleNextStep} />}
{step === 3 && <DashboardHomeDetail handleNextStep={handleNextStep} />}
{step === 4 && <DashboardHomeEmploymentInfo handleNextStep={handleNextStep} />}
{step === 5 && <DashboardHomeRefereeInfo handleNextStep={handleNextStep} />}
{step === 6 && <DashboardHomeAttestation handleNextStep={handleNextStep} applicationDetails={applicationDetails} />}
{step === 7 && <DashboardHomeIntro step={step} handleNextStep={handleNextStep} />}
{/* <DashboardHomeAttestation handleNextStep={handleNextStep} applicationDetails={applicationDetails} /> */}
</div>
);
};
+138 -23
View File
@@ -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,28 +73,138 @@ export const DashBoardCard: React.FC<DashBoardCardProps> = ({
};
interface DashboardHomeIntroProps {
handleNextStep: any;
handleNextStep: (value: {}) => any;
step?: number | string;
}
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({ handleNextStep }) => {
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 (
<>
<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>
</>
<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>
);
};
+38 -34
View File
@@ -1,21 +1,34 @@
import { Button, InputCompOne, Stepper } from "..";
import { InputCompOne } from "..";
import { useNavigate } from "react-router-dom";
import { RouteHandler } from "../../router/routes";
export default function DashboardProfile() {
let navigate = useNavigate();
const navigateToProfile = () => navigate(RouteHandler.dashboardHome);
return (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={1} />
<div className='my-[2rem] flex items-center'>
<button onClick={navigateToProfile} className='w-6 h-6 text-lg flex justify-center items-center rounded-full bg-gray-500'>&lt;</button>
</div>
<div className="mt-[3.25rem] flex flex-col gap-9">
<div className="flex items-center gap-[4.125rem]">
<div className="max-w-[25.875rem] w-full p-4 rounded-xl flex flex-col gap-1 bg-[#FBB700]/30">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="Select your gender"
label="Full name"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Male"
placeholder="John James"
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="Phone number"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="07000000000"
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
@@ -26,17 +39,6 @@ export default function DashboardProfile() {
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Somewhere in lagos"
/>
</div>
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="Marital status"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Single"
/>{" "}
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
@@ -46,22 +48,24 @@ export default function DashboardProfile() {
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Lagos"
/>
</div>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
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"
/>
<Button
className="my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
text="Next"
type="button"
// onClick={navigateToProfile}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
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"
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="Date of birth"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="12/10/1994"
/>
</div>
</div>
);
@@ -0,0 +1,147 @@
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:(value:{})=>any
applicationDetails: {}
}
const initialValues = {
account: "",
checked: false
};
// To get the validation schema
const validationSchema = Yup.object().shape({
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, applicationDetails}:Props) {
// let navigate = useNavigate();
// const navigateToProfile = () => navigate(RouteHandler.dashboardProfile);
//FUNCTION TO HANDLE LOAN APPLICATION
const handleSubmit = (values:any) => {
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 (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={4} />
</div>
<p className='my-10 text-red-500 text-lg md:text-2xl'>Applicant's Attestation and Debit Instruction</p>
<p className='text-red-500 text-base'>NB: Must be your {import.meta.env.VITE_BANK_NAME_SHORT} account number</p>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(props)=>(
<Form>
<div className="flex flex-col gap-9">
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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}
onChange={props.handleChange}
error={(props.errors.account && props.touched.account) ? props.errors.account : ''}
/>
</div>
<div className='max-w-[25.875rem]'>
<div className='flex gap-4 items-start'>
<input
type='checkbox'
name="checked"
className='w-4 h-4 p-2 accent-purple-600 text-purple-600 bg-gray-100 border-gray-300 rounded focus:ring-purple-500'
onChange={props.handleChange}
/>
<p className='text-[12px] text-justify'>By pressing, you agree that you have read, understood and accept the <span className='text-blue-600'>applicatant's attestation</span> and <span className='text-blue-600'>terms and conditions</span> for {import.meta.env.VITE_BANK_NAME_SHORT}
premium salary loan. You also give us permission to collect financial information and run credit checks on the account provided through our partners
</p>
</div>
{props.errors.checked && props.touched.checked && <span className='text-[10px] text-red-500'>{props.errors.checked}</span>}
</div>
<Button
className="my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
text="Apply"
type="submit"
/>
</div>
</Form>
)}
</Formik>
</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'}
// }
@@ -0,0 +1,190 @@
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
type Props = {
handleNextStep:(value:{})=>any
}
const initialValues = {
gender: "",
address: "",
marital_status: "",
state: "",
email:"",
country:""
};
// To get the validation schema
const validationSchema = Yup.object().shape({
gender: Yup.string()
.required("Required"),
address: Yup.string()
.required("Required"),
marital_status: Yup.string()
.required("Required"),
state: Yup.string()
.required("Required"),
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) => {
handleNextStep(values)
};
return (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={1} />
</div>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(props)=>(
<Form>
<div className="mt-[3.25rem] flex flex-col gap-9">
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="gender"
label="Select your gender"
labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={gender}
selectValue={props.values.gender}
onChange={props.handleChange}
error={(props.errors.gender && props.touched.gender) ? props.errors.gender : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="address"
label="Residential address"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Somewhere in lagos"
value={props.values.address}
onChange={props.handleChange}
error={(props.errors.address && props.touched.address) ? props.errors.address : ''}
/>
</div>
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="marital_status"
label="Marital status"
labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={maritalStatus}
selectValue={props.values.marital_status}
onChange={props.handleChange}
error={(props.errors.marital_status && props.touched.marital_status) ? props.errors.marital_status : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="state"
label="Select your state"
labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={state}
selectValue={props.values.state}
onChange={props.handleChange}
error={(props.errors.state && props.touched.state) ? props.errors.state : ''}
/>
</div>
<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"
type="submit"
/>
</div>
</Form>
)}
</Formik>
</div>
);
}
interface SelectOption {
loading: boolean;
data: {value: string;
label: string}[]
}
const gender: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "male", label: "Male" },
{ value: "female", label: "Female" },
{ value: "others", label: "Prefer not to say" },
]
}
const maritalStatus: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "single", label: "Single" },
{ value: "married", label: "Married" },
{ value: "divorced", label: "Divorced" },
]
}
const state: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "abia", label: "Abia" },
{ value: "imo", label: "Imo" },
{ value: "lagos", label: "Lagos" },
]
}
const country: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "NG", label: "Nigeria" },
]
}
@@ -0,0 +1,353 @@
import {useState, useEffect} from 'react'
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
import { getEmployersList } from '../../../core/apiRequest';
type Props = {
handleNextStep:(value:{})=>any
}
// type EmployerProps = {
// loading?: boolean,
// data?: Array<{[index:string]: string}> | {[index:string]: Array<{[index:string]: string}> }
// }
const initialValues = {
job_title: "",
name: "",
sector: "",
industry: "",
resumption_date: "",
email:"",
annual_income: "",
monthly_salary: "",
salary_payment_date: "",
employment_id: "",
highest_eductaion: "",
employer_uid: "",
isChecked: false
};
// To get the validation schema
const validationSchema = Yup.object().shape({
isChecked: Yup.bool(), // use bool instead of boolean
// .oneOf([true, false], "You must accept the terms and conditions"),
job_title: Yup.string()
.required("Required"),
name: Yup.string().when('isChecked', {
is: true,
then: () => Yup.string().required('required'),
otherwise: () => Yup.string(),
}),
sector: Yup.string().when('isChecked', {
is: true,
then: () => Yup.string().required('required'),
}),
industry: Yup.string().when('isChecked', {
is: true,
then: () => Yup.string().required('required'),
}),
resumption_date: Yup.string()
.required("Required"),
email: Yup.string().when('isChecked', {
is: true,
then: () => Yup.string().required('required'),
})
.email("Invalid"),
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"),
employment_id: Yup.string()
.required("Required"),
highest_eductaion: Yup.string()
.required("Required"),
employer_uid: Yup.string().when('isChecked', {
is: false,
then: () => Yup.string().required('required'),
}),
});
export default function DashboardHomeEmploymentInfo({handleNextStep}:Props) {
const [employersList, setEmployersList] = useState<any>({
loading: true,
data: []
})
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
// Remember to changed the checked value's name
if(values.employer_uid){
let employer_uid = values.employer_uid
delete values.employer_uid
handleNextStep({employer_uid, employment: values})
}else{
handleNextStep({employment: values})
}
};
useEffect(()=>{
getEmployersList().then(res => {
setEmployersList({loading:false, data:res?.data})
}).catch(err => {
console.log(err)
setEmployersList({loading:false, data:[]})
})
},[])
return (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={2} />
</div>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(props)=>(
<Form>
<div className="mt-[3.25rem] flex flex-col gap-9">
<p className='text-red-500 text-lg md:text-2xl'>Employment Informaton</p>
<div className="flex flex-col lg:flex-row items-start gap-[2rem]">
<div className='w-full lg:max-w-[30rem] flex flex-col'>
<div className='w-full gap-[2rem]'>
<InputCompOne
parentClass="w-full"
name="employer_uid"
floatLabel="Employer Name"
// labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={{loading:employersList?.loading, data: employersList?.data?.records}}
selectValue={props.values.employer_uid}
onChange={props.handleChange}
error={(props.errors.employer_uid && props.touched.employer_uid) ? props.errors.employer_uid : ''}
disabled={props.values.isChecked}
/>
<div className='flex gap-4 items-start my-2'>
<input
type='checkbox'
name="isChecked"
className='w-4 h-4 p-2 accent-purple-600 text-purple-600 bg-gray-100 border-gray-300 rounded focus:ring-purple-500'
onChange={props.handleChange}
checked={props.values.isChecked}
/>
<p className='text-[12px] text-justify'>Check here if employer is not on the list</p>
</div>
<div className={`hidden p-4 ${props.values.isChecked && 'hidden'}`}>
Name: {'Name'}
</div>
</div>
<div className={`w-full flex flex-col gap-[2rem] ${!props.values.isChecked && 'hidden'}`}>
<InputCompOne
parentClass="w-full"
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.name}
onChange={props.handleChange}
error={(props.errors.name && props.touched.name) ? props.errors.name : ''}
/>
<InputCompOne
parentClass="w-full"
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.email}
onChange={props.handleChange}
error={(props.errors.email && props.touched.email) ? props.errors.email : ''}
/>
<InputCompOne
parentClass="w-full"
name="industry"
floatLabel="Select your industry"
// labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={industry}
selectValue={props.values.industry}
onChange={props.handleChange}
error={(props.errors.industry && props.touched.industry) ? props.errors.industry : ''}
/>
<InputCompOne
parentClass="w-full"
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.sector}
onChange={props.handleChange}
error={(props.errors.sector && props.touched.sector) ? props.errors.sector : ''}
/>
</div>
</div>
<div className='w-full lg:max-w-[30rem] flex flex-col gap-[2rem]'>
<InputCompOne
parentClass="w-full"
name="job_title"
floatLabel="Job Title"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Software Engineer"
value={props.values.job_title}
onChange={props.handleChange}
error={(props.errors.job_title && props.touched.job_title) ? props.errors.job_title : ''}
/>
<InputCompOne
parentClass="w-full"
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={highestEductaion}
selectValue={props.values.highest_eductaion}
onChange={props.handleChange}
error={(props.errors.highest_eductaion && props.touched.highest_eductaion) ? props.errors.highest_eductaion : ''}
/>
<div className="w-full flex flex-col sm:flex-row items-center gap-4">
<InputCompOne
parentClass="w-full"
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.resumption_date}
onChange={props.handleChange}
error={(props.errors.resumption_date && props.touched.resumption_date) ? props.errors.resumption_date : ''}
/>
<InputCompOne
parentClass="w-full"
name="salary_payment_date"
floatLabel="Salary payment date"
// labelClass="font-bold text-[1.125rem]"
input
inputType='date'
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="30th of every month"
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 flex flex-col sm:flex-row items-center gap-4">
<InputCompOne
parentClass="w-full"
name="annual_income"
floatLabel="Annual Income"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
placeholder="1,200,000"
value={props.values.annual_income}
onChange={props.handleChange}
error={(props.errors.annual_income && props.touched.annual_income) ? props.errors.annual_income : ''}
/>
<InputCompOne
parentClass="w-full"
name="monthly_salary"
floatLabel="Net monthly salary"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
placeholder="100,000"
value={props.values.monthly_salary}
onChange={props.handleChange}
error={(props.errors.monthly_salary && props.touched.monthly_salary) ? props.errors.monthly_salary : ''}
/>
</div>
<InputCompOne
parentClass="w-full"
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.employment_id}
onChange={props.handleChange}
error={(props.errors.employment_id && props.touched.employment_id) ? props.errors.employment_id : ''}
/>
<div className="w-full">
<Button
className="my-4 btn-Y text-black w-full h-11"
text="Next"
type="submit"
/>
</div>
</div>
</div>
</div>
</Form>
)}
</Formik>
</div>
);
}
interface SelectOption {
loading: boolean;
data: {value: string;
label: string}[]
}
const jobSector: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "private (non academic)", label: "Private (non academic)" },
]
}
const industry: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "engineering", label: "Engineering" },
]
}
const highestEductaion: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "b.sc + professional qualification", label: "B.Sc + Professional Qualification" },
]
}
@@ -0,0 +1,244 @@
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
type Props = {
handleNextStep:(value:{})=>any
}
const initialValues = {
ref_name: "",
ref_email: "",
ref_phone_number: "",
ref_relationship: "",
ref_bvn: "",
ref_two_name: "",
ref_two_email: "",
ref_two_phone_number: "",
ref_two_relationship: "",
ref_two_bvn: "",
};
// To get the validation schema
const validationSchema = Yup.object().shape({
ref_name: Yup.string()
.required("Required"),
ref_email: Yup.string()
.email("Invalid")
.required("Required"),
ref_phone_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_phone_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"),
});
export default function DashboardHomeRefereeInfo({handleNextStep}:Props) {
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
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]})
};
return (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={3} />
</div>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(props)=>(
<Form>
<div className="mt-[3.25rem] flex flex-col gap-9">
<p className='text-red-500 text-lg md:text-2xl'>Reference Details <span className='text-base'>(Must be 18 years and above)</span></p>
<div className="flex items-center gap-[4.125rem]">
<div className='w-full max-w-[25.875rem]'>
<p className='text-red-500 text-base'>Reference one</p>
<div className='w-full flex flex-col gap-9'>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="ref_name"
floatLabel="Full name"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="John James"
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-[25.875rem] w-full flex flex-col gap-4"
name="ref_relationship"
floatLabel="Relationship"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Sister"
value={props.values.ref_relationship}
onChange={props.handleChange}
error={(props.errors.ref_relationship && props.touched.ref_relationship) ? props.errors.ref_relationship : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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_phone_number}
onChange={props.handleChange}
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"
name="ref_email"
floatLabel="Email address"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="demo@gamil.com"
value={props.values.ref_email}
onChange={props.handleChange}
error={(props.errors.ref_email && props.touched.ref_email) ? props.errors.ref_email : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="ref_bvn"
floatLabel="BVN"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="2228457896"
value={props.values.ref_bvn}
onChange={props.handleChange}
error={(props.errors.ref_bvn && props.touched.ref_bvn) ? props.errors.ref_bvn : ''}
/>
</div>
</div>
<div className='w-full max-w-[25.875rem]'>
<p className='text-red-500 text-base'>Reference two</p>
<div className='w-full flex flex-col gap-9'>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="ref_two_name"
floatLabel="Full name"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="John James"
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-[25.875rem] w-full flex flex-col gap-4"
name="ref_two_relationship"
floatLabel="Relationship"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Sister"
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 : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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_phone_number}
onChange={props.handleChange}
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"
name="ref_two_email"
floatLabel="Email address"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="demo@gamil.com"
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 : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="ref_two_bvn"
floatLabel="BVN"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="2228457896"
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-[25.875rem] btn-Y text-black w-full h-11"
text="Next"
type="submit"
/>
</div>
</Form>
)}
</Formik>
</div>
);
}
+1 -1
View File
@@ -17,7 +17,7 @@ const BottomFooterOne = () => {
<CustomerLinks />
</div>
<p className="text-[.8125rem] text-[#333] leading-[1.42857]">
© <span>{date}</span> First City Monument Bank (Licensed by the
© <span>{date}</span> {import.meta.env.VITE_BANK_NAME} (Licensed by the
Central Bank of Nigeria)
</p>
</div>
+1 -1
View File
@@ -8,7 +8,7 @@ export default function Footer() {
<div className="w-full h-[5.4375rem] bg-[F7F7F7] flex items-center">
<div className="containerMode flex justify-center md:justify-between items-center flex-wrap gap-2">
<p className="text-[.9375rem] tracking-[2%] font-semibold text-[#969696]">
{date} @ First City Monument Bank Limited
{date} @ {import.meta.env.VITE_BANK_NAME} Limited
</p>
<div className="footer-social-icons flex justify-end items-center gap-2">
{renderSocialLinks()}
@@ -1,6 +1,7 @@
import React from "react";
import DebitAccount from "./DebitAccount";
const ApplicantsAttestation: React.FC = () => {
return (
<>
+1 -1
View File
@@ -32,6 +32,7 @@ const BVN = ({handleNextStep}:Props) => {
const handleSubmit = (values:any) => {
console.log('values', values)
handleNextStep()
};
return (
@@ -70,7 +71,6 @@ const BVN = ({handleNextStep}:Props) => {
<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"
onClick={handleNextStep}
>
Enter
</button>
+285 -75
View File
@@ -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]">
Lets 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" },
]
}
+124 -69
View File
@@ -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="Employers 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="Employers 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;
-28
View File
@@ -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}
/>
)}
-133
View File
@@ -1,133 +0,0 @@
import React from "react";
import InputCompOne from "../shared/InputCompOne";
interface Option {
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: [{ 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: Option[] = [
{ value: "", label: "Select" },
{ value: "single", label: "Single" },
{ value: "married", label: "Married" },
{ value: "divorced", label: "Divorced" },
{ value: "widowed", label: "Widowed" },
];
const titleOptions: Option[] = [
{ value: "", label: "Select" },
{ value: "ms", label: "Ms" },
{ value: "mr", label: "Mr" },
{ value: "miss", label: "Miss" },
{ value: "mrs", label: "Mrs" },
];
+163 -90
View File
@@ -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>
// );
// };
-111
View File
@@ -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;
+385 -14
View File
@@ -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]">
Youre 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="Employers 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="Employers 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>
</>
);
};
+1 -1
View File
@@ -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,
@@ -12,7 +12,7 @@ const EligiblityBox = () => {
You must have a valid BVN
</li>
<li className="text-base leading-[1.5625rem]">
Must have a salary or current bank account with FCMB
Must have a salary or current bank account with {import.meta.env.VITE_BANK_NAME_SHORT}
</li>
</ul>
</div>
+9 -2
View File
@@ -1,10 +1,13 @@
import { FaCaretDown, FaCaretRight } from "react-icons/fa";
import dashIcon from "../../assets/images/dashboard/dashDefault.svg";
type Props = {
name: string;
fillColor?: string;
className?:string;
};
export default function Icons({ name, fillColor }: Props) {
export default function Icons({ name, fillColor, className }: Props) {
return (
<>
{name == "home" ? (
@@ -106,7 +109,11 @@ export default function Icons({ name, fillColor }: Props) {
fill={fillColor ? fillColor : "#FFF"}
/>
</svg>
) : name == "dash-icon" ? (
) :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}
</>
+216 -121
View File
@@ -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">
Lets 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">
Lets 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"
}`}
>
&lt;
</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"
}`}
>
&gt;
</button>
</div>
)}
</div>
);
}
+67 -18
View File
@@ -1,29 +1,31 @@
import React, { forwardRef } from "react";
import { Icons } from "../Icons";
export interface InputCompOneProps {
label: string;
labelClass: string;
label?: string;
labelClass?: string;
labelSpan?: string;
labelSpanClass?: string;
floatLabel?: string;
placeholder?: string;
value?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
onInput?: (e: React.FormEvent<HTMLInputElement>) => void;
value?: string | any;
onChange?: (e:any) => any;
onInput?: (e:any) => any;
name: string;
tabIndex?: number;
ref?: React.RefObject<HTMLInputElement>;
selectValue?: string;
input?: boolean;
select?: boolean;
selectOptions?: { value: string; label: string }[];
selectOptions?: {loading:boolean, data:{ [index: string]: string; }[]};
inputType?: string;
inputClass?: string;
parentInputClass?: string;
selectClass?: string;
parentSelectClass?: string;
parentClass?: string;
maxLength?: number;
error?: string;
disabled?: boolean
}
const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
@@ -33,6 +35,7 @@ const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
labelClass,
labelSpan,
labelSpanClass,
floatLabel,
placeholder,
value,
onChange,
@@ -42,29 +45,29 @@ const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
selectValue,
input = false,
select = false,
selectOptions = [],
selectOptions = {loading:false, data:[]},
inputType = "text",
inputClass,
parentInputClass,
selectClass,
parentSelectClass,
parentClass,
maxLength,
error,
disabled=false
},
forwardedRef
) => {
return (
<div className={parentClass}>
{label && (
<label htmlFor="" className={labelClass}>
<label htmlFor={label ? label : floatLabel} className={`flex gap-2 items-center flex-wrap ${labelClass}`}>
{label}
{labelSpan && <span className={labelSpanClass}>{labelSpan}</span>}
{error && <span className='text-[10px] text-red-500'>{error}</span>}
{error && label && <span className='text-[10px] text-red-500'>{error}</span>}
</label>
)}
{input && (
<div className={parentInputClass}>
<div className={`relative ${parentInputClass}`}>
<input
type={inputType}
placeholder={placeholder}
@@ -74,25 +77,71 @@ const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
name={name}
tabIndex={tabIndex}
ref={forwardedRef}
className={inputClass}
className={`px-4 ${floatLabel && 'peer pt-4 placeholder:text-transparent'} ${inputClass}`}
maxLength={maxLength}
id={label ? label : floatLabel}
disabled={disabled}
/>
{floatLabel &&
<label
htmlFor={label ? label : floatLabel}
className={`flex items-center gap-2 cursor-pointer text-sm text-black/70 dark:text-white absolute left-4 top-0 translate-y-0 peer-focus:top-0 peer-focus:translate-y-0 peer-placeholder-shown:top-1/2 peer-placeholder-shown:-translate-y-1/2 transition-all duration-500`}
>
{floatLabel}
{error && floatLabel && !label && <span className='text-[10px] text-red-500'>{error}</span>}
</label>
}
</div>
)}
{select && (
<div className={parentSelectClass}>
<div className={`relative ${parentInputClass}`}>
<select
name={name}
id=""
id={label ? label : floatLabel}
value={selectValue}
className={selectClass}
className={`px-4 appearance-none ${floatLabel && 'peer pt-4'} ${selectClass} ${disabled && 'opacity-50'}`}
onChange={onChange}
disabled={disabled}
>
{selectOptions.map(({ value, label }) => (
{selectOptions.loading ?
<option value=''>Loading...</option>
: selectOptions.data.length && name == 'employer_uid' ?
<>
<option value=''>Please Select</option>
{selectOptions.data.map(({ uid, name }) => (
<option key={uid} value={uid}>
{name}
</option>
))}
</>
: selectOptions.data.length && name != 'employer_uid' ?
selectOptions.data.map(({ value, label }) => (
<option key={value} value={value}>
{label}
</option>
))
:
<option value=''>Not Found</option>
}
{/* {selectOptions.map(({ value, label }) => (
<option key={value} value={value}>
{label}
</option>
))}
))} */}
</select>
{floatLabel &&
<label
htmlFor={label ? label : floatLabel}
className={`flex items-center gap-2 cursor-pointer text-sm text-black/70 dark:text-white absolute left-4 top-0 translate-y-0 peer-focus:top-0 peer-focus:translate-y-0 transition-all duration-500`}
>
{floatLabel}
{error && floatLabel && !label && <span className='text-[10px] text-red-500'>{error}</span>}
</label>
}
{/* select custon arrow */}
<div className='absolute right-4 top-1/2 -translate-y-1/2'>
<Icons name='arrow-down' />
</div>
</div>
)}
</div>
+1 -1
View File
@@ -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
+51
View File
@@ -0,0 +1,51 @@
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)
}
// FUNCTION TO GET LIST OF EMPLOYERS
export const getEmployersList = () => {
let reqData = {
// customer_uid: localStorage.getItem('uid'),
}
return getAuxEnd(`/employers`, reqData)
}
+81
View File
@@ -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
);
});
}
+27
View File
@@ -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
}[];
+81 -39
View File
@@ -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:[
+54 -4
View File
@@ -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>
+1 -1
View File
@@ -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">
+18
View File
@@ -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
View File
@@ -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>
);
+20
View File
@@ -0,0 +1,20 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
userDetails: {},
};
export const userSlice = createSlice({
name: "userDetails",
initialState,
reducers: {
updateUserDetails: (state, action) => {
state.userDetails = { ...action.payload };
},
},
});
// Action creators are generated for each case reducer function
export const { updateUserDetails } = userSlice.actions;
export default userSlice.reducer;
+9
View File
@@ -0,0 +1,9 @@
import { configureStore } from "@reduxjs/toolkit";
import userDetailReducer from "./UserDetails";
export default configureStore({
reducer: {
userDetails: userDetailReducer,
},
});
+291 -286
View File
@@ -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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} ELECTRONIC CHANNELS`, linkPath: '/e-channels' },
{ name: 'AGENT BANKING', linkPath: '/agent-banking' },
{
name: "FCMB SECURE COMMUNICATION",
linkPath: "/secure-communication",
name: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} ONLINE`, linkPath: '/fcmb-online-business' },
{
name: "FCMB ELECTRONIC CHANNELS",
linkPath: "https://www.fcmb.com/e-channels",
name: `${import.meta.env.VITE_BANK_NAME_SHORT} ELECTRONIC CHANNELS`,
linkPath: 'https://www.fcmb.com/e-channels',
},
{ name: "FCMB BUSINESS APP", linkPath: "/FCMB-business-app" },
{ name: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} CAPITAL MARKETS`,
linkPath: 'https://www.fcmbcapitalmarketsng.com/',
},
{
name: "FCMB ASSET MANAGEMENT",
linkPath: "https://www.fcmbassetmanagement.com/index/",
name: `${import.meta.env.VITE_BANK_NAME_SHORT} ASSET MANAGEMENT`,
linkPath: 'https://www.fcmbassetmanagement.com/index/',
},
{
name: "FCMB MICROFINANCE BANK",
linkPath: "/fcmb-microfinance-initiative",
name: `${import.meta.env.VITE_BANK_NAME_SHORT} MICROFINANCE BANK`,
linkPath: '/fcmb-microfinance-initiative',
},
{ name: "FCMB UK", linkPath: "http://www.fcmbuk.com/" },
{ name: `${import.meta.env.VITE_BANK_NAME_SHORT} UK`, linkPath: 'http://www.fcmbuk.com/' },
{
name: "FCMB PENSIONS LIMITED",
linkPath: "https://www.fcmbpensions.com/",
name: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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 ${import.meta.env.VITE_BANK_NAME_SHORT}`,
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: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} CAPITAL MARKETS`,
href: 'https://www.fcmbcapitalmarketsng.com/',
},
{
text: "FCMB ASSET MANAGEMENT",
href: "https://www.fcmbassetmanagement.com/index/",
text: `${import.meta.env.VITE_BANK_NAME_SHORT} 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: `${import.meta.env.VITE_BANK_NAME_SHORT} MICROFINANCE BANK`, href: '/fcmb-microfinance-initiative' },
{ text: `${import.meta.env.VITE_BANK_NAME_SHORT} UK`, href: 'http://www.fcmbuk.com/' },
{ text: `${import.meta.env.VITE_BANK_NAME_SHORT} PENSIONS LIMITED`, href: 'https://www.fcmbpensions.com/' },
{ text: 'CREDIT DIRECT LIMITED', href: 'https://www.creditdirect.ng' },
{ text: `${import.meta.env.VITE_BANK_NAME_SHORT} 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 },
];