Application and BVN list added #13

Merged
ameye merged 1 commits from dash-details into master 2024-05-10 10:45:21 +00:00
6 changed files with 470 additions and 170 deletions
@@ -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'}}
>
&lt;
</button>
{data.length && data.map((item, index)=>{
item = item
if(index%itemsPerPage == 0 && index >= currentPage && index <= currentPage+itemsPerPage){
return (
<button
key={index}
onClick={handleNext}
className={`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'}}
>
&gt;
</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'}}
>
&lt;
</button>
{data.length && data.map((item, index)=>{
item = item
if(index%itemsPerPage == 0 && index >= currentPage && index <= currentPage+itemsPerPage){
return (
<button
key={index}
onClick={handleNext}
className={`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'}}
>
&gt;
</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 */}
+2 -1
View File
@@ -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 => {
+11 -6
View File
@@ -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
} }
} }