Application and BVN list added #13
@@ -0,0 +1,137 @@
|
|||||||
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
|
import { RecentBVNProps } from "../../../../app/pages/dashboard/model";
|
||||||
|
|
||||||
|
type PaginatedListProps = {
|
||||||
|
data: RecentBVNProps,
|
||||||
|
itemsPerPage?: number,
|
||||||
|
filterItem?: string[],
|
||||||
|
tableTitle?: string,
|
||||||
|
titleClass?:string,
|
||||||
|
children: (data:RecentBVNProps) => ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RecentBVNList({
|
||||||
|
data,
|
||||||
|
itemsPerPage = 5,
|
||||||
|
filterItem,
|
||||||
|
tableTitle,
|
||||||
|
titleClass,
|
||||||
|
children,
|
||||||
|
}:PaginatedListProps) {
|
||||||
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
const [filteredData, setFilteredData] = useState(data);
|
||||||
|
|
||||||
|
const [currentPage, setCurrentPage] = useState(0);
|
||||||
|
const [newData, setNewData] = useState<any>([]);
|
||||||
|
|
||||||
|
const numberOfSelection = itemsPerPage;
|
||||||
|
|
||||||
|
const handlePrev = () => {
|
||||||
|
if (currentPage != 0) {
|
||||||
|
setCurrentPage((prev) => prev - numberOfSelection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentPage < data.length) {
|
||||||
|
setCurrentPage((prev) => prev + numberOfSelection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = ({ target: { value } }:{target: {value:string}}, name:string) => {
|
||||||
|
setSearchTerm(value);
|
||||||
|
let newFilteredData:any = data.filter((item:any) =>
|
||||||
|
item[name].toLowerCase().startsWith(value.toLowerCase())
|
||||||
|
);
|
||||||
|
setFilteredData(newFilteredData);
|
||||||
|
setCurrentPage(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setNewData(
|
||||||
|
filteredData?.slice(currentPage, numberOfSelection + currentPage)
|
||||||
|
);
|
||||||
|
}, [currentPage, filteredData]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setCurrentPage(0)
|
||||||
|
},[itemsPerPage])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full">
|
||||||
|
<h1 className={`text-2xl mb-5 font-semibold ${titleClass && titleClass}`}>{tableTitle}</h1>
|
||||||
|
|
||||||
|
{data.length > 0 && filterItem && (
|
||||||
|
<div className="mb-10 flex justify-end items-center gap-2">
|
||||||
|
{filterItem.map((item, index) => (
|
||||||
|
<label
|
||||||
|
key={index}
|
||||||
|
className="flex flex-col sm:flex-row items-center gap-2 text-slate-600 dark:text-slate-100 transition-all duration-500"
|
||||||
|
>
|
||||||
|
Search by {item[0].toUpperCase() + item.slice(1)}
|
||||||
|
<input
|
||||||
|
name={item}
|
||||||
|
type="text"
|
||||||
|
className="py-1 px-2 text-sm min-w-[100px] text-black dark:text-white bg-white dark:bg-slate-800 rounded-full border-0 outline-none ring-1 ring-slate-300 dark:ring-white transition-all duration-500"
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => {
|
||||||
|
handleSearch(e, item);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{children(newData)}
|
||||||
|
|
||||||
|
{/* show prev and next button if data exist */}
|
||||||
|
{(data.length > 0 && data.length > itemsPerPage) && (
|
||||||
|
<div className="mt-2 mt-sm-5 w-full d-flex gap-4 justify-content-center align-items-center">
|
||||||
|
<button
|
||||||
|
onClick={handlePrev}
|
||||||
|
className={`text-sm md:text-lg rounded-circle d-flex justify-content-center align-items-center border-1 transition-all duration-300 ${
|
||||||
|
currentPage == 0
|
||||||
|
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400 pe-none"
|
||||||
|
: "text-slate-600 border-slate-600 dark:text-white dark:border-white"
|
||||||
|
}`}
|
||||||
|
style={{width:'30px', height:'30px'}}
|
||||||
|
>
|
||||||
|
<
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{data.length && data.map((item, index)=>{
|
||||||
|
item = item
|
||||||
|
if(index%itemsPerPage == 0 && index >= currentPage && index <= currentPage+itemsPerPage){
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
onClick={handleNext}
|
||||||
|
className={`text-sm md:text-lg rounded-circle d-flex justify-content-center align-items-center border-1 transition-all duration-300 ${
|
||||||
|
currentPage != index
|
||||||
|
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400"
|
||||||
|
: "text-slate-600 border-slate-600 dark:text-white dark:border-white pe-none"
|
||||||
|
}`}
|
||||||
|
style={{width:'30px', height:'30px'}}
|
||||||
|
>
|
||||||
|
{index/itemsPerPage +1}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleNext}
|
||||||
|
className={`text-sm md:text-lg rounded-circle d-flex justify-content-center align-items-center border-1 transition-all duration-300 ${
|
||||||
|
currentPage + numberOfSelection >= data.length
|
||||||
|
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400 pe-none"
|
||||||
|
: "text-slate-600 border-slate-600 dark:text-white dark:border-white"
|
||||||
|
}`}
|
||||||
|
style={{width:'30px', height:'30px'}}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
|
import { RecentApplicationsProps } from "../../../../app/pages/dashboard/model";
|
||||||
|
|
||||||
|
type PaginatedListProps = {
|
||||||
|
data: RecentApplicationsProps,
|
||||||
|
itemsPerPage?: number,
|
||||||
|
filterItem?: string[],
|
||||||
|
tableTitle?: string,
|
||||||
|
titleClass?:string,
|
||||||
|
children: (data:RecentApplicationsProps) => ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RecentLoanAppList({
|
||||||
|
data,
|
||||||
|
itemsPerPage = 5,
|
||||||
|
filterItem,
|
||||||
|
tableTitle,
|
||||||
|
titleClass,
|
||||||
|
children,
|
||||||
|
}:PaginatedListProps) {
|
||||||
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
const [filteredData, setFilteredData] = useState(data);
|
||||||
|
|
||||||
|
const [currentPage, setCurrentPage] = useState(0);
|
||||||
|
const [newData, setNewData] = useState<any>([]);
|
||||||
|
|
||||||
|
const numberOfSelection = itemsPerPage;
|
||||||
|
|
||||||
|
const handlePrev = () => {
|
||||||
|
if (currentPage != 0) {
|
||||||
|
setCurrentPage((prev) => prev - numberOfSelection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleNext = () => {
|
||||||
|
if (currentPage < data.length) {
|
||||||
|
setCurrentPage((prev) => prev + numberOfSelection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = ({ target: { value } }:{target: {value:string}}, name:string) => {
|
||||||
|
setSearchTerm(value);
|
||||||
|
let newFilteredData:any = data.filter((item:any) =>
|
||||||
|
item[name].toLowerCase().startsWith(value.toLowerCase())
|
||||||
|
);
|
||||||
|
setFilteredData(newFilteredData);
|
||||||
|
setCurrentPage(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setNewData(
|
||||||
|
filteredData?.slice(currentPage, numberOfSelection + currentPage)
|
||||||
|
);
|
||||||
|
}, [currentPage, filteredData]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setCurrentPage(0)
|
||||||
|
},[itemsPerPage])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full">
|
||||||
|
<h1 className={`text-2xl mb-5 font-semibold ${titleClass && titleClass}`}>{tableTitle}</h1>
|
||||||
|
|
||||||
|
{data.length > 0 && filterItem && (
|
||||||
|
<div className="mb-10 flex justify-end items-center gap-2">
|
||||||
|
{filterItem.map((item, index) => (
|
||||||
|
<label
|
||||||
|
key={index}
|
||||||
|
className="flex flex-col sm:flex-row items-center gap-2 text-slate-600 dark:text-slate-100 transition-all duration-500"
|
||||||
|
>
|
||||||
|
Search by {item[0].toUpperCase() + item.slice(1)}
|
||||||
|
<input
|
||||||
|
name={item}
|
||||||
|
type="text"
|
||||||
|
className="py-1 px-2 text-sm min-w-[100px] text-black dark:text-white bg-white dark:bg-slate-800 rounded-full border-0 outline-none ring-1 ring-slate-300 dark:ring-white transition-all duration-500"
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => {
|
||||||
|
handleSearch(e, item);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{children(newData)}
|
||||||
|
|
||||||
|
{/* show prev and next button if data exist */}
|
||||||
|
{(data.length > 0 && data.length > itemsPerPage) && (
|
||||||
|
<div className="mt-2 mt-sm-5 w-full d-flex gap-4 justify-content-center align-items-center">
|
||||||
|
<button
|
||||||
|
onClick={handlePrev}
|
||||||
|
className={`text-sm md:text-lg rounded-circle d-flex justify-content-center align-items-center border-1 transition-all duration-300 ${
|
||||||
|
currentPage == 0
|
||||||
|
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400 pe-none"
|
||||||
|
: "text-slate-600 border-slate-600 dark:text-white dark:border-white"
|
||||||
|
}`}
|
||||||
|
style={{width:'30px', height:'30px'}}
|
||||||
|
>
|
||||||
|
<
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{data.length && data.map((item, index)=>{
|
||||||
|
item = item
|
||||||
|
if(index%itemsPerPage == 0 && index >= currentPage && index <= currentPage+itemsPerPage){
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
onClick={handleNext}
|
||||||
|
className={`text-sm md:text-lg rounded-circle d-flex justify-content-center align-items-center border-1 transition-all duration-300 ${
|
||||||
|
currentPage != index
|
||||||
|
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400"
|
||||||
|
: "text-slate-600 border-slate-600 dark:text-white dark:border-white pe-none"
|
||||||
|
}`}
|
||||||
|
style={{width:'30px', height:'30px'}}
|
||||||
|
>
|
||||||
|
{index/itemsPerPage +1}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleNext}
|
||||||
|
className={`text-sm md:text-lg rounded-circle d-flex justify-content-center align-items-center border-1 transition-all duration-300 ${
|
||||||
|
currentPage + numberOfSelection >= data.length
|
||||||
|
? "text-slate-400 border-slate-400 dark:text-slate-400 dark:border-slate-400 pe-none"
|
||||||
|
: "text-slate-600 border-slate-600 dark:text-white dark:border-white"
|
||||||
|
}`}
|
||||||
|
style={{width:'30px', height:'30px'}}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,11 +3,12 @@ import React from 'react'
|
|||||||
import { NewDateTimeFormatter } from '../../../lib/NewDateTimeFormatter'
|
import { NewDateTimeFormatter } from '../../../lib/NewDateTimeFormatter'
|
||||||
// import {KTIcon} from '../../../helpers'
|
// import {KTIcon} from '../../../helpers'
|
||||||
// import {Dropdown1} from '../../content/dropdown/Dropdown1'
|
// import {Dropdown1} from '../../content/dropdown/Dropdown1'
|
||||||
import { dashDataProps } from '../../../../app/pages/dashboard/model'
|
import { DashDataProps, RecentBVNProps } from '../../../../app/pages/dashboard/model'
|
||||||
|
import RecentBVNList from '../../../layout/components/paginatedListing/RecentBVNList'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className: string
|
className: string
|
||||||
dashData?: dashDataProps
|
dashData?: DashDataProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListsWidget3: React.FC<Props> = ({dashData, className}) => {
|
const ListsWidget3: React.FC<Props> = ({dashData, className}) => {
|
||||||
@@ -38,7 +39,13 @@ const ListsWidget3: React.FC<Props> = ({dashData, className}) => {
|
|||||||
null
|
null
|
||||||
:
|
:
|
||||||
dashData?.data?.recent_bvn && dashData?.data?.recent_bvn.length ?
|
dashData?.data?.recent_bvn && dashData?.data?.recent_bvn.length ?
|
||||||
dashData?.data?.recent_bvn.map(item => (
|
<RecentBVNList
|
||||||
|
data = {dashData?.data?.recent_bvn}
|
||||||
|
itemsPerPage={5}
|
||||||
|
>
|
||||||
|
{(data:RecentBVNProps) => (
|
||||||
|
<>
|
||||||
|
{data?.map(item => (
|
||||||
<div key={item?.uid} className='d-flex align-items-center mb-8'>
|
<div key={item?.uid} className='d-flex align-items-center mb-8'>
|
||||||
{/* begin::Bullet */}
|
{/* begin::Bullet */}
|
||||||
<span className='bullet bullet-vertical h-40px bg-primary'></span>
|
<span className='bullet bullet-vertical h-40px bg-primary'></span>
|
||||||
@@ -58,7 +65,10 @@ const ListsWidget3: React.FC<Props> = ({dashData, className}) => {
|
|||||||
{/* end::Description */}
|
{/* end::Description */}
|
||||||
<span className='badge badge-light-primary fs-8 fw-bold'>New</span>
|
<span className='badge badge-light-primary fs-8 fw-bold'>New</span>
|
||||||
</div>
|
</div>
|
||||||
))
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</RecentBVNList>
|
||||||
:
|
:
|
||||||
<p>No list Found!</p>
|
<p>No list Found!</p>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
|
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import {KTIcon, toAbsoluteUrl} from '../../../helpers'
|
import {KTIcon, toAbsoluteUrl} from '../../../helpers'
|
||||||
import { dashDataProps } from '../../../../app/pages/dashboard/model'
|
import { DashDataProps, RecentApplicationsProps } from '../../../../app/pages/dashboard/model'
|
||||||
import { NewDateTimeFormatter } from '../../../lib/NewDateTimeFormatter'
|
import { NewDateTimeFormatter } from '../../../lib/NewDateTimeFormatter'
|
||||||
|
import RecentLoanAppList from '../../../layout/components/paginatedListing/RecentLoanAppList'
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className: string
|
className: string
|
||||||
dashData?: dashDataProps
|
dashData?: DashDataProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
||||||
console.log('dashData', dashData?.data?.recent_applications)
|
|
||||||
return (
|
return (
|
||||||
<div className={`card ${className}`}>
|
<div className={`card ${className}`}>
|
||||||
{/* begin::Header */}
|
{/* begin::Header */}
|
||||||
@@ -42,7 +41,13 @@ const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
|||||||
{/* begin::Body */}
|
{/* begin::Body */}
|
||||||
{dashData?.loading ?
|
{dashData?.loading ?
|
||||||
null
|
null
|
||||||
:
|
: dashData?.data?.recent_applications ?
|
||||||
|
<RecentLoanAppList
|
||||||
|
data={dashData?.data?.recent_applications}
|
||||||
|
itemsPerPage={5}
|
||||||
|
>
|
||||||
|
{(data:RecentApplicationsProps)=>(
|
||||||
|
<>
|
||||||
<div className='card-body py-3'>
|
<div className='card-body py-3'>
|
||||||
{/* begin::Table container */}
|
{/* begin::Table container */}
|
||||||
<div className='table-responsive'>
|
<div className='table-responsive'>
|
||||||
@@ -63,7 +68,7 @@ const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
|||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th className='min-w-150px'>Authors</th>
|
<th className='min-w-150px'>Authors</th>
|
||||||
<th className='min-w-140px'>Company</th>
|
<th className='min-w-140px'>Amount</th>
|
||||||
<th className='min-w-120px'>Progress</th>
|
<th className='min-w-120px'>Progress</th>
|
||||||
<th className='min-w-100px text-end'>Actions</th>
|
<th className='min-w-100px text-end'>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -71,8 +76,8 @@ const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
|||||||
{/* end::Table head */}
|
{/* end::Table head */}
|
||||||
{/* begin::Table body */}
|
{/* begin::Table body */}
|
||||||
<tbody>
|
<tbody>
|
||||||
{dashData?.data.recent_applications && dashData?.data.recent_applications.length ?
|
{data && data.length ?
|
||||||
dashData?.data.recent_applications.map(item => (
|
data.map(item => (
|
||||||
<tr key={item?.uid}>
|
<tr key={item?.uid}>
|
||||||
<td>
|
<td>
|
||||||
<div className='form-check form-check-sm form-check-custom form-check-solid'>
|
<div className='form-check form-check-sm form-check-custom form-check-solid'>
|
||||||
@@ -95,11 +100,11 @@ const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href='#' className='text-gray-900 fw-bold text-hover-primary d-block fs-6'>
|
<span className='text-gray-900 fw-bold text-hover-primary d-block fs-6'>
|
||||||
Intertico
|
{item.loan_amount}
|
||||||
</a>
|
</span>
|
||||||
<span className='text-muted fw-semibold text-muted d-block fs-7'>
|
<span className='text-muted fw-semibold text-muted d-block fs-7'>
|
||||||
Web, UI/UX Design
|
{item?.sales_agent? `Agent: ${item?.sales_agent}` : ``}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className='text-end'>
|
<td className='text-end'>
|
||||||
@@ -152,6 +157,11 @@ const TablesWidget10: FC<Props> = ({className, dashData}) => {
|
|||||||
</div>
|
</div>
|
||||||
{/* end::Table container */}
|
{/* end::Table container */}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</RecentLoanAppList>
|
||||||
|
:
|
||||||
|
null
|
||||||
}
|
}
|
||||||
{/* begin::Body */}
|
{/* begin::Body */}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ import {
|
|||||||
import { ToolbarWrapper } from '../../../_digifi/layout/components/toolbar';
|
import { ToolbarWrapper } from '../../../_digifi/layout/components/toolbar';
|
||||||
import { Content } from '../../../_digifi/layout/components/content';
|
import { Content } from '../../../_digifi/layout/components/content';
|
||||||
import { getUserDashDetails } from '../../modules/auth/core/_requests';
|
import { getUserDashDetails } from '../../modules/auth/core/_requests';
|
||||||
|
import { DashDataProps } from './model';
|
||||||
|
|
||||||
const DashboardPage: FC = () => {
|
const DashboardPage: FC = () => {
|
||||||
const [dashDetails, setDashDetails] = useState({loading:true, data:{}})
|
const [dashDetails, setDashDetails] = useState<DashDataProps>({loading:true, data:{}})
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
getUserDashDetails().then(res => {
|
getUserDashDetails().then(res => {
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
export type dashDataProps = {
|
export type RecentApplicationsProps = {
|
||||||
loading: boolean,
|
|
||||||
data: {
|
|
||||||
call_return?: string
|
|
||||||
recent_applications? : {
|
|
||||||
firstname?: string
|
firstname?: string
|
||||||
lastname?: string
|
lastname?: string
|
||||||
uid?: string
|
uid?: string
|
||||||
@@ -19,7 +15,8 @@ export type dashDataProps = {
|
|||||||
added?: string
|
added?: string
|
||||||
updated?: string
|
updated?: string
|
||||||
}[]
|
}[]
|
||||||
recent_bvn?: {
|
|
||||||
|
export type RecentBVNProps = {
|
||||||
id?: string
|
id?: string
|
||||||
uid?: string
|
uid?: string
|
||||||
bvn?: string
|
bvn?: string
|
||||||
@@ -34,5 +31,13 @@ export type dashDataProps = {
|
|||||||
phone?: string | null
|
phone?: string | null
|
||||||
nationality?: string | null
|
nationality?: string | null
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
|
|
||||||
|
export type DashDataProps = {
|
||||||
|
loading: boolean,
|
||||||
|
data: {
|
||||||
|
call_return?: string
|
||||||
|
recent_applications? : RecentApplicationsProps
|
||||||
|
recent_bvn?: RecentBVNProps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user