Compare commits

...

5 Commits

Author SHA1 Message Date
victorAnumudu 827d0a1c30 added loan details API 2024-07-15 17:11:14 +01:00
victorAnumudu 0fc549f1b5 added loan details API 2024-07-15 17:09:06 +01:00
ameye ee1fe4a5b6 Merge branch 'process-page' of DigiFi/digifi-bko into master 2024-07-12 09:51:06 +00:00
victorAnumudu 4ac97537cd process page added 2024-07-12 10:22:05 +01:00
ameye fc214b4bad Merge branch 'side-menu-adjust' of DigiFi/digifi-bko into master 2024-07-11 16:52:59 +00:00
8 changed files with 305 additions and 70 deletions
@@ -0,0 +1,132 @@
import React, { useEffect, useState } from 'react'
import {useLocation, useNavigate} from 'react-router-dom'
import { Content } from '../../../../_digifi/layout/components/content'
import { ToolbarWrapper } from '../../../../_digifi/layout/components/toolbar'
import { CustomLoading, UsersListLoading } from '../user-started/components/loading/UsersListLoading'
import { getVerifiedLoanDetailsByUID } from '../core/_requests'
export default function ApproveRejectPage() {
const {state:{selectedUser}} = useLocation()
const navigate = useNavigate()
const [requestStatus, setRequestStatus] = useState<any>({loading:false, status:false, data:null})
const [loanDetails, setLoanDetails] = useState<any>({loading:true, data:null})
const handleSubmit = ():any => {
setRequestStatus({loading:true, status:false, data:null})
setTimeout(()=>{
setRequestStatus({loading:false, status:false, data:null})
},2000)
}
useEffect(()=>{
if(!selectedUser){
return navigate('/', {replace:true})
}
getVerifiedLoanDetailsByUID(selectedUser?.uid).then(res => {
setLoanDetails({loading:false, data:res?.data})
}).catch(err => {
console.log(err)
setLoanDetails({loading:false, data:null})
})
},[])
return (
<>
{/* <ToolbarWrapper /> */}
<Content>
{loanDetails.loading ?
<div className='position-relative w-100 vh-100'>
<CustomLoading />
</div>
:
<>
<div className='w-100'>
<h3 className='py-3 py-xl-5 card-title text-gray-800 fw-bold'>Processing: {selectedUser?.uid}</h3>
</div>
{/* begin::Row */}
<div className="row g-5 g-xl-10 mb-5 mb-xl-10">
{/* begin::Col */}
<div className="col-xl-6 mb-md-5 mb-xl-10">
<div className="card card-flash flex flex-col justify-content-between p-4 h-md-50 mb-5 mb-xl-10 bg-secondary">
<h3 className='card-title text-gray-800 fw-bold'>Process Loan</h3>
<div className='w-100 d-flex justify-content-between'>
<button
className='btn btn-light btn-active-light-secondary text-success btn-lg'
onClick={()=>navigate('/loan/pages/process/verified', {replace:true})}
>
Return
</button>
<button
className='btn btn-light btn-active-light-secondary text-danger btn-lg'
onClick={handleSubmit}
>
Reject
</button>
<button
className='btn btn-light btn-active-light-secondary text-primary btn-lg'
onClick={handleSubmit}
>
Approve
</button>
</div>
</div>
<div className="card card-flash flex flex-col p-4 h-md-50 mb-5 mb-xl-10 bg-secondary">
<h3 className='card-title text-gray-800 fw-bold mb-5'>Verification details</h3>
<div className='w-100'>
{loanDetails?.data?.verification.length > 0 ?
<table className='w-100'>
<tr>
<th>UID</th>
<th>EMPLOYER NAME</th>
</tr>
{loanDetails?.data?.verification?.map((item:any) => (
<tr key={item.uid || item.id}>
<td>{item.uid}</td>
<td>{item.employers_name}</td>
</tr>
))}
</table>
:
null
}
</div>
</div>
</div>
{/* end::Col */}
{/* begin::Col */}
<div className="col-xl-6">
<div className="card card-flash flex flex-col p-4 h-md-100 bg-secondary">
<h3 className='card-title text-gray-800 fw-bold mb-5'>Loan Details</h3>
<div className='w-100'>
{loanDetails?.data?.application.length > 0 ?
<table className='w-100'>
<tr>
<th>UID</th>
<th>AMOUNT</th>
</tr>
{loanDetails?.data?.application?.map((item:any) => (
<tr key={item.uid || item.id}>
<td>{item.uid}</td>
<td>{item.loan_amount}</td>
</tr>
))}
</table>
:
null
}
</div>
</div>
</div>
{/* end::Col */}
</div>
{/* end::Row */}
</>
}
</Content>
{requestStatus.loading && <UsersListLoading />}
</>
)
}
@@ -0,0 +1,45 @@
import { Navigate, Routes, Route, Outlet } from "react-router-dom";
import { PageLink, PageTitle } from "../../../../_digifi/layout/core";
import ApproveRejectPage from "./ApproveRejectPage";
const processBreadCrumbs: Array<PageLink> = [
{
title: "Loan",
path: "/loan/pages/process/verified",
isSeparator: false,
isActive: false,
},
{
title: "",
path: "",
isSeparator: true,
isActive: false,
},
];
const ApproveRejectRoutes = () => (
<Routes>
<Route
element={
<>
{/* <ProcessHeader /> */}
<Outlet />
</>
}
>
<Route
path="process"
element={
<>
<PageTitle breadcrumbs={processBreadCrumbs}>Verified</PageTitle>
<ApproveRejectPage />
</>
}
/>
<Route index element={<Navigate to="/loan/verified/process" />} />
</Route>
</Routes>
);
export default ApproveRejectRoutes;
+49
View File
@@ -33,8 +33,57 @@ export type User = {
employer_name?: string
}
export type VerifiedLoanDetails = {
application_uid?: string
application?: Array<{[index: string]: string}>
// application?: [
// {
// "id": "21",
// "uid": "006915e9-cb0d-42e9-b4af-c047da51e2ac",
// "customer_uid": "9cb678e0-0697-4cc9-9bf0-3f40a3c989fb",
// "loan_amount": "2220",
// "payment_month": "18",
// "sales_agent": "866969",
// "gender": null,
// "marital_status": "single",
// "email": "ameye+update@chiefsoft.com",
// "address": "4201 Defoors Farm Trail",
// "state": "abia",
// "country": "NG",
// "loan_detail": "{\"customer_uid\":\"9cb678e0-0697-4cc9-9bf0-3f40a3c989fb\",\"loan_amount\":\"2220\",\"payment_month\":\"18\",\"sales_agent\":\"866969\",\"gender\":\"female\",\"address\":\"4201 Defoors Farm Trail\",\"marital_status\":\"single\",\"state\":\"abia\",\"email\":\"ameye+update@chiefsoft.com\",\"country\":\"NG\",\"employer_uid\":\"3a9ec95a-090c-4c98-bc01-e96d76b93952\",\"employment\":\"[object Object]\",\"loan_reference\":\"[object Object],[object Object]\",\"disbursement\":\"[object Object]\"}",
// "status": "4",
// "added": "2024-07-10 21:28:13.404726",
// "updated": "2024-07-10 21:28:13.404726",
// "employer_uid": "3a9ec95a-090c-4c98-bc01-e96d76b93952"
// }
// ],
verification?: Array<{[index: string]: string}>
// "verification": [
// {
// "id": "56",
// "uid": "e041279c-875d-4973-b042-48efec05fecf",
// "employer_uid": "3a9ec95a-090c-4c98-bc01-e96d76b93952",
// "status": "1",
// "added": "2024-07-11 16:03:25.343553",
// "updated": "2024-07-11 16:03:25.343553",
// "username": "ameye+update@chiefsoft.com",
// "password": "5769407ab4409037161a51692c6bb617",
// "signatory_uid": "db444b87-ec0f-483b-a8cf-eea9e8466f10",
// "application_uid": "006915e9-cb0d-42e9-b4af-c047da51e2ac",
// "education": "b.sc",
// "grade": "Test 001",
// "applicant_date": "2024-07-10 00:00:00",
// "ippis_number": "",
// "employers_name": "bshshsjss",
// "designation": "jdjdjddk"
// }
// ]
}
export type UsersQueryResponse = Response<Array<User>>
export type VerifiedLoanDetailsResponse = Response<VerifiedLoanDetails>
export const initialUser: User = {
avatar: 'avatars/300-6.jpg',
position: 'Art Director',
+8 -2
View File
@@ -1,7 +1,7 @@
import axios, { AxiosResponse } from "axios";
import { ID, Response } from "../../../../_digifi/helpers"
import { User, UsersQueryResponse } from "./_models";
import { postAuxEnd } from "../../auth/core/AxiosCallHelper";
import { User, UsersQueryResponse, VerifiedLoanDetailsResponse } from "./_models";
import { postAuxEnd, getAuxEnd } from "../../auth/core/AxiosCallHelper";
const API_URL = import.meta.env.VITE_APP_THEME_API_URL;
const USER_URL = `${API_URL}/user`;
@@ -54,6 +54,10 @@ const employersVerify = (uid: ID): Promise<UsersQueryResponse> => { // FUNCTION
return postAuxEnd('/employers/verify', {application_uid:uid})
};
const getVerifiedLoanDetailsByUID = (uid: string): Promise<VerifiedLoanDetailsResponse> => { // FUNCTION TO GET VERIFIED LOAN DETAILS IN ORDER TO PROCESS
return getAuxEnd(`/loan/process/${uid}`)
};
const getUserById = (id: ID): Promise<User | undefined> => {
return axios
.get(`${USER_URL}/${id}`)
@@ -92,6 +96,8 @@ export {
getVerifiedUsers,
getApprovedUsers,
employersVerify,
getVerifiedLoanDetailsByUID,
deleteUser,
deleteSelectedUsers,
getUserById,
@@ -15,4 +15,21 @@ const UsersListLoading = () => {
return <div style={{...styles, position: 'absolute', textAlign: 'center'}}>Processing...</div>
}
export {UsersListLoading}
const CustomLoading = () => {
const styles = {
borderRadius: '0.475rem',
boxShadow: '0 0 50px 0 rgb(82 63 105 / 15%)',
backgroundColor: '#fff',
color: '#7e8299',
fontWeight: '500',
margin: '0',
width: 'auto',
padding: '1rem 2rem',
top: 'calc(50% - 2rem)',
left: 'calc(50% - 4rem)',
}
return <div style={{...styles, position: 'absolute', textAlign: 'center'}}>Loading...</div>
}
export {UsersListLoading, CustomLoading}
@@ -1,46 +1,29 @@
import { FC, useEffect } from "react";
import { useMutation, useQueryClient } from "react-query";
import { useQueryClient } from "react-query";
import { MenuComponent } from "../../../../../../_digifi/assets/ts/components";
import { ID, KTIcon, QUERIES } from "../../../../../../_digifi/helpers";
import { useListView } from "../../core/ListViewProvider";
import { useQueryResponse } from "../../core/QueryResponseProvider";
import { employersVerify } from "../../../core/_requests";
import { Link } from "react-router-dom";
import { User } from "../../../core/_models";
type Props = {
id: ID;
data: Array<User> | any
};
const UserActionsCell: FC<Props> = ({ id }) => {
const { setItemIdForUpdate } = useListView();
const { query } = useQueryResponse();
const queryClient = useQueryClient();
const UserActionsCell: FC<Props> = ({ id, data }) => {
// const { setItemIdForUpdate } = useListView();
// const { query } = useQueryResponse();
// const queryClient = useQueryClient();
// let selectedUser = data?.filter((item:User) => item.uid == id)[0]
let selectedUser = data?.filter((item:User) => item.uid == id)[0]
useEffect(() => {
MenuComponent.reinitialization();
}, []);
const openEditModal = () => {
setItemIdForUpdate(id);
};
const empsVerify = useMutation(() => employersVerify(id), {
// 💡 response of the mutation is passed to onSuccess
onSuccess: () => {
// ✅ update detail view directly
queryClient.invalidateQueries([`${QUERIES.READY_LIST}-${query}`]);
},
});
const resendVerification = async () => { // FUNCTION TO RESEND VERIFICATION
let cont = confirm('Are you sure, you want to send resend verification?')
if(cont){
await empsVerify.mutateAsync()
}
}
return (
<>
<a
@@ -59,21 +42,9 @@ const UserActionsCell: FC<Props> = ({ id }) => {
>
{/* begin::Menu item */}
<div className="menu-item px-3">
<a className="menu-link px-3" onClick={openEditModal}>
Edit
</a>
</div>
{/* end::Menu item */}
{/* begin::Menu item */}
<div className="menu-item px-3">
<a
className="menu-link px-3"
data-kt-users-table-filter="delete_row"
onClick={async () => resendVerification()}
>
Resend Verification
</a>
<Link state={{selectedUser}} to='/loan/verified/process' className="menu-link px-3">
Process
</Link>
</div>
{/* end::Menu item */}
</div>
@@ -58,7 +58,7 @@ const usersColumns: ReadonlyArray<Column<User>> = [
<UserCustomHeader tableProps={props} title='Actions' className='text-end min-w-100px' />
),
id: 'actions',
Cell: ({...props}) => <UserActionsCell id={props.data[props.row.index].uid} />,
Cell: ({...props}) => <UserActionsCell id={props.data[props.row.index].uid} data={props.data} />,
},
]
+40 -25
View File
@@ -1,11 +1,11 @@
import {lazy, FC, Suspense} from 'react'
import {Route, Routes, Navigate} from 'react-router-dom'
import {MasterLayout} from '../../_digifi/layout/MasterLayout'
import TopBarProgress from 'react-topbar-progress-indicator'
import {DashboardWrapper} from '../pages/dashboard/DashboardWrapper'
import { lazy, FC, Suspense } from "react";
import { Route, Routes, Navigate } from "react-router-dom";
import { MasterLayout } from "../../_digifi/layout/MasterLayout";
import TopBarProgress from "react-topbar-progress-indicator";
import { DashboardWrapper } from "../pages/dashboard/DashboardWrapper";
// import {MenuTestPage} from '../pages/MenuTestPage'
import {getCSSVariableValue} from '../../_digifi/assets/ts/_utils'
import {WithChildren} from '../../_digifi/helpers'
import { getCSSVariableValue } from "../../_digifi/assets/ts/_utils";
import { WithChildren } from "../../_digifi/helpers";
// import BuilderPageWrapper from '../pages/layout-builder/BuilderPageWrapper'
const PrivateRoutes = () => {
@@ -13,28 +13,43 @@ const PrivateRoutes = () => {
// const AccountPage = lazy(() => import('../modules/accounts/AccountPage'))
// const WidgetsPage = lazy(() => import('../modules/widgets/WidgetsPage'))
// const ChatPage = lazy(() => import('../modules/apps/chat/ChatPage'))
const ProcessPage = lazy(() => import('../modules/process/ProcessPage'))
const UsersPage = lazy(() => import('../modules/apps/user-management/UsersPage'))
const EmployersPage =lazy(() => import('../modules/employers/employers-list/UsersPage'))
const ProcessPage = lazy(() => import("../modules/process/ProcessPage"));
const UsersPage = lazy(
() => import("../modules/apps/user-management/UsersPage")
);
const EmployersPage = lazy(
() => import("../modules/employers/employers-list/UsersPage")
);
const ApproveRejectRoutes = lazy(
() => import("../modules/process/approve-reject-page/ApproveRejectRoutes")
);
return (
<Routes>
<Route element={<MasterLayout />}>
{/* Redirect to Dashboard after success login/registartion */}
<Route path='auth/*' element={<Navigate to='/dashboard' />} />
<Route path="auth/*" element={<Navigate to="/dashboard" />} />
{/* Pages */}
<Route path='dashboard' element={<DashboardWrapper />} />
<Route path="dashboard" element={<DashboardWrapper />} />
{/* <Route path='builder' element={<BuilderPageWrapper />} /> */}
{/* <Route path='menu-test' element={<MenuTestPage />} /> */}
{/* Lazy Modules */}
<Route
path='loan/pages/process/*'
path="loan/pages/process/*"
element={
<SuspensedView>
<ProcessPage />
</SuspensedView>
}
/>
<Route
path="loan/verified/*"
element={
<SuspensedView>
<ApproveRejectRoutes />
</SuspensedView>
}
/>
{/* <Route
path='crafted/pages/wizards/*'
element={
@@ -68,7 +83,7 @@ const PrivateRoutes = () => {
}
/> */}
<Route
path='tools/user-management/*'
path="tools/user-management/*"
element={
<SuspensedView>
<UsersPage />
@@ -76,7 +91,7 @@ const PrivateRoutes = () => {
}
/>
<Route
path='/employers/*'
path="/employers/*"
element={
<SuspensedView>
<EmployersPage />
@@ -84,22 +99,22 @@ const PrivateRoutes = () => {
}
/>
{/* Page Not Found */}
<Route path='*' element={<Navigate to='/error/404' />} />
<Route path="*" element={<Navigate to="/error/404" />} />
</Route>
</Routes>
)
}
);
};
const SuspensedView: FC<WithChildren> = ({children}) => {
const baseColor = getCSSVariableValue('--bs-primary')
const SuspensedView: FC<WithChildren> = ({ children }) => {
const baseColor = getCSSVariableValue("--bs-primary");
TopBarProgress.config({
barColors: {
'0': baseColor,
"0": baseColor,
},
barThickness: 1,
shadowBlur: 5,
})
return <Suspense fallback={<TopBarProgress />}>{children}</Suspense>
}
});
return <Suspense fallback={<TopBarProgress />}>{children}</Suspense>;
};
export {PrivateRoutes}
export { PrivateRoutes };