Compare commits

...

72 Commits

Author SHA1 Message Date
victorAnumudu 0207bf631a started input validation on forms 2024-04-23 19:25:50 +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
victorAnumudu 747c945659 get started first step added 2024-04-22 09:36:48 +01:00
ameye 94f9803ec5 Merge branch 'otp-input' of DigiFi/digifi-www into master 2024-04-17 18:49:10 +00:00
victorAnumudu 3998596fba validation bug fix 2024-04-16 20:56:34 +01:00
victorAnumudu 886fd64347 validated otp input to be numbers 2024-04-16 20:17:57 +01:00
tokslaw f95fd66c57 Merge branch 'layout-update' of DigiFi/digifi-www into master 2024-04-04 09:35:17 +00:00
tokslaw 98b5d4bc4f Merge branch 'Corporate' of DigiFi/digifi-www into master 2024-04-04 09:33:45 +00:00
victorAnumudu fd2b2245f5 updated layout style 2024-04-03 17:58:45 +01:00
victorAnumudu a7e97e1890 updated layout style 2024-04-03 17:55:55 +01:00
Pascallina Ocheme 537d609117 Modified pathlink 2024-03-26 12:17:15 +01:00
tokslaw 5e0d21b5dd Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-25 12:09:09 +00:00
chukwumdiebube ojinta ea4e6b7a59 Added new pages to dashboard 2024-03-23 17:03:13 +01:00
ameye 07f7a90c0d Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-23 10:58:39 +00:00
chukwumdiebube ojinta 2a2b8ee85d changed check prop to defaultChecked 2024-03-23 06:27:16 +01:00
chukwumdiebube ojinta e2b3978ab6 Added Applicants Attestation Page 2024-03-23 06:23:50 +01:00
chukwumdiebube ojinta b8f9958517 Fixed build error 2024-03-23 05:28:00 +01:00
chukwumdiebube ojinta 06cadbb742 Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-www into first-homepage-layout 2024-03-23 05:24:26 +01:00
chukwumdiebube ojinta 067e7a395d Fix build 2024-03-23 05:23:53 +01:00
tokslaw 5b6695c1f6 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-22 22:33:05 +00:00
chukwumdiebube ojinta 911c67e874 Completed layout for Loan Amount 2024-03-22 23:27:58 +01:00
ameye a33784fc9e Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-22 21:39:18 +00:00
chukwumdiebube ojinta b3efba09d6 fixed build and added updates to loan amount component 2024-03-22 22:35:11 +01:00
tokslaw ff03282310 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-22 21:20:41 +00:00
Ebube 05dfb50f62 You're added comp 2024-03-22 18:27:50 +01:00
Ebube 08af493d65 Added You're almost done page 2024-03-22 18:16:18 +01:00
Ebube e1bd0293f1 Added You are almost there comp 2024-03-22 17:19:58 +01:00
ameye a5b77abc92 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-21 10:33:44 +00:00
Ebube dd6d92654c Fixed Layout and switch functionality 2024-03-21 11:29:38 +01:00
Ebube dd9652fe58 Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-www into first-homepage-layout 2024-03-21 10:06:08 +01:00
Ebube 266627d941 Corrected Form Layout 2024-03-21 10:05:44 +01:00
ameye c4ffd49509 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-20 17:49:40 +00:00
Ebube 21b4bf5e8f Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-www into first-homepage-layout 2024-03-20 18:19:10 +01:00
Ebube b71490aa8a fixed footer link 2024-03-20 18:18:39 +01:00
tokslaw be9672991e Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-20 13:33:20 +00:00
Ebube 97e6951685 added Enter Btn 2024-03-20 14:00:17 +01:00
Ebube 1bd523c493 added valid types 2024-03-20 13:37:49 +01:00
Ebube 32f2a358b2 Added social links to env and added hero text to the pages 2024-03-20 13:12:08 +01:00
tokslaw ee94a59f75 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-20 03:49:03 +00:00
Ebube 4c24ce5903 Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-www into first-homepage-layout 2024-03-20 01:38:28 +01:00
Ebube 86c0a236fe Added personal image to the pages 2024-03-20 01:37:31 +01:00
ameye 2daae9b0e0 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-19 12:35:47 +00:00
Ebube 2890677472 fix build error 2024-03-19 13:33:33 +01:00
Ebube 4a3f46c19b added otp to letsGetStarted 2024-03-19 13:11:21 +01:00
Ebube 79f5af7692 Added layout to lets get started bvn 2024-03-19 09:04:49 +01:00
ameye 2a59165054 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-18 17:21:25 +00:00
Ebube e3cf881e09 fix build error 2024-03-18 17:49:55 +01:00
Ebube dde4072593 added pages for top header nav links 2024-03-18 17:42:36 +01:00
Ebube df6fe828e3 added Terms and Condition Page 2024-03-18 17:23:04 +01:00
Ebube db08d1201c complete footer and home layout page created 2024-03-18 15:52:12 +01:00
ameye 32acf978c3 Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-18 11:32:51 +00:00
Ebube f7ef9ff3a0 fix for production build 2024-03-18 12:31:17 +01:00
ameye 37c012461f Merge branch 'first-homepage-layout' of DigiFi/digifi-www into master 2024-03-18 10:08:29 +00:00
Ebube 0a295cc81c Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-www into first-homepage-layout 2024-03-18 11:01:37 +01:00
Ebube e5c605560b Added footer and input component 2024-03-18 11:01:05 +01:00
ameye 26b95bab3d Merge branch 'dashboard-home-reponsive' of DigiFi/digifi-www into master 2024-03-18 09:43:27 +00:00
victorAnumudu cbbd23fde3 made dashboard home page reponsive 2024-03-18 10:39:54 +01:00
tokslaw 18c1a78d4c Merge branch 'aside-menu-bug' of DigiFi/digifi-www into master 2024-03-18 04:51:08 +00:00
victorAnumudu 979330478c made aside bar to close on mobile view whenever a link is clicked 2024-03-18 01:32:52 +01:00
Ebube f402efeb85 Merge branch 'master' of https://gitlab.chiefsoft.net/DigiFi/digifi-www into first-homepage-layout 2024-03-17 20:08:16 +01:00
Ebube 38becd42ac . 2024-03-17 20:04:31 +01:00
ameye bf87780204 Merge branch 'dashboard-home-page' of DigiFi/digifi-www into master 2024-03-16 18:36:09 +00:00
victorAnumudu 81b2f439ce added some component to dashboard home page 2024-03-16 17:47:17 +01:00
ameye 9d86fc51c8 Merge branch 'dashboard-variables' of DigiFi/digifi-www into master 2024-03-16 13:04:12 +00:00
victorAnumudu 435bc08f2f removed unused variables 2024-03-16 14:01:02 +01:00
ameye 197d5f32ed Merge branch 'dashboard-component' of DigiFi/digifi-www into master 2024-03-16 10:09:36 +00:00
victorAnumudu eaf959ab84 merged branch 2024-03-16 03:09:41 +01:00
victorAnumudu 7cbfae619b added dashboard layout 2024-03-16 02:53:40 +01:00
101 changed files with 4765 additions and 110 deletions
+5
View File
@@ -1 +1,6 @@
DIGIFI_PORT=5173
# Social Links
FACEBOOK_URL=https://www.facebook.com
TWITTER_URL=https://twitter.com
INSTAGRAM_URL=https://www.instagram.com
+5
View File
@@ -1 +1,6 @@
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
+5
View File
@@ -1 +1,6 @@
DIGIFI_PORT=5173
# Social Links
FACEBOOK_URL=https://www.facebook.com
TWITTER_URL=https://twitter.com
INSTAGRAM_URL=https://www.instagram.com
+1
View File
@@ -15,6 +15,7 @@
"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",
+29 -2
View File
@@ -1,5 +1,5 @@
.btn-primary {
background: #5A2C82;
background: #5A2C82 !important;
color: #FFFFFF;
display: block;
text-decoration: none;
@@ -8,7 +8,34 @@
}
.btn-active {
background: #D10056;
background: #D10056 !important;
}
.btn-R {
padding-inline: 3rem !important;
font-weight: bold !important;
font-size: 16px !important;
background-color: #5A2C82;
}
.btn-W {
background: white !important;
border-radius: 8px;
font-size: 18px;
font-weight: bold;
color: #FBB700;
line-height: 25px;
align-items: center !important;
}
.btn-Y {
background: #FBB700 !important;
border-radius: 8px;
font-size: 18px;
font-weight: bold;
/* color: white; */
line-height: 25px;
align-items: center !important;
}
.sidebar {
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px"><g fill="#ffffff" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M32,11h5c0.552,0 1,-0.448 1,-1v-6.737c0,-0.524 -0.403,-0.96 -0.925,-0.997c-1.591,-0.113 -4.699,-0.266 -6.934,-0.266c-6.141,0 -10.141,3.68 -10.141,10.368v6.632h-7c-0.552,0 -1,0.448 -1,1v7c0,0.552 0.448,1 1,1h7v19c0,0.552 0.448,1 1,1h7c0.552,0 1,-0.448 1,-1v-19h7.222c0.51,0 0.938,-0.383 0.994,-0.89l0.778,-7c0.066,-0.592 -0.398,-1.11 -0.994,-1.11h-8v-5c0,-1.657 1.343,-3 3,-3z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 856 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="64px" height="64px"><g fill="#ffffff" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(4,4)"><path d="M21.58008,7c-8.039,0 -14.58008,6.54494 -14.58008,14.58594v20.83203c0,8.04 6.54494,14.58203 14.58594,14.58203h20.83203c8.04,0 14.58203,-6.54494 14.58203,-14.58594v-20.83398c0,-8.039 -6.54494,-14.58008 -14.58594,-14.58008zM47,15c1.104,0 2,0.896 2,2c0,1.104 -0.896,2 -2,2c-1.104,0 -2,-0.896 -2,-2c0,-1.104 0.896,-2 2,-2zM32,19c7.17,0 13,5.83 13,13c0,7.17 -5.831,13 -13,13c-7.17,0 -13,-5.831 -13,-13c0,-7.169 5.83,-13 13,-13zM32,23c-4.971,0 -9,4.029 -9,9c0,4.971 4.029,9 9,9c4.971,0 9,-4.029 9,-9c0,-4.971 -4.029,-9 -9,-9z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 993 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px"><g fill="#ffffff" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M41,4h-32c-2.76,0 -5,2.24 -5,5v32c0,2.76 2.24,5 5,5h32c2.76,0 5,-2.24 5,-5v-32c0,-2.76 -2.24,-5 -5,-5zM17,20v19h-6v-19zM11,14.47c0,-1.4 1.2,-2.47 3,-2.47c1.8,0 2.93,1.07 3,2.47c0,1.4 -1.12,2.53 -3,2.53c-1.8,0 -3,-1.13 -3,-2.53zM39,39h-6c0,0 0,-9.26 0,-10c0,-2 -1,-4 -3.5,-4.04h-0.08c-2.42,0 -3.42,2.06 -3.42,4.04c0,0.91 0,10 0,10h-6v-19h6v2.56c0,0 1.93,-2.56 5.81,-2.56c3.97,0 7.19,2.73 7.19,8.26z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 878 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px"><g fill="#ffffff" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M6.91992,6l14.2168,20.72656l-14.9082,17.27344h3.17773l13.13867,-15.22266l10.44141,15.22266h10.01367l-14.87695,-21.6875l14.08008,-16.3125h-3.17578l-12.31055,14.26172l-9.7832,-14.26172z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 664 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px"><g fill="#ffffff" fill-rule="nonzero" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M25,2c-12.682,0 -23,10.318 -23,23c0,3.96 1.023,7.854 2.963,11.29l-2.926,10.44c-0.096,0.343 -0.003,0.711 0.245,0.966c0.191,0.197 0.451,0.304 0.718,0.304c0.08,0 0.161,-0.01 0.24,-0.029l10.896,-2.699c3.327,1.786 7.074,2.728 10.864,2.728c12.682,0 23,-10.318 23,-23c0,-12.682 -10.318,-23 -23,-23zM36.57,33.116c-0.492,1.362 -2.852,2.605 -3.986,2.772c-1.018,0.149 -2.306,0.213 -3.72,-0.231c-0.857,-0.27 -1.957,-0.628 -3.366,-1.229c-5.923,-2.526 -9.791,-8.415 -10.087,-8.804c-0.295,-0.389 -2.411,-3.161 -2.411,-6.03c0,-2.869 1.525,-4.28 2.067,-4.864c0.542,-0.584 1.181,-0.73 1.575,-0.73c0.394,0 0.787,0.005 1.132,0.021c0.363,0.018 0.85,-0.137 1.329,1.001c0.492,1.168 1.673,4.037 1.819,4.33c0.148,0.292 0.246,0.633 0.05,1.022c-0.196,0.389 -0.294,0.632 -0.59,0.973c-0.296,0.341 -0.62,0.76 -0.886,1.022c-0.296,0.291 -0.603,0.606 -0.259,1.19c0.344,0.584 1.529,2.493 3.285,4.039c2.255,1.986 4.158,2.602 4.748,2.894c0.59,0.292 0.935,0.243 1.279,-0.146c0.344,-0.39 1.476,-1.703 1.869,-2.286c0.393,-0.583 0.787,-0.487 1.329,-0.292c0.542,0.194 3.445,1.604 4.035,1.896c0.59,0.292 0.984,0.438 1.132,0.681c0.148,0.242 0.148,1.41 -0.344,2.771z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,256,256" width="50px" height="50px"><g fill="#ffffff" fill-rule="evenodd" stroke="none" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" font-family="none" font-weight="none" font-size="none" text-anchor="none" style="mix-blend-mode: normal"><g transform="scale(5.12,5.12)"><path d="M13,5l3,9v6h2v-6l3,-9h-2l-2,6l-2,-6zM24,9c-1.06641,0 -1.58984,0.16797 -2.24219,0.70313c-0.625,0.52734 -0.79687,0.93359 -0.75781,2.29688v5c0,0.99609 0.16406,1.65234 0.76563,2.23438c0.625,0.58203 1.21484,0.76563 2.23438,0.76563c1.06641,0 1.64844,-0.18359 2.25,-0.76562c0.625,-0.55859 0.75,-1.23828 0.75,-2.23437v-5c0,-0.88281 -0.15625,-1.71875 -0.76172,-2.27734c-0.625,-0.57422 -1.26953,-0.72266 -2.23828,-0.72266zM29,9v9c0,0.97266 0.98047,2 2,2c1.01953,0 1.55859,-0.51172 2,-1v1h2v-11h-2v8c-0.01172,0.68359 -0.81641,1 -1,1c-0.20703,0 -1,-0.04297 -1,-1v-8zM24,11c0.30078,0 1,-0.00391 1,1v5c0,0.96875 -0.67578,1 -1,1c-0.30078,0 -1,-0.01172 -1,-1v-5c0,-0.81641 0.43359,-1 1,-1zM10,22c-3.59375,0 -6,2.38281 -6,6v9.5c0,3.61719 2.40625,6.5 6,6.5h30c3.59375,0 6,-2.38281 6,-6v-10c0,-3.61719 -2.40625,-6 -6,-6zM12,26h6v2h-2v12h-2v-12h-2zM26,26h2v4c0.23047,-0.35937 0.57422,-0.64453 0.90234,-0.80469c0.32031,-0.16406 0.64453,-0.25781 0.97266,-0.25781c0.64844,0 1.15625,0.23438 1.50391,0.67188c0.34766,0.44141 0.62109,1.02734 0.62109,1.89063v6c0,0.74219 -0.25,1.20313 -0.57812,1.59766c-0.32031,0.39453 -0.80078,0.89453 -1.42187,0.90234c-1.05078,0.01172 -1.61328,-0.55078 -2,-1v1h-2zM18,29h2v8c0,0.23047 0.26953,1.00781 1,1c0.8125,-0.00781 0.82031,-0.76562 1,-1v-8h2v11h-2v-1c-0.37109,0.4375 -0.5625,0.57422 -0.98047,0.78125c-0.41406,0.23438 -0.83594,0.21875 -1.22656,0.21875c-0.48437,0 -1.03516,-0.4375 -1.29297,-0.76562c-0.23047,-0.30078 -0.5,-0.60937 -0.5,-1.23437zM36.19922,29c0.94922,0 1.61719,0.20313 2.12109,0.73438c0.51563,0.53125 0.67969,1.15234 0.67969,2.15234v3.11328h-4v1.54688c0,0.55859 0.07422,0.91406 0.21875,1.125c0.13672,0.23047 0.41406,0.33203 0.78125,0.32813c0.40625,-0.00391 0.66406,-0.08594 0.80078,-0.26953c0.14063,-0.16406 0.19922,-0.62891 0.19922,-1.23047v-0.5h2v0.59375c0,1.08984 -0.08594,1.90234 -0.625,2.43359c-0.50781,0.55859 -1.30078,0.81641 -2.33984,0.81641c-0.94922,0 -1.69141,-0.28125 -2.22266,-0.85937c-0.53125,-0.57812 -0.80859,-1.37109 -0.80859,-2.39062v-4.70703c0,-0.90625 0.31641,-1.57812 0.89844,-2.17578c0.46875,-0.48047 1.34766,-0.71094 2.29688,-0.71094zM29,30.5c-0.55078,0 -0.99219,0.49609 -1,1v6c0.00781,0.28906 0.44922,0.5 1,0.5c0.55078,0 1,-0.42578 1,-0.97656v-5.02344c0,-1 -0.44922,-1.5 -1,-1.5zM36,31c-0.55078,0 -0.99219,0.46484 -1,1v1h2v-1c0,-0.61328 -0.44922,-1 -1,-1z"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

+42
View File
@@ -0,0 +1,42 @@
import { Icons } from "../"
type Props = {
title?: string,
descText?: string,
iconName?: string,
iconColor?: string,
cardClass?: string,
titleClass?: string,
descTextClass?: string,
onClick?: ()=>any
}
export default function DefaultCard({
title,
descText,
iconName,
iconColor,
cardClass,
titleClass,
descTextClass,
onClick
}:Props) {
return (
<button
className={`h-full w-full rounded-lg p-5 shadow-lg hover:shadow-none bg-no-repeat bg-[90%] flex justify-between gap-4 items-center transition-all duration-300 ${cardClass && cardClass}`}
onClick={onClick}
>
<div className='w-3/4'>
<h1 className={`mb-1 text-[#FFF] text-lg text-left font-bold ${titleClass && titleClass}`}>{title}</h1>
<p className={`text-sm text-left ${descTextClass && descTextClass}`}>{descText}</p>
</div>
{iconName && // DISPLAYS ICON IF THERE IS ICON NAME PRESENT
<div className='group-hover:-translate-x-2 transition-all duration-300'>
<Icons name={iconName} fillColor={`${iconColor ? iconColor : '#FFF'}`} />
</div>
}
</button>
)
}
+3
View File
@@ -0,0 +1,3 @@
import DefaultCard from "./DefaultCard";
export { DefaultCard };
@@ -0,0 +1,118 @@
import { Button, InputCompOne, Stepper } from "..";
import {Formik, Form} from 'formik'
import * as Yup from "yup";
type Props = {
handleNextStep:()=>any
}
const initialValues = {
amount: "",
duration: "",
id: "",
};
// To get the validation schema
const validationSchema = Yup.object().shape({
duration: Yup.string()
.required("Required"),
amount: Yup.string()
.required("Required")
.test("no-e", "Invalid", (value:any) => {
if (value && /^[0-9]*$/.test(value) == false) {
return false;
}
return true;
}),
id: Yup.string()
.required("Required")
});
export default function DashboardFormInit({handleNextStep}:Props) {
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
console.log(values)
handleNextStep()
};
return (
<div className="w-full">
<div className="w-full flex justify-center">
<Stepper step={0} />
</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="amount"
label="How Much Do You Want To Apply For?"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
placeholder="350,000"
value={props.values.amount}
onChange={props.handleChange}
error={(props.errors.amount && props.touched.amount) ? props.errors.amount : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="duration"
label="For How Many Months?"
labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={duration}
selectValue={props.values.duration}
onChange={props.handleChange}
error={(props.errors.duration && props.touched.duration) ? props.errors.duration : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="id"
label="Direct sales agent ID ( Optional )"
labelClass="font-bold text-[1.125rem]"
floatLabel='Enter agent ID'
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Agent ID"
value={props.values.id}
onChange={props.handleChange}
error={(props.errors.id && props.touched.id) ? props.errors.id : ''}
/>
<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 duration: 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" },
]
}
@@ -0,0 +1,33 @@
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 handleNextStep = () => {
if (step < 7) {
setStep(step + 1);
}
};
return (
<div className="w-full">
{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} />}
{step === 7 && <DashboardHomeIntro step={step} handleNextStep={handleNextStep} />}
</div>
);
};
export default DashboardHome;
@@ -0,0 +1,177 @@
import React, { FC } from "react";
import NairaBag from "../../assets/images/dashboard/naira-bag.png";
import { Button } from "../";
export interface DashBoardCardProps {
title?: string;
desc?: string;
descSpan?: string;
descSpanClass?: string;
onClick?: any;
cardClass?: string;
titleClass?: string;
descClass?: string;
btnTitle?: string;
btnTextClass?: string;
image?: any;
imgClass?: string;
}
export const DashBoardCard: React.FC<DashBoardCardProps> = ({
title,
desc,
onClick,
cardClass,
titleClass,
descClass,
descSpan,
descSpanClass,
btnTitle,
btnTextClass,
image,
imgClass,
}) => {
return (
<div
className={`h-full w-full rounded-lg p-5 shadow-lg hover:shadow-none bg-no-repeat bg-[90%] flex justify-between gap-4 items-center transition-all duration-300 ${
cardClass && cardClass
}`}
// onClick={onClick}
>
<div className="w-3/4 flex flex-col gap-[2.3125rem]">
{title && (
<h1
className={`mb-1 text-[#FFF] text-lg text-left font-bold ${
titleClass && titleClass
}`}
>
{title}
</h1>
)}
{desc && (
<p className={`text-lg text-left ${descClass && descClass}`}>
{desc}{" "}
{descSpan && (
<span className={`${descSpanClass && descSpanClass}`}>
{descSpan}
</span>
)}
</p>
)}
{btnTitle && (
<Button className={btnTextClass} text={btnTitle} onClick={onClick} />
)}
</div>
{image && <img className={imgClass} src={image} alt="card-image" />}
</div>
);
};
interface DashboardHomeIntroProps {
handleNextStep: any;
step?:number|string
}
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({ handleNextStep, step }) => {
return (
<>
{step == 1 ?
<>
<h1 className="font-bold my-5 text-2xl">Hello, Olanrewaju</h1>
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
<DashBoardCard
cardClass="bg-[#5C2684] relative"
desc="Begin your application and get up to "
descSpan="5 million naira loan."
descClass="leading-[1.5625rem] text-lg text-white"
descSpanClass="font-bold"
btnTitle="Apply here"
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
image={NairaBag}
imgClass="translate-y-4 -rotate-6"
onClick={handleNextStep}
/>
</div>
</>
:
<>
<h1 className="font-bold my-5 text-2xl">Welcome Back, Olanrewaju</h1>
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
<DashBoardCard
cardClass="bg-[#5C2684] relative"
desc="Your loan application has been reviewed and accepted, please confirm for disbursement."
// descSpan="5 million naira loan."
descClass="leading-[1.5625rem] text-lg text-white"
// descSpanClass="font-bold"
btnTitle="View and accept"
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
image={NairaBag}
imgClass="translate-y-4 -rotate-6"
// onClick={handleNextStep}
/>
</div>
</>
}
</>
);
};
export default DashboardHomeIntro;
// {/* <div className="group w-full lg:w-96 h-32">
// <DefaultCard
// descText="You currently do not have any open application. Click on apply for a loan to get started."
// iconName="arrow"
// iconColor="#FBB700"
// cardClass={`p-4 bg-[#FFFAFA] border border-[#EE4040]`}
// descTextClass="text-[#423131] leading-5"
// onClick={() => {
// console.log("working");
// }}
// />
// </div> */}
// {/* <div className="w-full mt-20 flex gap-16 flex-wrap">
// <div className="group h-40 w-full lg:w-80">
// <DefaultCard
// title="Apply for a loan"
// descText="You currently do not have any open application. Click on apply for a loan to get started."
// iconName="greater-than"
// iconColor="#FFF"
// cardClass={`bg-[#5C2684] bg-[url('../../../src/assets/images/dashboard/card_bg.png')]`}
// titleClass="text-[#FFF]"
// descTextClass="text-[#EFEFEF] leading-5"
// onClick={() => {
// console.log("working");
// }}
// />
// </div>
// <div className="group h-40 w-full lg:w-80">
// <DefaultCard
// title="Loan history"
// descText="You currently do not have any open application. Click on apply for a loan to get started."
// iconName="greater-than"
// iconColor="#FFF"
// cardClass={`bg-[#635D4D] bg-[url('../../../src/assets/images/dashboard/card_bg.png')]`}
// titleClass="text-[#FFF]"
// descTextClass="text-[#EFEFEF] leading-5"
// onClick={() => {
// console.log("working");
// }}
// />
// </div>
// <div className="group h-40 w-full lg:w-80">
// <DefaultCard
// title="How it works?"
// descText="Steps to follow to complete your loan application successfully."
// iconName="greater-than"
// iconColor="#FFF"
// cardClass={`bg-[#635D4D] bg-[url('../../../src/assets/images/dashboard/card_bg.png')]`}
// titleClass="text-[#FFF]"
// descTextClass="text-[#EFEFEF] leading-5"
// onClick={() => {
// console.log("working");
// }}
// />
// </div>
// </div> */}
@@ -0,0 +1,72 @@
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='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="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="Full name"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
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"
name="applyIshInput"
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"
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="applyIshInput"
label="Select your state"
labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Lagos"
/>
<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,89 @@
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
// import { useNavigate } from "react-router-dom";
// import { RouteHandler } from '../../../router/routes';
type Props = {
handleNextStep:()=>any
}
const initialValues = {
account_number: "",
checked: false
};
// To get the validation schema
const validationSchema = Yup.object().shape({
account_number: Yup.string()
.required("Required"),
checked: Yup.bool() // use bool instead of boolean
.oneOf([true], "You must accept the terms and conditions")
});
export default function DashboardHomeAttestation({handleNextStep}:Props) {
// let navigate = useNavigate();
// const navigateToProfile = () => navigate(RouteHandler.dashboardProfile);
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
console.log(values)
handleNextStep()
};
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 FCMB 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_number"
floatLabel="Disbursement account number"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="0102547896"
value={props.values.account_number}
onChange={props.handleChange}
error={(props.errors.account_number && props.touched.account_number) ? props.errors.account_number : ''}
/>
</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 FCMB
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>
);
}
@@ -0,0 +1,166 @@
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
type Props = {
handleNextStep:()=>any
}
const initialValues = {
gender: "",
address: "",
marital_status: "",
state: "",
email:""
};
// 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"),
});
export default function DashboardHomeDetail({handleNextStep}:Props) {
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
console.log(values)
handleNextStep()
};
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>
<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 : ''}
/>
<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" },
]
}
@@ -0,0 +1,275 @@
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
type Props = {
handleNextStep:()=>any
}
const initialValues = {
job_title: "",
employer_name: "",
job_sector: "",
industry: "",
date_of_resumption: "",
employer_email:"",
annual_income: "",
monthly_salary: "",
salary_payment_date: "",
employee_id: "",
qualification: ""
};
// To get the validation schema
const validationSchema = Yup.object().shape({
job_title: Yup.string()
.required("Required"),
employer_name: Yup.string()
.required("Required"),
job_sector: Yup.string()
.required("Required"),
industry: 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"),
qualification: Yup.string()
.required("Required"),
});
export default function DashboardHomeEmploymentInfo({handleNextStep}:Props) {
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
console.log(values)
handleNextStep()
};
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 items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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="max-w-[25.875rem] w-full flex flex-col gap-4"
name="employer_name"
floatLabel="Employer name"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="Mr. Mark John"
value={props.values.employer_name}
onChange={props.handleChange}
error={(props.errors.employer_name && props.touched.employer_name) ? props.errors.employer_name : ''}
/>
</div>
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="job_sector"
floatLabel="Job Sector"
// labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={jobSector}
selectValue={props.values.job_sector}
onChange={props.handleChange}
error={(props.errors.job_sector && props.touched.job_sector) ? props.errors.job_sector : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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 : ''}
/>
</div>
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="date_of_resumption"
floatLabel="Date of resumption"
// labelClass="font-bold text-[1.125rem]"
input
inputType='date'
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="12/12/2015"
value={props.values.date_of_resumption}
onChange={props.handleChange}
error={(props.errors.date_of_resumption && props.touched.date_of_resumption) ? props.errors.date_of_resumption : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="employer_email"
floatLabel="Employers official email"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="example@gmail.com"
value={props.values.employer_email}
onChange={props.handleChange}
error={(props.errors.employer_email && props.touched.employer_email) ? props.errors.employer_email : ''}
/>
</div>
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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="max-w-[25.875rem] w-full flex flex-col gap-4"
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>
<div className="flex items-center gap-[4.125rem]">
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
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 : ''}
/>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="employee_id"
floatLabel="Employee ID"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="LS/001/005"
value={props.values.employee_id}
onChange={props.handleChange}
error={(props.errors.employee_id && props.touched.employee_id) ? props.errors.employee_id : ''}
/>
</div>
<InputCompOne
parentClass="max-w-[25.875rem] w-full flex flex-col gap-4"
name="qualification"
floatLabel="Highest level of education"
// labelClass="font-bold text-[1.125rem]"
select={true}
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
selectOptions={qualification}
selectValue={props.values.qualification}
onChange={props.handleChange}
error={(props.errors.qualification && props.touched.qualification) ? props.errors.qualification : ''}
/>
<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 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 qualification: SelectOption = {
loading: false,
data: [
{ value: "", label: "Please Select" },
{ value: "b.sc + professional qualification", label: "B.Sc + Professional Qualification" },
]
}
@@ -0,0 +1,215 @@
import { Button, InputCompOne, Stepper } from '../../shared/index';
import {Formik, Form} from 'formik'
import * as Yup from "yup";
type Props = {
handleNextStep:()=>any
}
const initialValues = {
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({
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("Required"),
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("Required"),
});
export default function DashboardHomeRefereeInfo({handleNextStep}:Props) {
//FUNCTION TO HANDLE SUBMIT
const handleSubmit = (values:any) => {
console.log(values)
handleNextStep()
};
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_number"
floatLabel="Phone number"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="07000000000"
value={props.values.ref_number}
onChange={props.handleChange}
error={(props.errors.ref_number && props.touched.ref_number) ? props.errors.ref_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_number"
floatLabel="Phone number"
// labelClass="font-bold text-[1.125rem]"
input
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
placeholder="07000000000"
value={props.values.ref_two_number}
onChange={props.handleChange}
error={(props.errors.ref_two_number && props.touched.ref_two_number) ? props.errors.ref_two_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>
);
}
+4
View File
@@ -0,0 +1,4 @@
import DashboardHome from './DashboardHome'
import DashboardProfile from './DashboardProfile';
export { DashboardHome, DashboardProfile };
+69
View File
@@ -0,0 +1,69 @@
import { footerCustomerLinks, footerSocialLinks } from "../../utils/data";
interface FooterLinksProps {
href: string;
icon?: string;
text?: string;
}
const BottomFooterOne = () => {
const date: number = new Date().getFullYear();
return (
<footer className="pt-[1.25rem] pb-[1.875rem]">
<div className="containerMode flex flex-col gap-2 w-full">
<div className="flex flex-wrap flex-[100] justify-between w-full gap-2">
<SocialIconButtons />
<CustomerLinks />
</div>
<p className="text-[.8125rem] text-[#333] leading-[1.42857]">
© <span>{date}</span> First City Monument Bank (Licensed by the
Central Bank of Nigeria)
</p>
</div>
</footer>
);
};
export default BottomFooterOne;
const SocialIconButtons = () => {
const icons = footerSocialLinks.map(
({ href, icon }: FooterLinksProps, idx: number) => (
<li key={idx}>
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="bg-[#592B81] py-[.3125rem] px-[.625rem] text-white w-[2.625rem] h-[2.625rem] flex items-center justify-center rounded-[3.125rem]"
>
{icon && <img src={icon} alt="icon" />}
</a>
</li>
)
);
return <ul className="flex flex-[33.333] items-center gap-1">{icons}</ul>;
};
const CustomerLinks = () => {
const links = footerCustomerLinks.map(
({ href, text }: FooterLinksProps, idx: number) => (
<li key={idx} className="list-none">
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="py-[.75rem] text-[.8125rem] uppercase text-[#606161] flex items-center justify-center"
>
{text}
</a>
</li>
)
);
return (
<div className="flex-[66.667] flex items-center flex-nowrap md:flex-wrap gap-2">
{links}
</div>
);
};
+18 -7
View File
@@ -1,22 +1,33 @@
import { Link } from "react-router-dom";
// import { Link } from "react-router-dom";
import { socialsIcons } from "../../utils/data";
export default function Footer() {
const date = new Date().getFullYear();
return (
<div className="w-full h-[5.4375rem] bg-[F7F7F7] flex items-center">
<div className="containerMode flex justify-between items-center flex-wrap gap-2">
<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
</p>
<div className="footer-social-icons flex justify-end items-center gap-2">
{socialsIcons.map((icon, index) => (
<Link key={index} className="w-[1.875rem] h-[1.875rem]" to="#">
<img src={icon.image} alt={icon.name} />
</Link>
))}
{renderSocialLinks()}
</div>
</div>
</div>
);
}
function renderSocialLinks(): JSX.Element {
const link = socialsIcons.map(function (item, index) {
let { name, image, link } = item;
return (
<a href={link} key={index} className="w-[1.875rem] h-[1.875rem]">
<img src={image} alt={name} />
</a>
);
});
return <ul className="flex items-center gap-2">{link}</ul>;
}
+15
View File
@@ -0,0 +1,15 @@
import styles from "./footer.module.css"
const MidFooter = () => {
return (
<div className={`h-[2.3125rem] text-[1.25rem] ${styles.lower_footer}`}>
<div className="containerMode flex justify-end p-[.375rem] w-full text-white font-medium text-[.6875rem] md:text-[1.25rem]">
<div className="flex gap-2 items-center justify-end px-2 text-[11px] md:text-[13px]">
<p className="text-[20px] font-extralight">my bank and I</p>
</div>
</div>
</div>
)
}
export default MidFooter
+35
View File
@@ -0,0 +1,35 @@
import { footerItems } from "../../utils/data";
import TopFooterOneMenu from "./TopFooterOneMenu";
export interface TopFooterOneMenuProps {
category: string;
subItems: {
text: string;
href?: string;
}[];
}
const TopFooterOne = () => {
const footerListItems: TopFooterOneMenuProps[] = footerItems;
return (
<footer className="bg-[#f7f7f7] text-[#898B8B] border border-[#ececec] p-5">
<div className="containerMode w-full flex flex-col gap-[1.875rem]">
<h4 className="uppercase text-[1.3125rem] font-bold my-[.625rem] cursor-default">
sitemap
</h4>
<div className="grid grid-cols-2 md:grid-cols-6 gap-2 md:gap-0">
{footerListItems.map(({ category, subItems }, index) => (
<TopFooterOneMenu
key={`${category}-${index}`}
category={category}
subItems={subItems}
/>
))}
</div>
</div>
</footer>
);
};
export default TopFooterOne;
@@ -0,0 +1,29 @@
import React from "react";
import { Link } from "react-router-dom";
import { TopFooterOneMenuProps } from "./TopFooterOne";
const TopFooterOneMenu: React.FC<TopFooterOneMenuProps> = ({
category,
subItems,
}) => {
return (
<ul className="flex gap-2 flex-col">
<li className="text-[.6875rem] font-bold text-[#5e2785] cursor-default">
{category}
</li>
<ul className="flex flex-col gap-1">
{subItems.map(({ href = "#", text }) => (
<li
key={text}
className="text-[.6875rem] text-[#5e2785] hover:underline w-fit"
>
{href ? <Link to={href}>{text}</Link> : <span>{text}</span>}
</li>
))}
</ul>
</ul>
);
};
export default TopFooterOneMenu;
+8
View File
@@ -0,0 +1,8 @@
.lower_footer{
background: url(../../assets/images/footer_back.jpg) no-repeat;
background-size: cover;
/* padding: 0.4rem 0; */
display: flex;
align-items: center;
justify-content: center;
}
+4 -1
View File
@@ -1,3 +1,6 @@
import Footer from "./Footer";
import TopFooterOne from "./TopFooterOne";
import MidFooter from "./MidFooter";
import BottomFooterOne from "./BottomFooterOne";
export { Footer };
export { Footer, TopFooterOne, MidFooter, BottomFooterOne };
@@ -0,0 +1,28 @@
import React from "react";
import DebitAccount from "./DebitAccount";
const ApplicantsAttestation: React.FC = () => {
return (
<>
<div className="flex justify-between items-center w-full mt-8 mb-[45px]">
<h1 className="font-semibold text-[2.375rem] text-[#5C2684] my-[.5rem] max-w-[34rem]">
Applicants Attestation and Debit Instruction
</h1>
<div className="flex flex-col gap-[.4375rem]">
<p className="font-extrabold tracking-[3%] text-[#FBB700] underline">
For more enquiries and support
</p>
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
Call: 09099000000
</p>
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
Email: fcmbloan@support.com
</p>
</div>
</div>
<DebitAccount />
</>
);
};
export default ApplicantsAttestation;
+89
View File
@@ -0,0 +1,89 @@
import React from "react";
import * as Yup from "yup";
import { Form, Formik } from "formik";
import { InputCompOne } from "../shared";
// 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")
});
// initial values for formik
let initialValues = {
bvn: ''
};
type Props = {
handleNextStep:()=>any
}
const BVN = ({handleNextStep}:Props) => {
const firstInputRef = React.useRef<HTMLInputElement>(null);
const handleSubmit = (values:any) => {
console.log('values', values)
handleNextStep()
};
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(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}
ref={firstInputRef}
maxLength={11}
error={(props.errors.bvn && props.touched.bvn) && props.errors.bvn}
/>
<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"
>
Enter
</button>
<p className="text-[#5C2684] mt-[1.5625rem] max-w-[31.625rem]">
***Every personal information attached to your BVN is safe and secured. It is only inportant for us to verify your information and also give you access to your application profile/account
</p>
</div>
</div>
</div>
</Form>
)}
</Formik>
);
};
export default BVN;
+101
View File
@@ -0,0 +1,101 @@
import React, { useRef, useState } from "react";
import InputDetails from "./IntroDetails";
import OTPSection from "./OtpSection";
import SpouseDetails from "./SpouseDetails";
import { Button } from "..";
// interface Option {
// value: string;
// label: string;
// }
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 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;
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");
}
}
};
return (
<>
{/* Header */}
<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>
</>
);
};
export default BasicInfo;
@@ -0,0 +1,27 @@
import React from "react";
import { InputCompOne } from "..";
const CreditAccount: 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">
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]"
/>
</>
);
};
export default CreditAccount;
@@ -0,0 +1,91 @@
import React from "react";
import {useNavigate} from 'react-router-dom'
import { Button, InputCompOne } from "..";
import { RouteHandler } from "../../router/routes";
const DebitAccount: React.FC = () => {
const navigate = useNavigate()
return (
<>
<div className="w-full rounded py-3 mb-9 bg-[#5C2684] px-5">
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
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]"
/>
<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="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="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>
</>
);
};
export default DebitAccount;
@@ -0,0 +1,99 @@
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;
+45 -10
View File
@@ -1,17 +1,52 @@
import { FC } from "react";
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: "",
});
const GetStarted: FC = () => {
return (
<div className="w-full flex items-center justify-center">
<div className="containerMode">
<h1 className="font-semibold text-[2.375rem] text-[#5C2684] my-[.5rem]">
Lets Get You Started
</h1>
<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>
{/* Main */}
<main>
{step === 2 && (
<BasicInfo
inputValues={inputValues}
setInputValues={setInputValues}
handleNextStep={handleNextStep}
/>
)}
{step === 3 && <YourAreAlmostThere handleNextStep={handleNextStep} />}
{step === 4 && <LoanAmountComp handleNextStep={handleNextStep} />}
{step === 5 && <ApplicantsAttestation />}
</main>
</div>
</div>
);
+140
View File
@@ -0,0 +1,140 @@
import React from "react";
import InputCompOne from "../shared/InputCompOne";
interface SelectOption {
loading: boolean;
data: {value: string;
label: string}[]
}
interface InputSectionProps {
inputValues: {
title: string;
marital: string;
agentId: string;
bvn: string;
};
handleChange: (e: React.FormEvent<HTMLInputElement>) => void;
handleInput: (e: React.FormEvent<HTMLInputElement>) => void;
inputRef: React.RefObject<HTMLInputElement>;
}
const InputSection: React.FC<InputSectionProps> = ({
inputValues,
handleChange,
handleInput,
inputRef,
}) => {
const basicInfoInputFields = [
{
label: "Title",
name: "title",
parentInputClass: "max-w-[224px] w-full",
labelClass:
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]",
select: true,
selectClass: "w-full h-[36px] rounded-[6px]",
selectOptions: titleOptions,
value: inputValues.title,
},
{
label: "Marital Status",
name: "marital",
parentInputClass: "max-w-[224px] w-full",
labelClass:
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]",
select: true,
selectClass: "w-full h-[36px] rounded-[6px]",
selectOptions: maritalStatusOptions,
value: inputValues.marital,
onInput: handleInput,
},
{
label: "Direct Sales Agent ID",
name: "agentId",
parentInputClass: "max-w-[224px] w-full",
labelClass:
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px]",
select: true,
selectClass: "w-full h-[36px] rounded-[6px]",
selectOptions: {loading: false, data:[{ value: "", label: "Select" }]},
value: inputValues.agentId,
onInput: handleInput,
},
{
label: "BVN",
name: "bvn",
parentInputClass: " w-full",
labelSpan: "( To get your BVN, dial *565*0# )",
labelSpanClass: "text-[11px] text-[#7a7373]",
placeholder: "Enter your BVN",
labelClass:
"font-bold text-[18px] leading-[21.78px] tracking-[2%] text-[#5C2684] mb-[2px] gap-[2px]",
input: true,
inputClass: "w-full h-[36px] bg-[#EFEFEF] px-[2px] rounded-[6px]",
value: inputValues.bvn,
onInput: handleInput,
maxLength: 10,
},
];
return (
<>
<div className="w-full rounded py-3 bg-[#5C2684] px-5">
<p className="text-base text-[#FBB700] tracking-[3%] font-extrabold w-fit">
BASIC INFORMATION
</p>
</div>
<div className="mt-8 grid grid-cols-2">
<div className="flex flex-col gap-4 max-w-[15.6875rem]">
{basicInfoInputFields.map((field, index) => (
<InputCompOne
key={index}
label={field.label}
name={field.name}
parentInputClass={field.parentInputClass}
labelClass={field.labelClass}
select={field.select}
selectClass={field.selectClass}
selectOptions={field.selectOptions}
value={field.value}
onChange={handleChange}
onInput={field.onInput}
placeholder={field.placeholder}
labelSpan={field.labelSpan}
labelSpanClass={field.labelSpanClass}
input={field.input}
inputClass={field.inputClass}
maxLength={field.maxLength}
ref={inputRef}
/>
))}
</div>
</div>
</>
);
};
export default InputSection;
const maritalStatusOptions: SelectOption = {
loading: false,
data: [
{ value: "", label: "Select" },
{ value: "single", label: "Single" },
{ value: "married", label: "Married" },
{ value: "divorced", label: "Divorced" },
{ value: "widowed", label: "Widowed" },
]
}
const titleOptions: SelectOption = {
loading: false,
data: [
{ value: "", label: "Select" },
{ value: "ms", label: "Ms" },
{ value: "mr", label: "Mr" },
{ value: "miss", label: "Miss" },
{ value: "mrs", label: "Mrs" },
]
}
@@ -0,0 +1,129 @@
import React from "react";
import { Button, InputCompOne } from "..";
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 handleSliderChange = (e: any) => {
setValue(e.target.value);
};
return (
<>
<div className="flex justify-between items-center w-full mt-8 mb-[2.8125rem]">
<h1 className="font-semibold text-[38px] text-[#5C2684] my-[8px]">
Loan Amount
</h1>
<div className="flex flex-col gap-[7px]">
<p className="font-extrabold tracking-[3%] text-[#FBB700] underline">
For more enquiries and support
</p>
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
Call: 09099000000
</p>
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
Email: fcmbloan@support.com
</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"
/>
<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="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="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>
</>
);
};
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>
);
};
+111
View File
@@ -0,0 +1,111 @@
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;
@@ -0,0 +1,126 @@
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;
@@ -0,0 +1,49 @@
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;
@@ -0,0 +1,31 @@
import React from "react";
// import { useNavigate } from "react-router-dom";
import EmploymentDetails from "./EmploymentDetails";
import ReferenceDetails from "./ReferenceDetails";
import { Button } from "..";
interface YourAreAlmostThereProps {
handleNextStep: any;
}
const YourAreAlmostThere: React.FC<YourAreAlmostThereProps> = ({ 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>
</>
);
};
export default YourAreAlmostThere;
+32 -28
View File
@@ -1,13 +1,16 @@
import { useState, ChangeEvent, FC } from "react";
import React, { useState, ChangeEvent } from "react";
import Logo from "../../assets/icons/logo.svg";
import Button from "../shared/Button";
import { lowerMenuItems } from "../../utils/data";
import { _lowerMenuItems } from "../../utils/data";
import Sidebar from "./Sidebar";
import { Link } from "react-router-dom";
import HeaderMenuItem from "./HeaderMenuItem";
import { RouteHandler } from "../../router/routes";
type LowerMenuItem = {
id: string | number;
export type LowerMenuItem = {
name: string;
linkPath: string;
subItems?: LowerMenuItem[];
};
type HiddenMenuItems = {
@@ -15,7 +18,7 @@ type HiddenMenuItems = {
hideMenu?: boolean;
};
const Header: FC<HiddenMenuItems> = ({
const Header: React.FC<HiddenMenuItems> = ({
hideSidebar = false,
hideMenu = false,
}) => {
@@ -31,7 +34,7 @@ const Header: FC<HiddenMenuItems> = ({
};
return (
<div className="relative my-2 py-2 flex items-center justify-center border-b-2 border-[#E3DEDA]">
<div className="relative mt-2 py-2 flex items-center justify-center border-b-2 border-[#E3DEDA]">
{!hideSidebar && (
<Sidebar toggleSidebar={toggleSidebar} isSidebarOpen={isSidebarOpen} />
)}
@@ -48,20 +51,25 @@ const Header: FC<HiddenMenuItems> = ({
{!hideMenu && (
<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">
{["Open An Account", "Internet Banking", "Contact Us"].map(
(text: string) => (
<li key={text} className="hidden sm:flex">
<a href="#">
<Button
className={
text === "Open An Account" ? "btn-active" : ""
}
text={text}
/>
</a>
</li>
)
)}
{[
{ text: "Open An Account", href: RouteHandler.getStarted },
{
text: "Internet Banking",
href: RouteHandler.businessBanking,
},
{ text: "Contact Us", href: RouteHandler.cooperateBanking },
].map((item: { text: string; href: string }) => (
<li key={item.text} className="hidden sm:flex">
<a href={item.href}>
<Button
className={
item.text === "Open An Account" ? "btn-active" : ""
}
text={item.text}
/>
</a>
</li>
))}
<li className="w-full lg:w-fit">
<SearchInput
onChange={handleSearchChange}
@@ -69,6 +77,7 @@ const Header: FC<HiddenMenuItems> = ({
/>
</li>
</ul>
<div className="flex lg:hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -88,14 +97,9 @@ const Header: FC<HiddenMenuItems> = ({
/>
</svg>
</div>
<ul className="hidden lg:flex gap-[10px] items-center justify-end flex-wrap">
{lowerMenuItems.map((item: LowerMenuItem) => (
<li
key={item.id}
className="cursor-pointer text-[13.5px] font-medium text-[#525252] tracking-[1px] leading-[-0.3pt]"
>
{item.name}
</li>
<ul className="hidden lg:flex gap-[10px] items-center justify-end flex-wrap relative">
{_lowerMenuItems.map((item: LowerMenuItem, idx: number) => (
<HeaderMenuItem key={idx} item={item} />
))}
</ul>
</div>
+35
View File
@@ -0,0 +1,35 @@
import React, { useState } from "react";
import { LowerMenuItem } from "./Header";
interface MenuItemProps {
item: LowerMenuItem;
}
const HeaderMenuItem: React.FC<MenuItemProps> = ({ item }) => {
const [showSubMenu, setShowSubMenu] = useState<boolean>(false);
const toggleSubMenu = () => {
setShowSubMenu(!showSubMenu);
};
return (
<li
className={`cursor-pointer text-[13.5px] font-medium text-[#525252] tracking-[1px] leading-[-0.3pt]`}
onMouseEnter={toggleSubMenu}
onMouseLeave={toggleSubMenu}
>
<a href={item.linkPath}>{item.name}</a>
{showSubMenu && item.subItems && (
<ul
className={`absolute bg-white shadow-md p-4 z-20 `}
>
{item.subItems.map((subItem, index) => (
<HeaderMenuItem key={index} item={subItem} />
))}
</ul>
)}
</li>
);
};
export default HeaderMenuItem;
+18 -9
View File
@@ -1,4 +1,5 @@
import { top_header_data } from "../../utils/data";
import { Link } from "react-router-dom";
import styles from "./header.module.css";
const TopHeader = () => {
@@ -7,28 +8,36 @@ const TopHeader = () => {
<div className="flex flex-col sm:hidden bg-[#5c2684]">
<ul className="flex flex-col justify-center items-center pt-[0.4rem] text-[13px] font-light">
{["Open An Account", "Internet Banking", "Contact Us"].map((text) => (
<li key={text} className="w-full">
<a href="#" className={`p-2 cursor-pointer text-white w-full items-center justify-center flex`}>
<li key={text} className="w-full">
<a
href="#"
className={`p-2 cursor-pointer text-white w-full items-center justify-center flex`}
>
{text}
</a>
</li>
))}
<li className="w-full flex items-center justify-center">
<a href="#" className={`p-2 mt-2 flex gap-2 bg-[#74449E] cursor-pointer text-white w-full items-center justify-center`}>
<a
href="#"
className={`p-2 mt-2 flex gap-2 bg-[#74449E] cursor-pointer text-white w-full items-center justify-center`}
>
<p className="uppercase">Today's Share price:</p>
<span className="text-[#F8B51F] text-base md:text-lg">$ 4.00</span>
</a>
</li>
<span className="text-[#F8B51F] text-base md:text-lg">
$ 4.00
</span>
</a>
</li>
</ul>
</div>
<div className={styles.top_header}>
<div className="containerMode flex justify-between w-full text-white font-medium text-[11px] md:text-[13px]">
<ul className="flex items-center py-[0.4rem] flex-wrap">
{top_header_data.map(({ id, name }) => (
{top_header_data.map(({ id, name, href }) => (
<li key={id}>
<a href="#" className={`py-[11px] px-[15px]`}>
<Link to={href} className={`py-[11px] px-[15px]`}>
{name}
</a>
</Link>
</li>
))}
</ul>
+2 -2
View File
@@ -2,10 +2,10 @@ import styles from "./hero.module.css";
const Hero = () => {
return (
<div
className={`w-full relative mt-[.9375rem] mb-0 sm:mb-[2.25rem] regLap:h-[30rem] xl:h-[26.875rem] lg:h-[25rem] md:h-[21.875rem] sm:h-[18.75rem] h-[15.625rem] object-cover ${styles.heroBg}`}
className={`w-full relative mb-0 sm:mb-[2.25rem] regLap:h-[30rem] xl:h-[26.875rem] lg:h-[25rem] md:h-[21.875rem] sm:h-[18.75rem] h-[15.625rem] object-cover ${styles.heroBg}`}
>
<div className="containerMode flex justify-between gap-1 xl:gap-8">
<h1 className="max-w-[32.9375rem] font-extrabold text-[1.3rem] leading-[2.5rem] sm:text-[3.625rem] sm:leading-[4.3869rem] text-[#5C2684]">
<h1 className="max-w-[32.9375rem] font-extrabold text-[1.3rem] leading-[2.5rem] sm:text-[3.625rem] sm:leading-[4.3869rem] text-[#5C2684] cursor-default">
PREMIUM SALARY LOAN
</h1>
</div>
+36
View File
@@ -0,0 +1,36 @@
import React from "react";
import styles from "./hero.module.css";
import { Link } from "react-router-dom";
interface PersonalHeroProps {
heading?: string;
body?: string;
buttonLink?: string;
buttonText?: string;
}
const PersonalHero: React.FC<PersonalHeroProps> = ({
heading,
body,
buttonLink = "#",
buttonText,
}) => {
return (
<div
className={`w-full max-[28.125rem] relative mb-0 sm:mb-[2.25rem] regLap:h-[30rem] xl:h-[26.875rem] lg:h-[25rem] md:h-[21.875rem] sm:h-[18.75rem] h-[15.625rem] object-cover ${styles.personalHeroBg}`}
>
<div className="containerMode flex justify-between gap-1 xl:gap-8 flex-col">
<h1 className="max-w-[32.9375rem] font-extrabold text-[1.3rem] leading-[2.5rem] sm:text-[3.625rem] sm:leading-[4.3869rem] text-[#5C2684] cursor-default">
{heading}
</h1>
<p className="p-[.3125rem] pr-5 font-medium table w-[25.375rem]">{body}</p>
<Link to={buttonLink}>
<button className="bg-[#A6368C] text-white text-[.9375rem] w-[10.9375rem] py-[.4375rem] px-[.625rem]">
{buttonText} &nbsp;
</button>
</Link>
</div>
</div>
);
};
export default PersonalHero;
+10
View File
@@ -6,4 +6,14 @@
display: flex;
align-items: center;
justify-content: center;
}
.personalHeroBg{
background: url(../../../assets/images/personal-page.jpg) no-repeat;
background-size: cover;
background-position: center;
/* padding: 0.4rem 0; */
display: flex;
align-items: center;
justify-content: center;
}
+2 -1
View File
@@ -1,3 +1,4 @@
import Hero from "./Hero";
import PersonalHero from "./PersonalHero";
export { Hero };
export { Hero, PersonalHero };
@@ -1,11 +1,10 @@
import { FC } from "react";
import { Link } from "react-router-dom";
import { RouteHandler } from "../../../router/routes";
const FeatureText: FC = () => {
const FeatureText = () => {
return (
<div className="w-full sm:w-2/3 px-0 sm:px-[15px] flex flex-col">
<div className="mt-5 text-[.9375rem] text-[#454545] leading-[1.4375rem]">
<div className="mt-5 text-[.9375rem] text-[#454545] leading-[1.4375rem] cursor-default">
<p className="mb-[.9375rem] text-justify sm:text-left">
Premium Salary Plus loan provides confirmed staff of commercial
organizations more usable funds. The employees organization must have
@@ -28,14 +27,17 @@ const FeatureText: FC = () => {
</ul>
</div>
<Link
to={RouteHandler.getStarted}
className="text-[#5C2684] hover:underline mt-[1.5625rem] w-fit"
to={RouteHandler.letsGetStarted}
className="text-[#5C2684] mt-[1.5625rem] w-fit"
>
***Click here to apply
*** <span className="hover:underline">Click here to apply</span>
</Link>
<p className="mt-[.5625rem] font-bold cursor-default">
<Link
to={RouteHandler.termsAndConditions}
className="mt-[.5625rem] font-bold"
>
Terms and conditions apply
</p>
</Link>
</div>
);
};
+2 -2
View File
@@ -1,4 +1,4 @@
import { Hero } from "./Hero";
import { Hero, PersonalHero } from "./Hero";
import { Requirements } from "./Requirements";
export {Hero, Requirements}
export {Hero, Requirements, PersonalHero}
+119
View File
@@ -0,0 +1,119 @@
import { FaCaretDown } 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, className }: Props) {
return (
<>
{name == "home" ? (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14.1667 14.9875V19.9875H17.5C18.8807 19.9875 20 18.8682 20 17.4875V9.88673C20.0002 9.4538 19.832 9.03778 19.5308 8.72673L12.4492 1.07087C11.1996 -0.281086 9.09074 -0.364094 7.73879 0.885437C7.67457 0.944812 7.6127 1.00665 7.55336 1.07087L0.48418 8.72423C0.173945 9.03657 -0.000117128 9.45899 5.9134e-08 9.89923V17.4875C5.9134e-08 18.8682 1.1193 19.9875 2.5 19.9875H5.83332V14.9875C5.84891 12.7152 7.68355 10.8596 9.89867 10.8061C12.1879 10.7509 14.1492 12.6381 14.1667 14.9875Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
<path
d="M10 12.4875C8.6193 12.4875 7.5 13.6068 7.5 14.9875V19.9875H12.5V14.9875C12.5 13.6068 11.3807 12.4875 10 12.4875Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
</svg>
) : name == "profile" ? (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 10C12.7614 10 15 7.76142 15 5C15 2.23858 12.7614 0 10 0C7.23858 0 5 2.23858 5 5C5 7.76142 7.23858 10 10 10Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
<path
d="M10 11.6667C5.85977 11.6713 2.50461 15.0265 2.5 19.1667C2.5 19.6269 2.87309 20 3.33332 20H16.6666C17.1269 20 17.5 19.6269 17.5 19.1667C17.4954 15.0265 14.1402 11.6713 10 11.6667Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
</svg>
) : name == "verification" ? (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.728 6.8281L18.1812 5.28145C17.814 4.91432 17.2203 4.91432 16.857 5.28145L7.50177 14.6356L3.15031 10.2807C2.78313 9.91359 2.1894 9.91359 1.82613 10.2807L0.275384 11.8313C-0.0917946 12.1984 -0.0917946 12.7921 0.275384 13.1592L6.83772 19.7246C7.2049 20.0918 7.79864 20.0918 8.16191 19.7246L19.7241 8.15603C20.0913 7.78499 20.0913 7.19133 19.728 6.8281ZM7.06037 10.9681C7.30256 11.2142 7.70098 11.2142 7.94316 10.9681L16.068 2.8365C16.3101 2.59044 16.3101 2.19597 16.068 1.95382L14.3024 0.184543C14.0602 -0.0615144 13.6618 -0.0615144 13.4196 0.184543L7.50177 6.10164L5.33776 3.93399C5.09558 3.68794 4.69715 3.68794 4.45497 3.93399L2.68548 5.70327C2.4433 5.94932 2.4433 6.3438 2.68548 6.58595L7.06037 10.9681Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
</svg>
) : name == "payments" ? (
<svg
width="20"
height="16"
viewBox="0 0 20 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 14.2857C0 15.2321 0.746528 16 1.66667 16H18.3333C19.2535 16 20 15.2321 20 14.2857V8H0V14.2857ZM6.66667 11.8571C6.66667 11.6214 6.85417 11.4286 7.08333 11.4286H11.8056C12.0347 11.4286 12.2222 11.6214 12.2222 11.8571V13.2857C12.2222 13.5214 12.0347 13.7143 11.8056 13.7143H7.08333C6.85417 13.7143 6.66667 13.5214 6.66667 13.2857V11.8571ZM2.22222 11.8571C2.22222 11.6214 2.40972 11.4286 2.63889 11.4286H5.13889C5.36806 11.4286 5.55556 11.6214 5.55556 11.8571V13.2857C5.55556 13.5214 5.36806 13.7143 5.13889 13.7143H2.63889C2.40972 13.7143 2.22222 13.5214 2.22222 13.2857V11.8571ZM20 1.71429V3.42857H0V1.71429C0 0.767857 0.746528 0 1.66667 0H18.3333C19.2535 0 20 0.767857 20 1.71429Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
</svg>
) : name == "legals" ? (
<svg
width="20"
height="16"
viewBox="0 0 20 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 10.5H7.99937C7.99937 9.99438 8.04125 10.2272 5.34156 4.82781C4.79 3.725 3.21062 3.72281 2.65812 4.82781C-0.0643752 10.2734 0.000625 10.0103 0.000625 10.5H0C0 11.8806 1.79094 13 4 13C6.20906 13 8 11.8806 8 10.5ZM4 5.5L6.25 10H1.75L4 5.5ZM19.9994 10.5C19.9994 9.99438 20.0413 10.2272 17.3416 4.82781C16.79 3.725 15.2106 3.72281 14.6581 4.82781C11.9356 10.2734 12.0006 10.0103 12.0006 10.5H12C12 11.8806 13.7909 13 16 13C18.2091 13 20 11.8806 20 10.5H19.9994ZM13.75 10L16 5.5L18.25 10H13.75ZM16.5 14H11V4.78906C11.7347 4.4675 12.2863 3.80531 12.4497 3H16.5C16.7763 3 17 2.77625 17 2.5V1.5C17 1.22375 16.7763 1 16.5 1H11.9888C11.5325 0.39625 10.8153 0 10 0C9.18469 0 8.4675 0.39625 8.01125 1H3.5C3.22375 1 3 1.22375 3 1.5V2.5C3 2.77625 3.22375 3 3.5 3H7.55031C7.71375 3.805 8.265 4.4675 9 4.78906V14H3.5C3.22375 14 3 14.2238 3 14.5V15.5C3 15.7762 3.22375 16 3.5 16H16.5C16.7763 16 17 15.7762 17 15.5V14.5C17 14.2238 16.7763 14 16.5 14Z"
fill={fillColor ? fillColor : "#5C2684"}
/>
</svg>
) : name == "arrow" ? (
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.3072 1.05822L7.03885 0.34847C7.34865 0.0479466 7.8496 0.0479466 8.15611 0.34847L14.563 6.56035C14.8728 6.86087 14.8728 7.34682 14.563 7.64415L8.15611 13.8592C7.84631 14.1597 7.34536 14.1597 7.03885 13.8592L6.3072 13.1495C5.9941 12.8458 6.00069 12.3502 6.32038 12.0529L10.2917 8.38267H0.819787C0.381453 8.38267 0.0288086 8.04058 0.0288086 7.61538V6.59232C0.0288086 6.16711 0.381453 5.82503 0.819787 5.82503H10.2917L6.32038 2.15481C5.9974 1.85748 5.99081 1.36194 6.3072 1.05822Z"
fill={fillColor ? fillColor : "#FBB700"}
/>
</svg>
) : name == "greater-than" ? (
<svg
width="11"
height="16"
viewBox="0 0 11 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.74365 8.64502L3.10303 15.2856C2.64404 15.7446 1.90186 15.7446 1.44775 15.2856L0.344238 14.1821C-0.114746 13.7231 -0.114746 12.981 0.344238 12.5269L5.05127 7.81982L0.344238 3.11279C-0.114746 2.65381 -0.114746 1.91162 0.344238 1.45752L1.44287 0.344238C1.90186 -0.114746 2.64404 -0.114746 3.09814 0.344238L9.73877 6.98486C10.2026 7.44385 10.2026 8.18604 9.74365 8.64502Z"
fill={fillColor ? fillColor : "#FFF"}
/>
</svg>
) :name == 'arrow-down'?
<FaCaretDown className={`text-xl ${className && className}`} />
:name == "dash-icon" ? (
<img src={dashIcon} alt="dash-icon" />
) : null}
</>
);
}
+3
View File
@@ -0,0 +1,3 @@
import Icons from "./Icons";
export { Icons };
@@ -0,0 +1,9 @@
import React from 'react'
const InternetBanking: React.FC = () => {
return (
<div>InternetBanking</div>
)
}
export default InternetBanking
+3
View File
@@ -0,0 +1,3 @@
import InternetBanking from "./InternetBanking";
export { InternetBanking };
@@ -0,0 +1,165 @@
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";
// 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"),
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"),
// .test("no-e", "must be 11 characters", (value:any) => {
// if (value.length < 11) {
// return false;
// }
// return true;
// })
});
// initial values for formik
let initialValues = {
bvn: '',
otp: '',
};
const LetsGetStarted: React.FC = () => {
const navigate = useNavigate()
// const [pinValues, setPinValues] = React.useState({
// bvn: "",
// otp: "",
// });
const [hideOTPComponent, setHideOTPComponent] = React.useState<boolean>(true);
const firstInputRef = React.useRef<HTMLInputElement>(null);
const secondInputRef = React.useRef<HTMLInputElement>(null);
// const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// let { name, value } = e.target as HTMLInputElement;
// setPinValues((prev) => ({ ...prev, [name]: value }));
// };
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");
}
}
};
const handleSubmit = (values:any) => {
console.log('values', values)
navigate(RouteHandler.dashboardHome, {replace:true})
};
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{(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>
{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>
) : (
<p className="text-[#5C2684] mt-[1.5625rem] w-fit">
***Did not receive OTP? Click to resend
</p>
)}
</div>
</div>
</div>
</Form>
)}
</Formik>
);
};
export default LetsGetStarted;
@@ -0,0 +1,22 @@
import React from "react";
import { Link } from "react-router-dom";
import Logo from "../../assets/icons/logo.svg";
const LetsGetStartedNav: React.FC = () => {
return (
<div className="w-full">
<div className="containerMode flex justify-between gap-1 xl:gap-8">
<Link to="/">
<img
src={Logo}
alt="Logo"
className="w-[52px] h-[43px] xl:w-[72px] xl:h-[63px]"
/>
</Link>
</div>
</div>
);
};
export default LetsGetStartedNav;
+4
View File
@@ -0,0 +1,4 @@
import LetsGetStarted from "./LetsGetStarted";
import LetsGetStartedNav from "./LetsGetStartedNav";
export { LetsGetStarted, LetsGetStartedNav };
+1 -1
View File
@@ -18,7 +18,7 @@ export default function Login() {
password: ''
})
const handleFormChange = ({target:{name, value}}:{target:HandleChange}):void => {
const handleFormChange = ({target:{name, value}}:{target:HandleChange}):any => {
setFormDetails(prev => ({...prev, [name]:value}))
}
+428
View File
@@ -0,0 +1,428 @@
import React from "react";
const Main: React.FC = () => {
return (
<div className="w-full my-3">
<div className="containerMode">
<p className="mb-[15px]">
<strong>PRIVACY POLICY</strong>
</p>
<p className="mb-[15px]">
<strong>
<span>1.Your Privacy is important to us.</span>
</strong>
</p>
<p className="mb-[15px]">
This privacy statement sets out the privacy policy of
fcmbgroupplc.com, which provides a portal, or gateway, to the
financial services offered by the First City Monument Bank Limited and
the other members of the FCMB Group Plc (Collectively, FCMB).
</p>
<p className="mb-[15px]">
This policy explains how we collect, share, use, and protect
information when you visit or use this website and any other online
services, platforms, or products offered by FCMB or any of its banking
and non-banking affiliates and subsidiaries that link to or reference
this policy (collectively, our services).
</p>
<p className="mb-[15px]">
<strong>1.1 FCMB and You</strong>
</p>
<p className="mb-[15px]">
First City Monument Bank Limited is a private limited liability
company registered in the Federal Republic of Nigeria under RC No.
46713. Its head-office is at Primrose Tower, 17A Tinubu Street, Lagos
State, Nigeria.
</p>
<p className="mb-[15px]">
FCMB Group Plc hosts the fcmbgroupplc.com website and provides
technical support, access and links to the Local Sites of First City
Group members. fcmbgroupplc.com does not offer financial services or
products. Financial services and products may only be obtained by
registering with a Local Site. The First City Group provides financial
products and services to a global clientele through its affiliated
companies and branches located in 36 states and the Federal Capital
Territory in Nigeria, and in the UK. Privacy and personal data
protection principles vary from one country to another. When you
access or link to a Local Site, please read the privacy statement
issued by the Local Site to determine the policies that apply to
information or data maintained by the Local Site.
</p>
<p className="mb-[15px]">
<strong>
<span>2. Information we may collect about you </span>
</strong>
</p>
<p className="mb-[15px]">
<strong>2.1 Your Personal Information</strong>
</p>
<p className="mb-[15px]">
At FCMB, we strive to meet your needs and provide you with exceptional
services. In the course of consuming our services through various
channels, such as forms, phone calls, correspondence, service point
interfaces, and other available channels, we collect information that
you provide to us. This information may include, but is not limited
to, contact data, log/Technical information, Financial Data, Marketing
and Communications Data, identity verification details (this includes
Personally Identifiable Information (PII), otherwise known as Personal
Information or Personal Data, which includes email address, phone
number, contact address, limited financial information, location data,
device data etc.) and documents, services consumed or desired, mode of
consumption, preferences, location, general events, and instructions
and transactions relating to the services.
</p>
<p className="mb-[15px]">
The lawful basis we rely on for processing your Personal Information
are:
</p>
<ol>
<li>
Your Consent: Where you agree to us collecting your Personal
Information by using our Services.
</li>
<li>
We have a contractual obligation: Without your Personal Information,
we cannot provide our Services to you.
</li>
<li>
We have a legal obligation: To ensure we are fully compliant with
all applicable financial legislations such as Anti-Money Laundering
and Countering the Financing of Terrorism (AML/CFT) Laws, we must
collect and store your Personal Information. We protect against
fraud by checking your identity with your Personal Information.
</li>
</ol>
<p className="mb-[15px]">
Additionally, to better serve your needs, we may utilize information
about you collected from third parties and service partners. It is
important to note that these third-party sources are not under the
control of FCMB, and we are not responsible for how they use the
information.
</p>
<p className="mb-[15px]">
<strong>2.2 Usage and other information</strong>
</p>
<p className="mb-[15px]">
In addition to the personal information described above, we may
collect certain information about your use of our online services. For
example, we may capture the IP address of the device you use to
connect to the online service, the type of operating system and
browser you use, and information about the site you came from, the
parts of our online service you access, and the site you visit next.
FCMB or our third-party partners may also use cookies, web beacons or
other technologies to collect and store other information about your
visit to, or use of, our online services. In addition, we may later
associate the usage and other information we collect online with
personal information about you.
</p>
<p className="mb-[15px]">
<strong>2.3 FCMB Mobile</strong>
</p>
<p className="mb-[15px]">
For the convenience of our FCMB customers, we provide access to our
products and services through our mobile applications and
mobile-optimized websites ("FCMB Mobile"). When you engage with us
through FCMB Mobile, we may collect certain information to enhance
your experience. This information may include unique device
identifiers for your mobile device, screen resolution, device
settings, location information, and analytical data regarding your
mobile device usage. Please note that we may request your permission
before collecting specific information, such as precise geo-location
data,- contact or image data and other personal identifiable
information through FCMB Mobile. Rest assured that any information
collected is handled with the utmost care and in accordance with our
privacy policy.
</p>
<p className="mb-[15px]">
<strong>2.4 Additional sources of information</strong>
</p>
<p className="mb-[15px]">
We may also collect information about you from additional online and
offline sources including from co-branded partner sites or
commercially available third-party sources, such as credit reporting
agencies. We may combine this information with the personal and other
information we have collected about you under this Privacy Policy.
</p>
<p className="mb-[15px]">
<strong>2.5 Non-Personal Information</strong>
</p>
<p className="mb-[15px]">
In order to achieve our goal of providing you with the best-in-class
service, we may also collect, store, use and transfer non-personal
information or anonymized data such as statistical or demographic
data. These may be collected or sourced during your visits to perform
certain tasks such as grant you access to some parts of our web site
or conduct research on your behaviour on our site in order to improve
our services. We will not disclose your information to any person
outside our organization except as described in this Privacy Policy.
</p>
<p className="mb-[15px]">
<strong>
<span>3. Our Use of Information</span>
</strong>
</p>
<p className="mb-[15px]">
FCMB and/or subsidiaries may use or process the information discussed
above in a number of ways, such as to:
</p>
<ol>
<li>Manage your preferences;</li>
<li>
Create and manage any accounts or transactions you may have with us,
verify your identity, provide our services, and respond to your
inquiries;
</li>
<li>
Process your applications and transactions (including authorization,
clearing, chargebacks and other related dispute resolution
activities);
</li>
<li>
Protect against and prevent fraud, unauthorized transactions, claims
and other liabilities as well as enhance the security of your
account or our online services;
</li>
<li>
Provide, administer and communicate with you about our products,
services, offers, programs and promotions as well as those of our
merchants and partners;
</li>
<li>
Evaluate your interest in employment and contact you regarding
possible employment with FCMB;
</li>
<li>
Evaluate and improve our business, including developing new products
and services;
</li>
<li>To target advertisements, newsletters, and service updates;</li>
<li>As necessary to establish, exercise and defend legal rights;</li>
<li>
Perform analytics concerning your use of our online services,
including your responses to our emails and the pages and
advertisements you view;
</li>
<li>
As may be required by applicable laws and regulations, including for
compliance with Know Your Customers and risk assessment, Anti-Money
Laundering, anti-corruption and sanctions screening requirements, or
as requested by any judicial process, law enforcement or
governmental agency having or claiming jurisdiction over FCMB or
affiliates;
</li>
<li>
To use data analytics to improve our Website, products, or services,
and user experiences;
</li>
<li>
For other purposes for which we provide specific notice at the time
you provide or we collect your information.
</li>
</ol>
<p className="mb-[15px]">
We may also use data that we collect on an aggregate or anonymous
basis (such that it does not identify any individual customers) for
various business purposes, where permissible under applicable laws and
regulations.
</p>
<p className="mb-[15px]">
<strong>
<span>4. Cookies</span>
</strong>
</p>
<p className="mb-[15px]">
This website, along with most other major websites, uses cookies.
Cookies are pieces of information that a website transfers to the
cookie file on your computers hard disk. Cookies enable users to
navigate around the website and (where appropriate) enable us to
tailor the content to fit the needs of visitors who have accessed the
site.
</p>
<p className="mb-[15px]">
Firstcitygroup.com uses two types of cookies on this website:
</p>
<ol>
<li>
Session cookies, which are temporary cookies that remain in the
cookie file of your computer until you close your browser (at which
point they are deleted).
</li>
<li>
Persistent or stored cookies that remain permanently on the cookie
file of your computer.
</li>
</ol>
<p className="mb-[15px]">
Cookies cannot look into your computer and obtain information about
you or your family or read any material kept on your hard drive and,
unless you have logged onto an authenticated page, cookies cannot be
used to identify who you are.
</p>
<p className="mb-[15px]">
Cookies cannot be used by anyone else who has access to the computer
to find out anything about you, other than the fact that someone using
the computer has visited a certain website. Cookies do not in any way
compromise the security of your computer.
</p>
<p className="mb-[15px]">
Cookies will not be used to contact you for marketing purposes other
than by means of advertisements offered within this website.
</p>
<p className="mb-[15px]">
Cookies may be used to record details of pages relating to particular
products and services that you have visited on this website. This is
to provide fcmb.com with generic usage statistics to allow the company
to improve this website and to provide you with information that may
interest you.
</p>
<p className="mb-[15px]">
The web browsers of most computers are initially set up to accept
cookies. If you prefer, you can set your web browser to disable
cookies or to inform you when a website is attempting to add a cookie.
You can also delete cookies that have previously been added to your
computers cookie file.
</p>
<p className="mb-[15px]">
You can set your browser to disable persistent cookies and/or session
cookies but if you disable session cookies, although you will be able
to view this websites unsecured pages, you may not be able to log
onto any authenticated pages.
</p>
<p className="mb-[15px]">
Please visit{" "}
<a href="http://www.allaboutcookies.org/manage-cookies/">
http://www.allaboutcookies.org/manage-cookies/
</a>{" "}
to discover how to disable and delete cookies.
</p>
<p className="mb-[15px]">
<strong>
<span>5. Disclosures</span>
</strong>
</p>
<p className="mb-[15px]">
<strong>5.1 Disclosures</strong>
</p>
<p className="mb-[15px]">
We may divulge individual data to any individual performing review,
lawful, operational, or different services for us. We will utilize
data which does not identify the person for these exercises at
whatever point achievable. Data divulged to vendors or contractors for
operational purposes may not be re-disclosed to others by such a
vendor or contractor. We may reveal individual data when needed to do
as such by a court request, or court order. We may divulge individual
data as we esteem it proper to secure the wellbeing of our customers
or for an investigation identified with open security or to report an
action that has all the earmarks of being disregarding law. We may
divulge individual data to ensure the security and dependability of
this site and to take safety measures against accountability.
</p>
<p className="mb-[15px]">
<strong>5.2 Disclosures to Third Parties</strong>
</p>
<p className="mb-[15px]">
Data about you that is accessible to you by means of fcmb.com,
including your personal data, can become subject to the legal systems
and laws in force in the country where the data is held, received or
stored by you or us. Such data can become subject to disclosure
pursuant to the laws of the country.
</p>
<p className="mb-[15px]">
We may reveal your name and other personal data and other monetary
data about you at the request of regulatory agency or in connection
with an examination of us as a bank. This information could be
revealed to internal and external attorneys or auditors, and to others
whom we are required to make such revelations.
</p>
<p className="mb-[15px]">
<strong>
<span>6. Information Security and Retention</span>
</strong>
</p>
<p className="mb-[15px]">
At FCMB, we are fully committed to protecting the information we
collect. We maintain administrative, technical, and physical controls
to actively safeguard the Personal Information you provide or we
collect. These controls are designed to protect against loss, theft,
unauthorized access, disclosure, copying, misuse, or modification.
</p>
<p className="mb-[15px]">
Our security measures actively include secure servers, firewalls, data
encryption, and restricted access granted only to employees for
fulfilling their job responsibilities.
</p>
<p className="mb-[15px]">
When using a password for any of your accounts, it is essential that
you actively ensure its confidentiality and refrain from sharing it
with anyone.
</p>
<p className="mb-[15px]">
We actively conduct our business in accordance with these principles
to actively ensure the confidentiality and protection of your Personal
Information. While transmitting information online may not be entirely
secure, we actively take all reasonable steps to ensure the security
and protection of your Personal Information.
</p>
<p className="mb-[15px]">
We will only retain personal information on our servers for as long as
it is actively necessary while providing services to you. In the event
you close your account, we actively store your information on our
servers to comply with regulatory obligations and actively monitor,
detect, and prevent fraud. Any retention of your Personal Data is
solely for such length of time as may be required by law, regulation,
and the internal policies of FCMB, her members and/or affiliates.
</p>
<p className="mb-[15px]">
<strong>6.1 Data Protection on the Internet</strong>
</p>
<p className="mb-[15px]">
At FCMB we utilize encryption innovation to ensure the transmission of
data to or from you by means of fcmb.com. For security reasons and to
protect the security of your information, access to fcmb.com is
restricted to authorized users only. However, because information
about you, your account data and other transactions can be accessed
through a public network, the Internet, there can be no guarantee that
your account information will remain secure and you accept the risk
that unauthorized persons may view such information. If you believe
that an unauthorized person has accessed your information, please
contact the Bank immediately.
</p>
<p className="mb-[15px]">
<strong>
<span>7. Updates to this Policy</span>
</strong>
</p>
<p className="mb-[15px]">
From time to time, we may change, amend or review this Privacy Policy
from time to time to reflect new services or changes in our Privacy
Policy and place any updates on this page. All changes made will be
posted on this page and where changes will materially affect you, we
will notify you of this change by placing a notice online or via mail.
If you keep using our Services, you consent to all amendments of this
Privacy Policy.
</p>
<p className="mb-[15px]">
<strong>
<span>8. Contact us</span>
</strong>
</p>
<p className="mb-[15px]">
For issues relating to personal data, please contact us via any of the
below:
</p>
<p className="mb-[15px]">
Corporate Address: Primrose Tower, 17A, Tinubu Street, Marina, Lagos
</p>
<p className="mb-[15px]">Telephone: 07003290000, 01-2798800</p>
<p className="mb-[15px]">
Email: <a href="#">customerservice@fcmb.com</a>
</p>
<p className="mb-[15px]">
Whatsapp: (+234) 09099999814 or (+234) 09099999815
</p>
</div>
</div>
);
};
export default Main;
+3
View File
@@ -0,0 +1,3 @@
import Main from "./Main";
export { Main as TsAndCs };
+11 -5
View File
@@ -1,5 +1,11 @@
export * from "./Header"
export * from "./Home"
export * from "./GetStarted"
export * from "./shared"
export * from "./Footer"
export * from "./Header";
export * from "./Home";
export * from "./GetStarted";
export * from "./shared";
export * from "./Footer";
// export * from "./DashboardLayout";
export * from "./Icons";
export * from "./Dashboard";
export * from "./Cards";
export * from "./LetsGetStated";
export * from "./TsAndCs";
+21 -5
View File
@@ -1,11 +1,27 @@
import React from "react";
type ButtonProps = {
className?: string;
interface ButtonProps {
text: string;
};
className?: string;
type?: "button" | "submit" | "reset";
onClick?: React.MouseEventHandler<HTMLButtonElement>;
}
const Button = ({ text, className }: ButtonProps) => {
return <button className={`btn-primary uppercase text-[11px] lg:text-[13px] p-[6px] lg:px-[10px] ${className}`}>{text}</button>;
const Button: React.FC<ButtonProps> = ({
text,
className,
onClick,
type = "button",
}) => {
return (
<button
className={`btn-primary uppercase text-[11px] lg:text-[13px] p-[6px] lg:px-[10px] ${className}`}
onClick={onClick}
type={type}
>
{text}
</button>
);
};
export default Button;
+1 -1
View File
@@ -7,7 +7,7 @@ type Props = {
labelName?:string,
inputClass?:string,
value:string,
onChange:()=>void
onChange:(event?: any)=>any
}
export default function FloatLabelInput({
+139
View File
@@ -0,0 +1,139 @@
import React, { forwardRef } from "react";
import { Icons } from "../Icons";
export interface InputCompOneProps {
label?: string;
labelClass?: string;
labelSpan?: string;
labelSpanClass?: string;
floatLabel?: string;
placeholder?: string;
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?: {loading:boolean, data:{ value: string; label: string }[]};
inputType?: string;
inputClass?: string;
parentInputClass?: string;
selectClass?: string;
parentClass?: string;
maxLength?: number;
error?: string;
}
const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
(
{
label,
labelClass,
labelSpan,
labelSpanClass,
floatLabel,
placeholder,
value,
onChange,
onInput,
name,
tabIndex,
selectValue,
input = false,
select = false,
selectOptions = {loading:false, data:[]},
inputType = "text",
inputClass,
parentInputClass,
selectClass,
parentClass,
maxLength,
error,
},
forwardedRef
) => {
return (
<div className={parentClass}>
{label && (
<label htmlFor={label ? label : floatLabel} className={`flex gap-2 items-center ${labelClass}`}>
{label}
{labelSpan && <span className={labelSpanClass}>{labelSpan}</span>}
{error && label && <span className='text-[10px] text-red-500'>{error}</span>}
</label>
)}
{input && (
<div className={`relative ${parentInputClass}`}>
<input
type={inputType}
placeholder={placeholder}
value={value}
onChange={onChange}
onInput={onInput}
name={name}
tabIndex={tabIndex}
ref={forwardedRef}
className={`px-4 ${floatLabel && 'peer pt-4 placeholder:text-transparent'} ${inputClass}`}
maxLength={maxLength}
id={label ? label : floatLabel}
/>
{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={`relative ${parentInputClass}`}>
<select
name={name}
id={label ? label : floatLabel}
value={selectValue}
className={`px-4 appearance-none ${floatLabel && 'peer pt-4'} ${selectClass}`}
onChange={onChange}
>
{selectOptions.loading ?
<option value=''>Loading</option>
: selectOptions.data.length ?
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>
);
}
);
export default InputCompOne;
+25
View File
@@ -0,0 +1,25 @@
import React from "react";
interface StepperProps {
step: number;
}
const Stepper: React.FC<StepperProps> = ({ step = 0 }) => {
// const [activeStep, setActiveStep] = useState(step);
return (
<div className="flex justify-between items-center gap-5">
{[...Array(6)].map((_, index) => (
<div
key={index}
className={`w-[1.875rem] border-[.1875rem] rounded-sm ${(step === index
? "border-[#E8B4FF]"
: "border-[#5C2684]")}`}
// onClick={() => setActiveStep(index)}
/>
))}
</div>
);
};
export default Stepper;
+3 -1
View File
@@ -1,4 +1,6 @@
import Button from "./Button";
import InputCompOne from "./InputCompOne";
import FloatLabelInput from "./FloatLabelInput";
import Stepper from "./Stepper";
export {Button, FloatLabelInput}
export { Button, FloatLabelInput, InputCompOne, Stepper };
+2 -1
View File
@@ -14,6 +14,7 @@ body {
@layer components {
.containerMode {
@apply container mx-auto px-5 xxs:max-w-full sm:max-w-[98%] lg:max-w-[1100px];
/* @apply container mx-auto px-5 xxs:max-w-full sm:max-w-[98%] lg:max-w-[1100px]; */
@apply container mx-auto px-5 max-w-[1500px]
}
}
+183
View File
@@ -0,0 +1,183 @@
import { useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import Logo from "../../assets/icons/logo.svg";
import { Icons } from "../../components";
type Props = {
asideDisplay?: () => void;
};
export default function Aside({ asideDisplay }: Props) {
const { pathname } = useLocation();
const navigate = useNavigate();
const [openNestedLink, setOpenNestedLink] = useState<{ name: string | null }>(
{ name: "" }
);
const handleOpenNestedLink = (e: any) => {
if (!e || !e.target) {
return setOpenNestedLink({ name: "" });
}
if (openNestedLink.name && openNestedLink.name == e.target.name) {
setOpenNestedLink({ name: "" });
} else {
setOpenNestedLink({ name: e.target.name });
}
};
return (
<div className="py-5 px-10 flex flex-col h-full bg-inherit">
<Link to="/">
<img src={Logo} alt="Logo" className="w-[72px] h-[63px]" />
</Link>
<div className="mt-10 h-full overflow-y-auto bg-inherit">
{asideLinks.map((link, index) => {
if (link.nestedLink?.length) {
let allNestedLinks = link.nestedLink.map((item) => item.link);
return (
<div
key={index}
className="w-full relative bg-inherit overflow-hidden"
>
<button
name={link.name}
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]"
}`}
>
{link.name}
{/* <div className={`mr-2 ${openNestedLink.name == link.name ? '-rotate-90' : 'rotate-90'} transition-all duration-300`}>
<Icons
name='greater-than'
fillColor={`${openNestedLink.name == link.name ? '#5C2684' : '#585858'}`}
/>
</div> */}
</button>
<div
className={`transition-all duration-300 w-full z-1 ${
openNestedLink.name == link.name
? "relative top-0"
: "absolute -top-[500px]"
}`}
>
{link.nestedLink.map((nextLink, index) => (
<Link
onClick={() => {
asideDisplay && asideDisplay();
}}
key={index}
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]"
}`}
>
<Icons
name={nextLink.icon}
fillColor={`${
pathname == nextLink.link ? "#5C2684" : "#585858"
}`}
/>
{nextLink.name}
</Link>
))}
</div>
</div>
);
} else {
return (
<Link
onClick={() => {
asideDisplay && asideDisplay();
}}
key={index}
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]"
}`}
>
<Icons
name={link.icon}
fillColor={`${pathname == link.link ? "#5C2684" : "#585858"}`}
/>
{link.name}
</Link>
);
}
})}
</div>
<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 })}
>
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]">
Call: 09099000000
</p>
<p className="font-extrabold tracking-[3%] text-[#5A5A5A]">
Email: fcmbloan@support.com
</p>
</div>
</div>
</div>
);
}
type AsideLinksType = {
name: string;
link?: string;
icon: string;
nestedLink?: {
name: string;
link: string;
icon: string;
}[];
}[];
const asideLinks: AsideLinksType = [
{ name: "Dashboard", link: "/dashboard/home", icon: "dash-icon", nestedLink: [] },
{
name: "Your Profile",
link: "/dashboard/profile",
icon: "dash-icon",
nestedLink: [],
},
{
name: "Employment Details",
link: "/dashboard/verification",
icon: "dash-icon",
nestedLink: [],
},
{
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:[
// {name: 'Link 2', link: '/dashboard/not-found', icon: 'legals'},
// {name: 'Link 1', link: '/dashboard/not-found', icon: 'home'}
// ]
// },
];
@@ -0,0 +1,11 @@
import DashboardLayout from "./DashboardLayout";
import { Outlet } from "react-router-dom";
export default function DashboardAuth() {
return (
<DashboardLayout>
<Outlet />
</DashboardLayout>
)
}
@@ -0,0 +1,115 @@
import { ReactNode, useState, useEffect } from "react";
import Aside from "./Aside";
export default function DashboardLayout({ children }: { children: ReactNode }) {
const [showAside, setShowAside] = useState<boolean>(false);
const asideDisplay = (): void => {
setShowAside((prev) => !prev);
};
useEffect(() => {
const handleResize = () => {
return setShowAside(false);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
// Assume this interface for ChildProps
// interface ChildProps {
// customProp?: string;
// }
// const enhanceChildren = React.Children.map(children, (child) => {
// if (React.isValidElement<ChildProps>(child)) {
// return React.cloneElement(child, { customProp: "Hello, World!" });
// }
// return child;
// });
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>
<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>
<main className="dash-bg-image bg-[#F9F9F9] relative w-full overflow-y-auto overflow-x-hidden">
<header className={`p-5 md:hidden sticky z-10 top-0 w-full bg-[#F9F9F9] border-b-2 border-[#E6E6E6]`}>
<div className='h-14 w-full flex justify-end items-center gap-5'>
{/* MENU HAND BURGER */}
{/* <div className='w-full'>Welcome Austin Catherine</div> */}
<div
className="relative md:hidden w-5 h-[20px] flex flex-col items-center justify-between"
onClick={asideDisplay}
>
<div
className={`absolute left-0 w-5 h-1 bg-black/80 dark:bg-white transition-all duration-500 ${
showAside ? "top-1/2 -translate-y-1/2 rotate-45" : "top-0"
}`}
></div>
<div
className={`absolute left-0 w-5 h-1 bg-black/80 dark:bg-white transition-all duration-300 ${
showAside
? "top-1/2 -translate-y-1/2 rotate-[2000deg] opacity-0"
: "top-1/2 -translate-y-1/2"
}`}
></div>
<div
className={`absolute left-0 w-5 h-1 bg-black/80 dark:bg-white transition-all duration-500 ${
showAside
? "top-1/2 -translate-y-1/2 -rotate-45"
: "bottom-0"
}`}
></div>
</div>
</div>
</header>
<div className="flex p-5 relative">
<div className="w-full p-5">{children}</div>
</div>
</main>
</div>
);
}
// {/* <header className={`p-5 sticky z-10 top-0 w-full bg-[#F9F9F9] border-b-2 border-[#E6E6E6]`}>
// <div className='h-14 w-full flex justify-end items-center gap-5'>
// {/* MENU HAND BURGER */}
// <div className='w-full'>Welcome Austin Catherine</div>
// <div
// className="relative md:hidden w-5 h-[20px] flex flex-col items-center justify-between"
// onClick={asideDisplay}
// >
// <div
// className={`absolute left-0 w-5 h-1 bg-black/80 dark:bg-white transition-all duration-500 ${
// showAside ? "top-1/2 -translate-y-1/2 rotate-45" : "top-0"
// }`}
// ></div>
// <div
// className={`absolute left-0 w-5 h-1 bg-black/80 dark:bg-white transition-all duration-300 ${
// showAside
// ? "top-1/2 -translate-y-1/2 rotate-[2000deg] opacity-0"
// : "top-1/2 -translate-y-1/2"
// }`}
// ></div>
// <div
// className={`absolute left-0 w-5 h-1 bg-black/80 dark:bg-white transition-all duration-500 ${
// showAside
// ? "top-1/2 -translate-y-1/2 -rotate-45"
// : "bottom-0"
// }`}
// ></div>
// </div>
// </div>
// </header> */}
+3
View File
@@ -0,0 +1,3 @@
import DashboardAuth from "./DashboardAuth";
export { DashboardAuth };
+24
View File
@@ -0,0 +1,24 @@
import React from "react";
import { Footer, Header } from "../components";
interface GetStartedLayoutProps {
children: React.ReactNode;
}
const GetStartedLayout: React.FC<GetStartedLayoutProps> = ({ children }) => {
return (
<div className="containerMode mb-[5.4375rem]">
<div className='sticky top-0 bg-white'>
<Header hideSidebar={true} hideMenu={true} />
</div>
<div className="flex flex-col min-h-[70vh] justify-between">
{children}
</div>
<div className="fixed bottom-0 left-0 bg-white w-full">
<Footer />
</div>
</div>
);
};
export default GetStartedLayout;
+27
View File
@@ -0,0 +1,27 @@
import React, { ReactNode } from "react";
import {
BottomFooterOne,
Header,
MidFooter,
TopFooterOne,
TopHeader,
} from "../components";
interface HomeLayoutProps {
children: ReactNode;
}
const HomeLayout: React.FC<HomeLayoutProps> = ({ children }) => {
return (
<>
<TopHeader />
<Header />
{children}
<TopFooterOne />
<MidFooter />
<BottomFooterOne />
</>
);
};
export default HomeLayout;
+24
View File
@@ -0,0 +1,24 @@
import React from "react";
import { Footer, LetsGetStartedNav } from "../components";
// import layoutImage from "../assets/images/test1-reverse.png";
const LetsGetStartedLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className='containerMode mb-[5.4375rem]'>
<div className="w-full min-h-[90vh] grid lg:grid-cols-2">
<div className="w-full flex flex-col my-3">
<LetsGetStartedNav />
{children}
</div>
<div className="w-full h-96 lg:h-full bg-[url(../src/assets/images/test1-reverse.png)] bg-cover bg-no-repeat">
{/* <img src={layoutImage} alt="" className="w-full h-full object-cover" /> */}
</div>
</div>
<div className="fixed bottom-0 left-0 bg-[#F7F7F7] w-full">
<Footer />
</div>
</div>
);
};
export default LetsGetStartedLayout;
+7
View File
@@ -0,0 +1,7 @@
import HomeLayout from "./HomeLayout";
import LetsGetStartedLayout from "./LetsGetStartedLayout";
import GetStartedLayout from "./GetStartedLayout";
import DashboardLayout from "./DashboardLayout/DashboardLayout";
import { DashboardAuth } from "./DashboardLayout";
export { HomeLayout, LetsGetStartedLayout, GetStartedLayout, DashboardLayout, DashboardAuth };
+19
View File
@@ -0,0 +1,19 @@
import React from "react";
import { HomeLayout } from "../layouts";
import { PersonalHero } from "../components";
const BusinessBankingPage: React.FC = () => {
return (
<HomeLayout>
<PersonalHero
heading="Business Account"
body="Open a personal or business account in minutes, tailored to your unique needs."
buttonLink="#"
buttonText="Click here"
/>
Business Banking
</HomeLayout>
);
};
export default BusinessBankingPage;
+19
View File
@@ -0,0 +1,19 @@
import React from "react";
import { HomeLayout } from "../layouts";
import { PersonalHero } from "../components";
const CooperateBankingPage: React.FC = () => {
return (
<HomeLayout>
<PersonalHero
heading="Cooperate Account"
body="Open a personal or business account in minutes, tailored to your unique needs."
buttonLink="#"
buttonText="Click here"
/>
Cooperate Banking
</HomeLayout>
);
};
export default CooperateBankingPage;
+9
View File
@@ -0,0 +1,9 @@
import { DashboardHome } from "../components"
export default function DashboardHomePage() {
return (
<div className=''>
<DashboardHome />
</div>
)
}
+5
View File
@@ -0,0 +1,5 @@
export default function DashboardLegalsPage() {
return (
<div>DashboardLegals</div>
)
}
+5
View File
@@ -0,0 +1,5 @@
export default function DashboardpaymentsPage() {
return (
<div>Dashboardpayments</div>
)
}
+9
View File
@@ -0,0 +1,9 @@
import { DashboardProfile } from "../components";
export default function DashboardProfilePage() {
return (
<>
<DashboardProfile />
</>
);
}
+5
View File
@@ -0,0 +1,5 @@
export default function DashboardVerificationPage() {
return (
<div>DashboardVerification</div>
)
}
+19 -4
View File
@@ -1,12 +1,27 @@
import React from "react";
import { GetStarted as Main, Header, Footer } from "../components";
import { GetStarted as Main } from "../components";
import { GetStartedLayout, LetsGetStartedLayout } from "../layouts";
import BVN from "../components/GetStarted/BVN";
const GetStartedPage: React.FC = () => {
const [step, setStep] = React.useState(1);
const handleNextStep = () => {
if (step < 5) {
setStep(step + 1);
}
};
return (
<>
<Header hideSidebar={true} hideMenu={true} />
<Main />
<Footer />
{step == 1 ?
<LetsGetStartedLayout>
<BVN handleNextStep={handleNextStep} />
</LetsGetStartedLayout>
:
<GetStartedLayout>
<Main step={step} handleNextStep={handleNextStep} />
</GetStartedLayout>
}
</>
);
};
+6 -7
View File
@@ -1,14 +1,13 @@
import { FC } from "react";
import { Hero, Header, TopHeader, Requirements } from "../components";
import React from "react";
import { Hero, Requirements } from "../components";
import { HomeLayout } from "../layouts";
const HomePage: FC = () => {
const HomePage: React.FC = () => {
return (
<>
<TopHeader />
<Header />
<HomeLayout>
<Hero />
<Requirements />
</>
</HomeLayout>
);
};
+10
View File
@@ -0,0 +1,10 @@
import React from 'react'
import { HomeLayout } from '../layouts'
const InternetBankingPage: React.FC = () => {
return (
<HomeLayout>InternetBankingPage</HomeLayout>
)
}
export default InternetBankingPage
+13
View File
@@ -0,0 +1,13 @@
import React from "react";
import { LetsGetStartedLayout } from "../layouts";
import { LetsGetStarted } from "../components";
const LetsGetStatedPage: React.FC = () => {
return (
<LetsGetStartedLayout>
<LetsGetStarted />
</LetsGetStartedLayout>
);
};
export default LetsGetStatedPage;
+19
View File
@@ -0,0 +1,19 @@
import React from "react";
import { HomeLayout } from "../layouts";
import { PersonalHero } from "../components";
const PersonalBankingPage: React.FC = () => {
return (
<HomeLayout>
<PersonalHero
heading="Personal Or Business Account"
body="Open a personal or business account in minutes, tailored to your unique needs."
buttonLink="#"
buttonText="Click here"
/>
Personal Banking
</HomeLayout>
);
};
export default PersonalBankingPage;
+13
View File
@@ -0,0 +1,13 @@
import React from "react";
import { HomeLayout } from "../layouts";
import { TsAndCs } from "../components";
const TermsAndConditionPage: React.FC = () => {
return (
<HomeLayout>
<TsAndCs />
</HomeLayout>
);
};
export default TermsAndConditionPage;
+25 -1
View File
@@ -1,5 +1,29 @@
import HomePage from "./HomePage";
import LoginPage from "./LoginPage";
import GetStartedPage from "./GetStartedPage";
import DashboardHomePage from "./DashboardHomePage";
import DashboardLegalsPage from "./DashboardLegalsPage";
import DashboardProfilePage from "./DashboardProfilePage";
import DashboardVerificationPage from "./DashboardVerificationPage";
import DashboardpaymentsPage from "./DashboardPaymentsPage";
import TermsAndConditionPage from "./TermsAndConditionPage";
import PersonalBankingPage from "./PersonalBankingPage";
import BusinessBankingPage from "./BusinessBankingPage";
import CooperateBankingPage from "./CooperateBankingPage";
import LetsGetStatedPage from "./LetsGetStatedPage";
export {HomePage, LoginPage, GetStartedPage}
export {
HomePage,
LoginPage,
GetStartedPage,
DashboardHomePage,
DashboardLegalsPage,
DashboardProfilePage,
DashboardVerificationPage,
DashboardpaymentsPage,
TermsAndConditionPage,
PersonalBankingPage,
BusinessBankingPage,
CooperateBankingPage,
LetsGetStatedPage
};
+61 -1
View File
@@ -1,6 +1,21 @@
import { Route, Routes } from "react-router-dom";
import { RouteHandler } from "./routes";
import { GetStartedPage, HomePage, LoginPage } from "../pages";
import {
GetStartedPage,
HomePage,
LoginPage,
DashboardHomePage,
DashboardLegalsPage,
DashboardProfilePage,
DashboardVerificationPage,
DashboardpaymentsPage,
TermsAndConditionPage,
BusinessBankingPage,
CooperateBankingPage,
PersonalBankingPage,
LetsGetStatedPage,
} from "../pages";
import { DashboardAuth } from "../layouts";
const Routers = () => {
return (
@@ -8,6 +23,51 @@ const Routers = () => {
<Route path={RouteHandler.homepage} element={<HomePage />} />
<Route path={RouteHandler.loginpage} element={<LoginPage />} />
<Route path={RouteHandler.getStarted} element={<GetStartedPage />} />
<Route
path={RouteHandler.termsAndConditions}
element={<TermsAndConditionPage />}
/>
<Route
path={RouteHandler.businessBanking}
element={<BusinessBankingPage />}
/>
<Route
path={RouteHandler.cooperateBanking}
element={<CooperateBankingPage />}
/>
<Route
path={RouteHandler.personalBanking}
element={<PersonalBankingPage />}
/>
<Route
path={RouteHandler.letsGetStarted}
element={<LetsGetStatedPage />}
/>
{/* Dashboard */}
<Route element={<DashboardAuth />}>
<Route
path={RouteHandler.dashboardHome}
element={<DashboardHomePage />}
/>
<Route
path={RouteHandler.dashboardProfile}
element={<DashboardProfilePage />}
/>
<Route
path={RouteHandler.dashboardVerification}
element={<DashboardVerificationPage />}
/>
<Route
path={RouteHandler.dashboardPayments}
element={<DashboardpaymentsPage />}
/>
<Route
path={RouteHandler.dashboardLegals}
element={<DashboardLegalsPage />}
/>
</Route>
<Route path="*" element={<>Error Page</>} />
</Routes>
);
};
+14 -4
View File
@@ -1,5 +1,15 @@
export class RouteHandler {
static homepage = "/"
static loginpage = '/login'
static getStarted = "/get-started"
}
static homepage = "/";
static loginpage = "/login";
static personalBanking = "/personal-banking";
static businessBanking = "/business-banking";
static cooperateBanking = "/cooperate-banking";
static letsGetStarted = "/lets-get-started";
static getStarted = "/get-started";
static dashboardHome = "/dashboard/home";
static dashboardProfile = "/dashboard/profile";
static dashboardVerification = "/dashboard/verification";
static dashboardPayments = "/dashboard/payments";
static dashboardLegals = "/dashboard/legals";
static termsAndConditions = "/terms-and-conditions";
}

Some files were not shown because too many files have changed in this diff Show More