Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 263c6740c5 | |||
| 07c1a8ae06 | |||
| bc2167e67a | |||
| 4d6a7380bb | |||
| b203c59ff7 | |||
| fe2168ce53 | |||
| 1c1af302aa | |||
| 945a5425f0 | |||
| 25545ad47e | |||
| 5efc935f05 | |||
| 69c43e1d88 | |||
| cb23cbd57c | |||
| 9c8e7dada4 | |||
| 22814f7e10 | |||
| bc9e26aad1 | |||
| 5cacd0f073 | |||
| 475e5c46a1 | |||
| 4af2f7ef10 |
@@ -0,0 +1,17 @@
|
||||
type Props = {
|
||||
width?: string
|
||||
height?: string
|
||||
}
|
||||
|
||||
export default function CustomSpinner({width='w-6', height='h-6'}:Props) {
|
||||
|
||||
return (
|
||||
<div role="status">
|
||||
<svg aria-hidden="true" className={`inline ${width} ${height} text-gray-200 animate-spin dark:text-gray-600 fill-blue-600`} viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
|
||||
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
|
||||
</svg>
|
||||
{/* <span className="sr-only">Loading...</span> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
import React, { FC, useState, useEffect } from 'react';
|
||||
import NairaBag from '../../assets/images/dashboard/naira-bag.png';
|
||||
import {useNavigate} from 'react-router-dom'
|
||||
import { Button, Icons } from '../';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PendingList from '../paginated-list/PendingList';
|
||||
import { PendingTableList } from '../../core/models';
|
||||
import { NewDateTimeFormatter } from '../../lib/NewDateTimeFormatter';
|
||||
import { getUserPendingLoanList } from '../../core/apiRequest';
|
||||
import {FormatAmount} from '../../lib/FormatAmount'
|
||||
import PendingLoanPopout from './PendingLoanPopout';
|
||||
import { RouteHandler } from '../../router/routes';
|
||||
|
||||
export interface DashBoardCardProps {
|
||||
title?: string;
|
||||
@@ -77,15 +81,27 @@ interface DashboardHomeIntroProps {
|
||||
step?: number | string;
|
||||
}
|
||||
|
||||
interface PopoutProps<T> {
|
||||
show?: boolean
|
||||
data?: T
|
||||
}
|
||||
|
||||
const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({
|
||||
handleNextStep,
|
||||
step,
|
||||
}) => {
|
||||
|
||||
const navigate = useNavigate()
|
||||
const { userDetails } = useSelector((state: any) => state?.userDetails); // CHECKS IF USER Details are avaliable
|
||||
|
||||
const [loanPopout, setLoanPopout] = useState<PopoutProps<PendingTableList>>({show:false, data:{}})
|
||||
const closePopout = () => {
|
||||
setLoanPopout({show:false, data:{}})
|
||||
}
|
||||
|
||||
const [userLoanList, setUserLoanList] = useState<{
|
||||
loading: boolean;
|
||||
data: PendingTableList;
|
||||
data: Array<PendingTableList>;
|
||||
}>({ loading: true, data: [] });
|
||||
|
||||
useEffect(() => {
|
||||
@@ -96,8 +112,6 @@ const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({
|
||||
}
|
||||
getUserPendingLoanList(uid)
|
||||
.then((res) => {
|
||||
console.log('RES', res);
|
||||
console.log('RES', userLoanList);
|
||||
if (!res || !res.data.loans) {
|
||||
setUserLoanList({ loading: false, data: [] });
|
||||
return;
|
||||
@@ -105,106 +119,115 @@ const DashboardHomeIntro: FC<DashboardHomeIntroProps> = ({
|
||||
setUserLoanList({ loading: false, data: res?.data?.loans });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
setUserLoanList({ loading: false, data: [] });
|
||||
console.log(err)
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
{step == 1 ? (
|
||||
<>
|
||||
<h1 className="font-bold my-5 text-2xl">
|
||||
Hello, {userDetails.firstname}
|
||||
</h1>
|
||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Begin your application and get up to "
|
||||
descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
descSpanClass="font-bold"
|
||||
btnTitle="Apply here"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
onClick={() => handleNextStep({})}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1 className="font-bold my-5 text-2xl">
|
||||
Welcome Back, {userDetails.firstname}
|
||||
</h1>
|
||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Your loan application has been reviewed and accepted, please confirm for disbursement."
|
||||
// descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
// descSpanClass="font-bold"
|
||||
btnTitle="View and accept"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
// onClick={handleNextStep}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{userLoanList.loading ? null : (
|
||||
<div className="mt-5 w-full">
|
||||
<PendingList
|
||||
data={userLoanList.data}
|
||||
itemsPerPage={5}
|
||||
tableTitle="Current Applications"
|
||||
>
|
||||
{(data: any) => (
|
||||
<div className="w-full p-4 rounded-lg shadow-lg bg-white overflow-x-auto min-h-[250px] max-h-[450px]">
|
||||
<table className="text-[12px] sm:text-base w-full table-auto">
|
||||
<thead>
|
||||
<tr className="text-left border-b-2">
|
||||
<th className="px-1 py-4">Date</th>
|
||||
<th className="px-1 py-4 text-right">Amount</th>
|
||||
<th className="px-1 py-4 text-center min-w-[110px]">
|
||||
Payment Term
|
||||
</th>
|
||||
<th className="px-1 py-4 text-center">Status</th>
|
||||
<th className="px-1 py-4 text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((item: any, index: any) => (
|
||||
<tr key={index || item} className="even:bg-slate-100">
|
||||
<td className="px-1 py-2">
|
||||
{NewDateTimeFormatter(item?.added)}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-right">
|
||||
{item?.loan_amount}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-center">
|
||||
{item?.payment_month}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-center">
|
||||
{item?.status}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-right">
|
||||
<button className="px-2 py-1 border-2 border-black">
|
||||
View
|
||||
<Icons name="arrow-right" />
|
||||
</button>
|
||||
</td>
|
||||
<>
|
||||
<div className="w-full">
|
||||
{step == 1 ? (
|
||||
<>
|
||||
<h1 className="font-bold my-5 text-2xl">
|
||||
Hello, {userDetails.firstname}
|
||||
</h1>
|
||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Begin your application and get up to "
|
||||
descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
descSpanClass="font-bold"
|
||||
btnTitle="Apply here"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
onClick={() => handleNextStep({})}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1 className="font-bold my-5 text-2xl">
|
||||
Welcome Back, {userDetails.firstname}
|
||||
</h1>
|
||||
<div className="group w-full lg:w-[27.8125rem] h-[12.75rem] mt-7 ">
|
||||
<DashBoardCard
|
||||
cardClass="bg-[#5C2684] relative"
|
||||
desc="Your loan application has been reviewed and accepted, please confirm for disbursement."
|
||||
// descSpan="5 million naira loan."
|
||||
descClass="leading-[1.5625rem] text-lg text-white"
|
||||
// descSpanClass="font-bold"
|
||||
btnTitle="View and accept"
|
||||
btnTextClass="w-[11.125rem] h-[2.8125rem] flex justify-center item-center btn-W text-[#FBB700]"
|
||||
image={NairaBag}
|
||||
imgClass="translate-y-4 -rotate-6"
|
||||
// onClick={handleNextStep}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{userLoanList.loading ? null : (
|
||||
<div className="mt-5 w-full">
|
||||
<PendingList
|
||||
data={userLoanList.data}
|
||||
itemsPerPage={5}
|
||||
tableTitle="Current Applications"
|
||||
>
|
||||
{(data: any) => (
|
||||
<div className="w-full p-4 rounded-lg shadow-lg bg-white overflow-x-auto min-h-[250px] max-h-[450px]">
|
||||
<table className="text-[12px] sm:text-base w-full table-auto">
|
||||
<thead>
|
||||
<tr className="text-left border-b-2">
|
||||
<th className="px-1 py-4">Date</th>
|
||||
<th className="px-1 py-4 text-right">Amount</th>
|
||||
<th className="px-1 py-4 text-center min-w-[110px]">
|
||||
Payment Term
|
||||
</th>
|
||||
<th className="px-1 py-4 text-center">Status</th>
|
||||
<th className="px-1 py-4 text-right">Action</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</PendingList>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((item: any, index: any) => (
|
||||
<tr key={index || item} className="even:bg-slate-100">
|
||||
<td className="px-1 py-2">
|
||||
{NewDateTimeFormatter(item?.added)}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-right">
|
||||
{FormatAmount(item?.loan_amount)}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-center">
|
||||
{item?.payment_month}
|
||||
</td>
|
||||
<td className="px-1 py-2 text-center">
|
||||
<button
|
||||
className={`${!item?.status_text?.button && 'pointer-events-none border-0'} border p-2`}
|
||||
onClick={()=>setLoanPopout({show:true, data:item})}
|
||||
>
|
||||
{item?.status_text?.text || 'Pending'}
|
||||
</button>
|
||||
</td>
|
||||
<td className="flex justify-end px-1 py-2 text-right">
|
||||
<button className="flex flex-nowrap items-center px-2 py-1 border-2 border-black" onClick={()=>navigate(RouteHandler.dashboardPayments, {state:{application_uid: item?.application_uid}})}>
|
||||
View
|
||||
<Icons name="arrow-right" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</PendingList>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loanPopout.show && <PendingLoanPopout data={loanPopout.data} action={closePopout} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import {useState} from 'react'
|
||||
import ModalWrapper from '../modal/ModalWrapper'
|
||||
import { PendingTableList } from '../../core/models'
|
||||
import { NewDateTimeFormatter } from '../../lib/NewDateTimeFormatter'
|
||||
import { addCard } from '../../core/apiRequest'
|
||||
import CustomSpinner from '../CustomSpinner'
|
||||
|
||||
|
||||
interface Props<T> {
|
||||
action: ()=>void
|
||||
data?: T
|
||||
}
|
||||
|
||||
export default function PendingLoanPopout({data, action}:Props<PendingTableList>) {
|
||||
console.log('MUMU', data)
|
||||
|
||||
const [addCardStatus, setAddCardStatus] = useState<{
|
||||
loading: boolean;
|
||||
status: boolean
|
||||
msg: string
|
||||
}>({ loading: false, status: false, msg: ''});
|
||||
|
||||
const handleAddCard = (appID:string | undefined) => {
|
||||
let reqData = {
|
||||
application_uid: appID
|
||||
|
||||
}
|
||||
setAddCardStatus({ loading: true, status: false, msg: ''})
|
||||
addCard(reqData).then(res => {
|
||||
if(res?.data?.call_return != '100'){
|
||||
setAddCardStatus({ loading: false, status: false, msg: 'failed to add card'})
|
||||
setTimeout(()=>{
|
||||
setAddCardStatus({ loading: false, status: false, msg: ''})
|
||||
},3000)
|
||||
}
|
||||
window.location.href = res?.data?.redirect_url
|
||||
setAddCardStatus({ loading: false, status: true, msg: 'card added'})
|
||||
action() // TO CLOSE MODAL
|
||||
}).catch(err => {
|
||||
setAddCardStatus({ loading: false, status: false, msg: 'failed to add card'})
|
||||
console.log('ERR', err)
|
||||
setTimeout(()=>{
|
||||
setAddCardStatus({ loading: false, status: false, msg: ''})
|
||||
},3000)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<ModalWrapper>
|
||||
<div className='modal-container'>
|
||||
<div className='modal-header'>
|
||||
<h1 className='modal-title'>Add Card</h1>
|
||||
<button
|
||||
type="button"
|
||||
className="modal-close-btn"
|
||||
name='cancel'
|
||||
onClick={action}
|
||||
>
|
||||
<svg
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 36 36"
|
||||
fill="none"
|
||||
className="fill-current"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M36 16.16C36 17.4399 36 18.7199 36 20.0001C35.7911 20.0709 35.8636 20.2554 35.8385 20.4001C34.5321 27.9453 30.246 32.9248 22.9603 35.2822C21.9006 35.6251 20.7753 35.7657 19.6802 35.9997C18.4003 35.9997 17.1204 35.9997 15.8401 35.9997C15.5896 35.7086 15.2189 35.7732 14.9034 35.7093C7.77231 34.2621 3.08728 30.0725 0.769671 23.187C0.435002 22.1926 0.445997 21.1199 0 20.1599C0 18.7198 0 17.2798 0 15.8398C0.291376 15.6195 0.214408 15.2656 0.270759 14.9808C1.71321 7.69774 6.02611 2.99691 13.0428 0.700951C14.0118 0.383805 15.0509 0.386897 15.9999 0C17.2265 0 18.4532 0 19.6799 0C19.7156 0.124041 19.8125 0.136067 19.9225 0.146719C27.3 0.868973 33.5322 6.21922 35.3801 13.427C35.6121 14.3313 35.7945 15.2484 36 16.16ZM33.011 18.0787C33.0433 9.77105 26.3423 3.00309 18.077 2.9945C9.78479 2.98626 3.00344 9.658 2.98523 17.8426C2.96667 26.1633 9.58859 32.9601 17.7602 33.0079C26.197 33.0577 32.9787 26.4186 33.011 18.0787Z"
|
||||
fill=""
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
<path
|
||||
d="M15.9309 18.023C13.9329 16.037 12.007 14.1207 10.0787 12.2072C9.60071 11.733 9.26398 11.2162 9.51996 10.506C9.945 9.32677 11.1954 9.0811 12.1437 10.0174C13.9067 11.7585 15.6766 13.494 17.385 15.2879C17.9108 15.8401 18.1633 15.7487 18.6375 15.258C20.3586 13.4761 22.1199 11.7327 23.8822 9.99096C24.8175 9.06632 26.1095 9.33639 26.4967 10.517C26.7286 11.2241 26.3919 11.7413 25.9133 12.2178C24.1757 13.9472 22.4477 15.6855 20.7104 17.4148C20.5228 17.6018 20.2964 17.7495 20.0466 17.9485C22.0831 19.974 24.0372 21.8992 25.9689 23.8468C26.9262 24.8119 26.6489 26.1101 25.4336 26.4987C24.712 26.7292 24.2131 26.3441 23.7455 25.8757C21.9945 24.1227 20.2232 22.3892 18.5045 20.6049C18.0698 20.1534 17.8716 20.2269 17.4802 20.6282C15.732 22.4215 13.9493 24.1807 12.1777 25.951C11.7022 26.4262 11.193 26.7471 10.4738 26.4537C9.31345 25.9798 9.06881 24.8398 9.98589 23.8952C11.285 22.5576 12.6138 21.2484 13.9387 19.9355C14.5792 19.3005 15.2399 18.6852 15.9309 18.023Z"
|
||||
fill="#"
|
||||
fillOpacity="0.6"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className='modal-body'>
|
||||
<div className='w-full flex flex-col gap-2'>
|
||||
<div className='py-2 w-full flex gap-1'>
|
||||
<p className='font-semibold'>ID :</p>
|
||||
<p>{data?.application_uid}</p>
|
||||
</div>
|
||||
<div className='py-2 w-full flex gap-1'>
|
||||
<p className='font-semibold'>Loan Amount :</p>
|
||||
<p>{data?.loan_amount}</p>
|
||||
</div>
|
||||
<div className='py-2 w-full flex gap-1'>
|
||||
<p className='font-semibold'>Payment Month :</p>
|
||||
<p>{data?.payment_month}</p>
|
||||
</div>
|
||||
<div className='py-2 w-full flex gap-1'>
|
||||
<p className='font-semibold'>Added :</p>
|
||||
<p>{NewDateTimeFormatter(data?.added)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='modal-footer'>
|
||||
<button onClick={action} name='cancel' className='custom-btn text-red-500 border border-red-500 hover:text-red-700'>Cancel</button>
|
||||
{addCardStatus.loading ?
|
||||
<CustomSpinner width='w-6' height='h-6' />
|
||||
:
|
||||
<button onClick={()=>handleAddCard(data?.application_uid)} name='proceed' className={`custom-btn border border-sky-500 text-sky-500 hover:text-sky-700 ${addCardStatus.loading && 'opacity-20 pointer-events-none'}`}>Add Card</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
import {useState, useEffect} from 'react'
|
||||
import { Button, InputCompOne } from '../../shared/index';
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
import { getEmployer } from '../../../core/apiRequest';
|
||||
import CustomSpinner from '../../CustomSpinner';
|
||||
import { FormatAmount } from '../../../lib/FormatAmount';
|
||||
|
||||
// type Props = {
|
||||
// handleNextStep?:(value:{})=>any
|
||||
// }
|
||||
|
||||
// type EmployerProps = {
|
||||
// loading?: boolean,
|
||||
// data?: Array<{[index:string]: string}> | {[index:string]: Array<{[index:string]: string}> }
|
||||
// }
|
||||
|
||||
const initialValues = {
|
||||
job_title: "",
|
||||
name: "",
|
||||
job_sector: "",
|
||||
industry: "",
|
||||
start_date: "",
|
||||
official_email:"",
|
||||
annual_salary: "",
|
||||
net_montlty: "",
|
||||
salary_date: "",
|
||||
employee_id: "",
|
||||
highest_eductaion: "",
|
||||
employer_uid: "",
|
||||
isChecked: true
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
isChecked: Yup.bool(), // use bool instead of boolean
|
||||
// .oneOf([true, false], "You must accept the terms and conditions"),
|
||||
job_title: Yup.string()
|
||||
.required("Required"),
|
||||
name: Yup.string().when('isChecked', {
|
||||
is: true,
|
||||
then: () => Yup.string().required('required'),
|
||||
otherwise: () => Yup.string(),
|
||||
}),
|
||||
job_sector: Yup.string().when('isChecked', {
|
||||
is: true,
|
||||
then: () => Yup.string().required('required'),
|
||||
}),
|
||||
industry: Yup.string().when('isChecked', {
|
||||
is: true,
|
||||
then: () => Yup.string().required('required'),
|
||||
}),
|
||||
start_date: Yup.string()
|
||||
.required("Required"),
|
||||
official_email : Yup.string().when('isChecked', {
|
||||
is: true,
|
||||
then: () => Yup.string().required('required'),
|
||||
})
|
||||
.email("Invalid"),
|
||||
annual_salary: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
net_montlty: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
salary_date: Yup.string()
|
||||
.required("Required"),
|
||||
employee_id: Yup.string()
|
||||
.required("Required"),
|
||||
highest_eductaion: Yup.string()
|
||||
.required("Required"),
|
||||
employer_uid: Yup.string().when('isChecked', {
|
||||
is: false,
|
||||
then: () => Yup.string().required('required'),
|
||||
}),
|
||||
});
|
||||
|
||||
export default function EmploymentDetail() {
|
||||
|
||||
const [employerList, setEmployerList] = useState<any>({
|
||||
loading: true,
|
||||
data: {}
|
||||
})
|
||||
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = () => {
|
||||
console.log('good')
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
getEmployer().then(res => {
|
||||
setEmployerList({loading:false, data:res?.data?.employer})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
setEmployerList({loading:false, data:{}})
|
||||
})
|
||||
},[])
|
||||
|
||||
const formInitialValue = (employerList.loading || Object.keys(employerList?.data)?.length < 1) ? initialValues : {...initialValues, ...employerList?.data}
|
||||
|
||||
return (
|
||||
<>
|
||||
{employerList.loading ?
|
||||
<div className='flex flex-col justify-center items-center h-96'>
|
||||
<CustomSpinner width='w-8' height='h-8' />
|
||||
</div>
|
||||
:
|
||||
<div className="w-full">
|
||||
<Formik
|
||||
initialValues={formInitialValue}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props)=>(
|
||||
<Form>
|
||||
<div className="mt-[3.25rem] flex flex-col gap-9">
|
||||
<p className='text-red-500 text-lg md:text-2xl'>Employment Informaton</p>
|
||||
<div className="flex flex-col lg:flex-row items-start gap-[2rem]">
|
||||
<div className='w-full lg:max-w-[30rem] flex flex-col'>
|
||||
{/* <div className='w-full gap-[2rem]'>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="employer_uid"
|
||||
floatLabel="Employer Name"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={{loading:employersList?.loading, data: employersList?.data?.records}}
|
||||
selectValue={props.values.employer_uid}
|
||||
onChange={props.handleChange}
|
||||
error={(props.errors.employer_uid && props.touched.employer_uid) ? props.errors.employer_uid : ''}
|
||||
disabled={props.values.isChecked}
|
||||
/>
|
||||
<div className='flex gap-4 items-start my-2'>
|
||||
<input
|
||||
type='checkbox'
|
||||
name="isChecked"
|
||||
className='w-4 h-4 p-2 accent-purple-600 text-purple-600 bg-gray-100 border-gray-300 rounded focus:ring-purple-500'
|
||||
onChange={props.handleChange}
|
||||
checked={props.values.isChecked}
|
||||
/>
|
||||
<p className='text-[12px] text-justify'>Check here if employer is not on the list</p>
|
||||
</div>
|
||||
<div className={`hidden p-4 ${props.values.isChecked && 'hidden'}`}>
|
||||
Name: {'Name'}
|
||||
</div>
|
||||
</div> */}
|
||||
<div className={`w-full flex flex-col gap-[2rem] ${!props.values.isChecked && 'hidden'}`}>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="name"
|
||||
floatLabel="Employer name"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="Mr. Mark John"
|
||||
value={props.values.name}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.name && props.touched.name) ? props.errors.name : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="official_email"
|
||||
floatLabel="Employers official email"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="example@gmail.com"
|
||||
value={props.values.official_email}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.official_email && props.touched.official_email) ? props.errors.official_email : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="industry"
|
||||
floatLabel="Select your industry"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
disabled={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={props.values.industry}
|
||||
selectValue={props.values.industry}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.industry && props.touched.industry) ? props.errors.industry : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="job_sector"
|
||||
floatLabel="Job Sector"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
disabled={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={props.values.job_sector}
|
||||
selectValue={props.values.job_sector}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.job_sector && props.touched.job_sector) ? props.errors.job_sector : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='w-full lg:max-w-[30rem] flex flex-col gap-[2rem]'>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="job_title"
|
||||
floatLabel="Job Title"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="Software Engineer"
|
||||
value={props.values.job_title}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.job_title && props.touched.job_title) ? props.errors.job_title : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="highest_eductaion"
|
||||
floatLabel="Highest level of education"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
disabled={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={props.values.highest_eductaion}
|
||||
selectValue={props.values.highest_eductaion}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.highest_eductaion && props.touched.highest_eductaion) ? props.errors.highest_eductaion : ''}
|
||||
/>
|
||||
<div className="w-full flex flex-col sm:flex-row items-center gap-4">
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="start_date"
|
||||
floatLabel="Date of resumption"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputType='text'
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="12/12/2015"
|
||||
value={props.values.start_date}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.start_date && props.touched.start_date) ? props.errors.start_date : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="salary_date"
|
||||
floatLabel="Salary payment date"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputType='text'
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="30th of every month"
|
||||
value={(props.values.salary_date)}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.salary_date && props.touched.salary_date) ? props.errors.salary_date : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full flex flex-col sm:flex-row items-center gap-4">
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="annual_salary"
|
||||
floatLabel="Annual Income"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
|
||||
placeholder="1,200,000"
|
||||
value={FormatAmount(props.values.annual_salary)}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.annual_salary && props.touched.annual_salary) ? props.errors.annual_salary : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="net_montlty"
|
||||
floatLabel="Net monthly salary"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
|
||||
placeholder="100,000"
|
||||
value={FormatAmount(props.values.net_montlty)}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.net_montlty && props.touched.net_montlty) ? props.errors.net_montlty : ''}
|
||||
/>
|
||||
</div>
|
||||
<InputCompOne
|
||||
parentClass="w-full"
|
||||
name="employee_id"
|
||||
floatLabel="Employee ID"
|
||||
// labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
disabled={true}
|
||||
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 className="hidden w-full">
|
||||
<Button
|
||||
className="my-4 btn-Y text-black w-full h-11"
|
||||
text="Next"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// interface SelectOption {
|
||||
// loading: boolean;
|
||||
// data: {value: string;
|
||||
// label: string}[]
|
||||
// }
|
||||
|
||||
|
||||
// const jobSector: SelectOption = {
|
||||
// loading: false,
|
||||
// data: [
|
||||
// { value: "", label: "Please Select" },
|
||||
// { value: "private (non academic)", label: "Private (non academic)" },
|
||||
// ]
|
||||
// }
|
||||
|
||||
// const industry: SelectOption = {
|
||||
// loading: false,
|
||||
// data: [
|
||||
// { value: "", label: "Please Select" },
|
||||
// { value: "engineering", label: "Engineering" },
|
||||
// ]
|
||||
// }
|
||||
|
||||
// const highestEductaion: SelectOption = {
|
||||
// loading: false,
|
||||
// data: [
|
||||
// { value: "", label: "Please Select" },
|
||||
// { value: "b.sc + professional qualification", label: "B.Sc + Professional Qualification" },
|
||||
// ]
|
||||
// }
|
||||
@@ -32,10 +32,9 @@ export default function DashboardHomeAttestation({handleNextStep, applicationDet
|
||||
//FUNCTION TO HANDLE LOAN APPLICATION
|
||||
const handleSubmit = (values:any) => {
|
||||
delete values.checked
|
||||
applyForLoan({...applicationDetails, disbursement: values}).then(res=>{
|
||||
applyForLoan({...applicationDetails,disbursement_account: values?.account, disbursement: values}).then(res=>{
|
||||
console.log('APPLY FOR LOAN', res)
|
||||
handleNextStep({disbursement: values})
|
||||
console.log('ApplicationDetails', {...applicationDetails, disbursement: values})
|
||||
}).catch(err=>{
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Button, InputCompOne, Stepper } from '../../shared/index';
|
||||
|
||||
import { state } from '../../../utils/states';
|
||||
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
|
||||
@@ -13,7 +15,7 @@ const initialValues = {
|
||||
marital_status: "",
|
||||
state: "",
|
||||
email:"",
|
||||
country:""
|
||||
country:"NG"
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
@@ -171,16 +173,6 @@ const maritalStatus: SelectOption = {
|
||||
]
|
||||
}
|
||||
|
||||
const state: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Please Select" },
|
||||
{ value: "abia", label: "Abia" },
|
||||
{ value: "imo", label: "Imo" },
|
||||
{ value: "lagos", label: "Lagos" },
|
||||
]
|
||||
}
|
||||
|
||||
const country: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
import {useEffect, useState} from 'react'
|
||||
import {useLocation, useNavigate} from 'react-router-dom'
|
||||
import { Button, InputCompOne } from "../../shared";
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
import { RouteHandler } from '../../../router/routes';
|
||||
import { getLoanDetail } from '../../../core/apiRequest';
|
||||
import CustomSpinner from '../../CustomSpinner';
|
||||
|
||||
interface LoanDetail {
|
||||
loan_amount: string;
|
||||
payment_month: string;
|
||||
sales_agent: string;
|
||||
[key: string]: any; // to accommodate any additional properties
|
||||
}
|
||||
|
||||
// interface InitialValues {
|
||||
// loan_amount: string;
|
||||
// payment_month: string;
|
||||
// sales_agent: string;
|
||||
// }
|
||||
|
||||
const initialValues = {
|
||||
loan_amount: "",
|
||||
payment_month: "",
|
||||
sales_agent: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
payment_month: Yup.string()
|
||||
.required("Required"),
|
||||
loan_amount: Yup.string()
|
||||
.required("Required")
|
||||
.test("no-e", "Invalid", (value:any) => {
|
||||
if (value && /^[0-9]*$/.test(value) == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
sales_agent: Yup.string()
|
||||
});
|
||||
|
||||
type LocationState = {
|
||||
application_uid: string
|
||||
}
|
||||
|
||||
export default function ReferenceDetails() {
|
||||
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
// const applicationUID = location?.state?.application_uid
|
||||
const stateExist = location?.state as LocationState
|
||||
|
||||
//FUNCTION TO HANDLE SUBMIT
|
||||
const handleSubmit = (values:{}) => {
|
||||
// handleNextStep(values)
|
||||
console.log(values)
|
||||
};
|
||||
|
||||
const [loanDetail, setLoanDetail] = useState<{loading:boolean, data:LoanDetail}>({
|
||||
loading: true,
|
||||
data: {
|
||||
loan_amount: '',
|
||||
payment_month: '',
|
||||
sales_agent: '',
|
||||
},
|
||||
})
|
||||
useEffect(()=>{
|
||||
if(!stateExist){
|
||||
navigate(RouteHandler.dashboardHome)
|
||||
return
|
||||
}
|
||||
getLoanDetail({application_uid:stateExist.application_uid}).then(res => {
|
||||
setLoanDetail({loading:false, data:res?.data?.loan})
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
setLoanDetail((prev:any) => ({...prev, loading:false}))
|
||||
})
|
||||
},[])
|
||||
|
||||
// const formInitialValue:LoanDetail = (loanDetail.loading) ? initialValues : loanDetail?.data
|
||||
const formInitialValue = (loanDetail.loading || Object.keys(loanDetail?.data)?.length < 1) ? initialValues : {...initialValues, ...loanDetail?.data}
|
||||
|
||||
return (
|
||||
<>
|
||||
{loanDetail.loading ?
|
||||
<div className='flex flex-col justify-center items-center h-96'>
|
||||
<CustomSpinner width='w-8' height='h-8' />
|
||||
</div>
|
||||
:
|
||||
<div className="w-full">
|
||||
<Formik
|
||||
initialValues={formInitialValue}
|
||||
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'>Loan Details</p>
|
||||
<div className='w-full flex flex-wrap items-center gap-4'>
|
||||
<InputCompOne
|
||||
parentClass="w-full sm:max-w-[10rem] flex flex-col gap-4"
|
||||
name="loan_amount"
|
||||
label="Amount"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
input
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem] text-right"
|
||||
placeholder="350,000"
|
||||
value={props.values.loan_amount}
|
||||
disabled={true}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.loan_amount && props.touched.loan_amount) ? props.errors.loan_amount : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full sm:max-w-[10rem] flex flex-col gap-4"
|
||||
name="payment_month"
|
||||
label="Months?"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
select={true}
|
||||
disabled={true}
|
||||
selectClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
selectOptions={props.values.payment_month}
|
||||
selectValue={props.values.payment_month}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.payment_month && props.touched.payment_month) ? props.errors.payment_month : ''}
|
||||
/>
|
||||
<InputCompOne
|
||||
parentClass="w-full sm:max-w-[10rem] flex flex-col gap-4"
|
||||
name="sales_agent"
|
||||
label="agent ID"
|
||||
labelClass="font-bold text-[1.125rem]"
|
||||
floatLabel='Enter agent ID'
|
||||
input
|
||||
disabled={true}
|
||||
inputClass="w-full h-[3.625rem] bg-[#EFEFEF] px-4 rounded-[.375rem]"
|
||||
placeholder="Agent ID"
|
||||
value={props.values.sales_agent}
|
||||
onChange={props.handleChange}
|
||||
// error={(props.errors.sales_agent && props.touched.sales_agent) ? props.errors.sales_agent : ''}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className="hidden my-8 max-w-[25.875rem] btn-Y text-black w-full h-11"
|
||||
text="Next"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// interface SelectOption {
|
||||
// loading: boolean;
|
||||
// data: {value: string;
|
||||
// label: string}[]
|
||||
// }
|
||||
|
||||
|
||||
// const paymentMonth: SelectOption = {
|
||||
// loading: false,
|
||||
// data: [
|
||||
// { value: "", label: "Please Select" },
|
||||
// { value: "6", label: "6 Months" },
|
||||
// { value: "12", label: "12 Months" },
|
||||
// { value: "18", label: "18 Months" },
|
||||
// { value: "24", label: "24 Months" },
|
||||
// ]
|
||||
// }
|
||||
@@ -0,0 +1,5 @@
|
||||
export default function Payment() {
|
||||
return (
|
||||
<div>Payment Page</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ReactNode } from "react"
|
||||
|
||||
type Props = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default function ModalWrapper({children}:Props) {
|
||||
return (
|
||||
<div className="z-50 fixed inset-0">
|
||||
<div className="bg-black/50 fixed inset-0"></div>
|
||||
<div className="relative h-full flex flex-col justify-center items-center">{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { ReactNode, useEffect, useState } from "react";
|
||||
import { PendingTableList } from "../../core/models";
|
||||
|
||||
type PaginatedListProps = {
|
||||
data: PendingTableList,
|
||||
data: Array<PendingTableList>,
|
||||
itemsPerPage?: number,
|
||||
filterItem?: string[],
|
||||
tableTitle?: string,
|
||||
@@ -28,12 +28,12 @@ export default function PendingList({
|
||||
|
||||
const handlePrev = () => {
|
||||
if (currentPage != 0) {
|
||||
setCurrentPage((prev) => prev - numberOfSelection);
|
||||
setCurrentPage((prev:any) => prev - numberOfSelection);
|
||||
}
|
||||
};
|
||||
const handleNext = () => {
|
||||
if (currentPage < data.length) {
|
||||
setCurrentPage((prev) => prev + numberOfSelection);
|
||||
setCurrentPage((prev:any) => prev + numberOfSelection);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export interface InputCompOneProps {
|
||||
selectValue?: string;
|
||||
input?: boolean;
|
||||
select?: boolean;
|
||||
selectOptions?: {loading:boolean, data:{ [index: string]: string; }[]};
|
||||
selectOptions?: {loading:boolean, data:{ [index: string]: string; }[]} | any;
|
||||
inputType?: string;
|
||||
inputClass?: string;
|
||||
parentInputClass?: string;
|
||||
@@ -103,19 +103,21 @@ const InputCompOne = forwardRef<HTMLInputElement, InputCompOneProps>(
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
>
|
||||
{selectOptions.loading ?
|
||||
{typeof(selectOptions) == 'string' ?
|
||||
<option value={selectValue}>{selectValue}</option>
|
||||
:selectOptions.loading ?
|
||||
<option value=''>Loading...</option>
|
||||
: selectOptions.data.length && name == 'employer_uid' ?
|
||||
<>
|
||||
<option value=''>Please Select</option>
|
||||
{selectOptions.data.map(({ uid, name }) => (
|
||||
{selectOptions.data.map(({ uid, name }:any) => (
|
||||
<option key={uid} value={uid}>
|
||||
{name}
|
||||
</option>
|
||||
))}
|
||||
</>
|
||||
: selectOptions.data.length && name != 'employer_uid' ?
|
||||
selectOptions.data.map(({ value, label }) => (
|
||||
selectOptions.data.map(({ value, label }:any) => (
|
||||
<option key={value} value={value}>
|
||||
{label}
|
||||
</option>
|
||||
|
||||
@@ -48,4 +48,30 @@ export const getEmployersList = () => {
|
||||
// customer_uid: localStorage.getItem('uid'),
|
||||
}
|
||||
return getAuxEnd(`/employers`, reqData)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET USER EMPLOYER
|
||||
export const getEmployer = () => {
|
||||
let reqData = {
|
||||
uid: localStorage.getItem('uid'),
|
||||
}
|
||||
return getAuxEnd(`/dash/employer?uid=${reqData?.uid}`, null)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET LOAN DETAILS
|
||||
export const getLoanDetail = (postData:any) => {
|
||||
let reqData = {
|
||||
uid: localStorage.getItem('uid'),
|
||||
...postData
|
||||
}
|
||||
return getAuxEnd(`/loan/loandetail?uid=${reqData?.uid}&application_uid=${reqData?.application_uid}`, null)
|
||||
}
|
||||
|
||||
// FUNCTION TO ADD CARD
|
||||
export const addCard = (postData:any) => {
|
||||
let reqData = {
|
||||
uid: localStorage.getItem('uid'),
|
||||
...postData
|
||||
}
|
||||
return postAuxEnd('/addcard', reqData)
|
||||
}
|
||||
@@ -10,8 +10,8 @@ export function postAuxEnd(uri: string, reqData: any): Promise<any> {
|
||||
// console.log('SAMPLE',innerReqData)
|
||||
// formData.append(reqData[value][innerValue], reqData[value][innerValue]);
|
||||
// }
|
||||
// formData.append(value, JSON.stringify(reqData[value]));
|
||||
formData.append(value, reqData[value]);
|
||||
formData.append(value, JSON.stringify(reqData[value]));
|
||||
// formData.append(value, reqData[value]);
|
||||
} else {
|
||||
formData.append(value, reqData[value]);
|
||||
}
|
||||
|
||||
+8
-3
@@ -19,9 +19,14 @@ export interface User {
|
||||
|
||||
|
||||
export type PendingTableList = {
|
||||
status?: string | boolean;
|
||||
status?: string | boolean
|
||||
application_uid?: string
|
||||
added?: string
|
||||
loan_amount?: string
|
||||
payment_month?: string
|
||||
}[];
|
||||
payment_month?: string
|
||||
status_text?: {
|
||||
text?: string
|
||||
button?: boolean
|
||||
advise?: string
|
||||
}
|
||||
};
|
||||
@@ -17,4 +17,33 @@ body {
|
||||
/* @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]
|
||||
}
|
||||
|
||||
.custom-btn{@apply min-w-[100px] transition-all duration-300 p-2 rounded-full}
|
||||
|
||||
|
||||
/* MODAL COMPONENT */
|
||||
.modal-container{
|
||||
animation-name: zoom;
|
||||
animation-duration: .2s;
|
||||
animation-timing-function: linear;
|
||||
@apply w-4/5 max-w-[600px] bg-white shadow-md rounded-2xl overflow-hidden
|
||||
}
|
||||
.modal-header {
|
||||
@apply w-full flex items-center justify-between p-5 py-8 border-b bg-sky-500
|
||||
}
|
||||
.modal-title {
|
||||
@apply text-2xl leading-8 font-bold text-white dark:text-white tracking-wide flex items-center
|
||||
}
|
||||
.modal-close-btn {
|
||||
@apply text-white dark:text-red-500
|
||||
}
|
||||
.modal-body {
|
||||
@apply w-full p-5 min-h-[150px] max-h-[500px] overflow-y-auto break-words flex flex-col justify-center items-center
|
||||
}
|
||||
.modal-footer {
|
||||
@apply w-full p-5 border-t flex justify-between items-center gap-4
|
||||
}
|
||||
/* MODAL COMPONENT */
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// FUNCTION TO RETURN AMOUNT TO TWO DECIMAL PLACES
|
||||
export const FormatAmount = (
|
||||
amount = "00",
|
||||
) => {
|
||||
// Convert the number to a string
|
||||
let numStr = String(amount);
|
||||
|
||||
// Split the string into integer and decimal parts
|
||||
let parts = numStr.split(".");
|
||||
let integerPart = parts[0] || "";
|
||||
let decimalPart = parts[1] || "";
|
||||
|
||||
// Add thousands separators to the integer part
|
||||
let formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
|
||||
// Truncate or pad the decimal part to two decimal points
|
||||
let formattedDecimal = decimalPart.slice(0, 2).padEnd(2, "0");
|
||||
|
||||
// Combine the formatted integer and decimal parts
|
||||
let formattedNumber = '₦' + formattedInteger + '.' + formattedDecimal;
|
||||
|
||||
// return formattedNumber;
|
||||
return formattedNumber;
|
||||
};
|
||||
@@ -1,5 +1,9 @@
|
||||
import ReferenceDetails from "../components/Dashboard/referenceDetails/ReferenceDetails";
|
||||
|
||||
export default function DashboardpaymentsPage() {
|
||||
return (
|
||||
<div>Dashboardpayments</div>
|
||||
<>
|
||||
<ReferenceDetails />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import EmploymentDetail from "../components/Dashboard/employmentDetails/EmploymentDetails";
|
||||
|
||||
export default function DashboardVerificationPage() {
|
||||
return (
|
||||
<div>DashboardVerification</div>
|
||||
<>
|
||||
<EmploymentDetail />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import {useEffect} from 'react'
|
||||
import {useLocation, useNavigate} from 'react-router-dom'
|
||||
import Payment from '../components/Payment/Payment'
|
||||
import { RouteHandler } from '../router/routes'
|
||||
|
||||
export default function PaymentPage() {
|
||||
const location = useLocation()
|
||||
const navigate = useNavigate()
|
||||
const queryParams = new URLSearchParams(location?.search);
|
||||
const trxRef = queryParams.get("trxref");
|
||||
const reference = queryParams.get("reference");
|
||||
console.log('LOC', trxRef, reference)
|
||||
|
||||
useEffect(()=>{
|
||||
if(!trxRef || !reference){
|
||||
navigate(RouteHandler.dashboardHome, {replace:true})
|
||||
}
|
||||
},[])
|
||||
return (
|
||||
<>
|
||||
<Payment />
|
||||
</>
|
||||
)
|
||||
}
|
||||
+3
-1
@@ -11,6 +11,7 @@ import PersonalBankingPage from "./PersonalBankingPage";
|
||||
import BusinessBankingPage from "./BusinessBankingPage";
|
||||
import CooperateBankingPage from "./CooperateBankingPage";
|
||||
import LetsGetStatedPage from "./LetsGetStatedPage";
|
||||
import PaymentPage from "./PaymentPage";
|
||||
|
||||
export {
|
||||
HomePage,
|
||||
@@ -25,5 +26,6 @@ export {
|
||||
PersonalBankingPage,
|
||||
BusinessBankingPage,
|
||||
CooperateBankingPage,
|
||||
LetsGetStatedPage
|
||||
LetsGetStatedPage,
|
||||
PaymentPage
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
CooperateBankingPage,
|
||||
PersonalBankingPage,
|
||||
LetsGetStatedPage,
|
||||
PaymentPage
|
||||
} from "../pages";
|
||||
import { DashboardAuth } from "../layouts";
|
||||
|
||||
@@ -66,6 +67,10 @@ const Routers = () => {
|
||||
path={RouteHandler.dashboardLegals}
|
||||
element={<DashboardLegalsPage />}
|
||||
/>
|
||||
<Route
|
||||
path={RouteHandler.paymentpage}
|
||||
element={<PaymentPage />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="*" element={<>Error Page</>} />
|
||||
</Routes>
|
||||
|
||||
@@ -12,4 +12,5 @@ export class RouteHandler {
|
||||
static dashboardPayments = "/dashboard/payments";
|
||||
static dashboardLegals = "/dashboard/legals";
|
||||
static termsAndConditions = "/terms-and-conditions";
|
||||
static paymentpage = "/payment";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
interface SelectOption {
|
||||
loading: boolean;
|
||||
data: {value: string;
|
||||
label: string}[]
|
||||
}
|
||||
|
||||
export const state: SelectOption = {
|
||||
loading: false,
|
||||
data: [
|
||||
{ value: "", label: "Please Select" },
|
||||
{
|
||||
"value": "abia",
|
||||
"label": "Abia"
|
||||
},
|
||||
{
|
||||
"value": "adamawa",
|
||||
"label": "Adamawa"
|
||||
},
|
||||
{
|
||||
"value": "akwa ibom",
|
||||
"label": "Akwa Ibom"
|
||||
},
|
||||
{
|
||||
"value": "anambra",
|
||||
"label": "Anambra"
|
||||
},
|
||||
{
|
||||
"value": "bauchi",
|
||||
"label": "Bauchi"
|
||||
},
|
||||
{
|
||||
"value": "bayelsa",
|
||||
"label": "Bayelsa"
|
||||
},
|
||||
{
|
||||
"value": "benue",
|
||||
"label": "Benue"
|
||||
},
|
||||
{
|
||||
"value": "borno",
|
||||
"label": "Borno"
|
||||
},
|
||||
{
|
||||
"value": "cross river",
|
||||
"label": "Cross River"
|
||||
},
|
||||
{
|
||||
"value": "delta",
|
||||
"label": "Delta"
|
||||
},
|
||||
{
|
||||
"value": "ebonyi",
|
||||
"label": "Ebonyi"
|
||||
},
|
||||
{
|
||||
"value": "edo",
|
||||
"label": "Edo"
|
||||
},
|
||||
{
|
||||
"value": "ekiti",
|
||||
"label": "Ekiti"
|
||||
},
|
||||
{
|
||||
"value": "enugu",
|
||||
"label": "Enugu"
|
||||
},
|
||||
{
|
||||
"value": "fct - abuja",
|
||||
"label": "FCT - Abuja"
|
||||
},
|
||||
{
|
||||
"value": "gombe",
|
||||
"label": "Gombe"
|
||||
},
|
||||
{
|
||||
"value": "imo",
|
||||
"label": "Imo"
|
||||
},
|
||||
{
|
||||
"value": "jigawa",
|
||||
"label": "Jigawa"
|
||||
},
|
||||
{
|
||||
"value": "kaduna",
|
||||
"label": "Kaduna"
|
||||
},
|
||||
{
|
||||
"value": "kano",
|
||||
"label": "Kano"
|
||||
},
|
||||
{
|
||||
"value": "katsina",
|
||||
"label": "Katsina"
|
||||
},
|
||||
{
|
||||
"value": "kebbi",
|
||||
"label": "Kebbi"
|
||||
},
|
||||
{
|
||||
"value": "kogi",
|
||||
"label": "Kogi"
|
||||
},
|
||||
{
|
||||
"value": "kwara",
|
||||
"label": "Kwara"
|
||||
},
|
||||
{
|
||||
"value": "lagos",
|
||||
"label": "Lagos"
|
||||
},
|
||||
{
|
||||
"value": "nasarawa",
|
||||
"label": "Nasarawa"
|
||||
},
|
||||
{
|
||||
"value": "niger",
|
||||
"label": "Niger"
|
||||
},
|
||||
{
|
||||
"value": "ogun",
|
||||
"label": "Ogun"
|
||||
},
|
||||
{
|
||||
"value": "ondo",
|
||||
"label": "Ondo"
|
||||
},
|
||||
{
|
||||
"value": "osun",
|
||||
"label": "Osun"
|
||||
},
|
||||
{
|
||||
"value": "oyo",
|
||||
"label": "Oyo"
|
||||
},
|
||||
{
|
||||
"value": "plateau",
|
||||
"label": "Plateau"
|
||||
},
|
||||
{
|
||||
"value": "rivers",
|
||||
"label": "Rivers"
|
||||
},
|
||||
{
|
||||
"value": "sokoto",
|
||||
"label": "Sokoto"
|
||||
},
|
||||
{
|
||||
"value": "taraba",
|
||||
"label": "Taraba"
|
||||
},
|
||||
{
|
||||
"value": "yobe",
|
||||
"label": "Yobe"
|
||||
},
|
||||
{
|
||||
"value": "zamfara",
|
||||
"label": "Zamfara"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user