Recent Loans API Added #35

Merged
ameye merged 1 commits from recent-loans into master 2025-11-03 19:17:33 +00:00
11 changed files with 115 additions and 132 deletions
+12 -11
View File
@@ -8,6 +8,18 @@ import { generalLayoutContext } from './context/GeneralLayoutContext';
import './App.css';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 3,
staleTime: 300000 //5 mins
// refetchOnMount: false,
// staleTime: Infinity // can also be a number in millisecond
},
},
})
function App() {
const {pathname} = useLocation()
@@ -18,17 +30,6 @@ function App() {
window.scrollTo(0,0)
},[pathname])
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 3,
staleTime: 300000 //5 mins
// refetchOnMount: false,
// staleTime: Infinity // can also be a number in millisecond
},
},
})
return (
<>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

+9 -4
View File
@@ -11,6 +11,7 @@ import { loginUser } from '../../services/siteServices'
import RouteLinks from '../../RouteLinks'
import Icons from '../Icons'
import localImgLoader from '../../helpers/localImageLoader'
const initialValues = {
@@ -83,13 +84,17 @@ export default function LoginCom() {
{(props)=>(
<Form>
<div className='flex flex-col gap-8 w-full bg-white rounded-xl p-16 sm:px-20 sm:py-16 shadow'>
<div className='flex justify-center w-full mb-10'>
<img className='w-auto h-8 xs:h-16' src={localImgLoader('simbrella-bko-logo.png')} />
</div>
<div className='w-full flex flex-col gap-1 items-center'>
<h1 className='text-2xl md:text-3xl font-bold text-black-body'>Sign In</h1>
<p className='text-sm font-medium text-slate-500'>Welcome back, please login to your account</p>
</div>
{/* social login */}
<div className='grid grid-cols-2 gap-4 text-sm'>
{/* <div className='grid grid-cols-2 gap-4 text-sm'>
<div className='px-4 py-2 flex gap-2 items-center justify-center text-black-body font-medium border border-slate-300/50 rounded-md hover:text-primary hover:bg-sky-50 cursor-pointer'>
<Icons name='google' />
<span>Sign in with Google</span>
@@ -102,7 +107,7 @@ export default function LoginCom() {
<div className='relative h-[1px] bg-slate-300/50'>
<p className='absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 bg-white p-4 text-12 text-slate-500'>Or with email</p>
</div>
</div> */}
<div className='flex flex-col gap-6'>
<div className='relative text-input flex flex-col gap-2'>
@@ -146,11 +151,11 @@ export default function LoginCom() {
{/* <p className='text-sm text-center font-medium text-slate-500'>Not yet a member? <span className='text-primary'>Sign Up</span></p> */}
<div className='flex justify-end gap-4 mt-6 text-[13px] font-medium'>
{/* <div className='flex justify-end gap-4 mt-6 text-[13px] font-medium'>
<Link className='text-primary' to=''>Terms</Link>
<Link className='text-primary' to=''>Plans</Link>
<Link className='text-primary' to=''>Contact Us</Link>
</div>
</div> */}
</div>
@@ -57,6 +57,8 @@ export default function DashboardHeader() {
<div onClick={()=>handleActiveMenu('avatar')} className='relative cursor-pointer w-10 h-10 rounded shadow-round_black dark:shadow-round_white'>
<img src={UserAvatar} alt='user avatar' className='w-full h-full p-1 rounded-full' />
{activeMenu == 'avatar' &&
<>
<div className="fixed top-0 left-0 right-0 bottom-0 bg-black/10"></div>
<div className="pop-modal z-[777] absolute p-4 w-52 sm:w-96 bg-white dark:bg-black-box right-0 top-16 rounded shadow-round_black dark:shadow-round_white">
<div className="w-full h-full flex flex-col gap-4">
<div className="flex flex-col text-black dark:text-white text-base sm:text-lg">
@@ -74,6 +76,7 @@ export default function DashboardHeader() {
</div>
</div>
</div>
</>
}
</div>
</div>
@@ -9,6 +9,7 @@ import { generalLayoutContext } from "../../../context/GeneralLayoutContext";
import { TbLogout2 } from "react-icons/tb";
import UserAvatar from '../../../assets/user_avatar.jpg'
import Icons from "../../Icons";
import localImgLoader from '../../../helpers/localImageLoader';
export default function DashboardAside() {
@@ -22,7 +23,8 @@ export default function DashboardAside() {
return (
<div className='w-full h-full flex flex-col'>
<div className="mb-3 w-full h-24 logo flex items-center">
<DummyLogo />
{/* <DummyLogo /> */}
<img className='w-2/3 h-auto' src={localImgLoader('simbrella-bko-logo.png')} />
</div>
{/* <hr className="border-slate-400" /> */}
+14 -66
View File
@@ -2,77 +2,25 @@ import React from 'react'
import Img from '../../../assets/user_avatar.jpg'
import CustomCounter from '../../CustomCounter'
export default function Orders() {
export default function Orders({data}) {
return (
<div className='h-full p-2 sm:p-4 large:p-8 flex flex-col gap-16 overflow-y-auto aside-scroll-design'>
{/*<div className='flex flex-col gap-4'>*/}
{/* <p className='text-base text-white-body font-bold'>Recent Eligibility</p>*/}
{/* <div className='grid grid-cols-2 gap-4 sm:gap-6 large:gap-8'>*/}
{/* <div className='p-2 sm:p-3 large:p-4 flex flex-col border border-slate-500 border-dashed'>*/}
{/* <p className='text-base font-bold text-white-body'>*/}
{/* <CustomCounter targetNumber={18} timeInSeconds={1} />*/}
{/* </p>*/}
{/* <p className='text-sm text-slate-500'>Pending</p>*/}
{/* </div>*/}
{/* <div className='p-2 sm:p-3 large:p-4 flex flex-col border border-slate-500 border-dashed'>*/}
{/* <p className='text-base font-bold text-white-body'>*/}
{/* <CustomCounter targetNumber={5} timeInSeconds={1} />*/}
{/* </p>*/}
{/* <p className='text-sm text-slate-500'>Approved</p>*/}
{/* </div>*/}
{/* <div className='p-2 sm:p-3 large:p-4 flex flex-col border border-slate-500 border-dashed'>*/}
{/* <p className='text-base font-bold text-white-body'>*/}
{/* <CustomCounter targetNumber={1} timeInSeconds={1} />*/}
{/* </p>*/}
{/* <p className='text-sm text-slate-500'>Rejected</p>*/}
{/* </div>*/}
{/* <div className='p-2 sm:p-3 large:p-4 flex flex-col border border-slate-500 border-dashed'>*/}
{/* <p className='text-base font-bold text-white-body'>*/}
{/* <CustomCounter targetNumber={1} timeInSeconds={1} />*/}
{/* </p>*/}
{/* <p className='text-sm text-slate-500'>Created</p>*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
<div className='flex flex-col gap-4'>
<p className='text-base text-white-body font-bold'>Recent Loans</p>
<div className='flex flex-col gap-4'>
<div className='flex gap-3 items-center'>
<div className='px-4 py-2 bg-[#0E172E] rounded-md'>
<img src={Img} className='w-8' alt="Order Image" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
<p className='text-sm text-slate-500'>Project Manager</p>
</div>
</div>
<div className='flex gap-3 items-center'>
<div className='px-4 py-2 bg-[#0E172E] rounded-md'>
<img src={Img} className='w-8' alt="Order Image" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
<p className='text-sm text-slate-500'>Project Manager</p>
</div>
</div>
<div className='flex gap-3 items-center'>
<div className='px-4 py-2 bg-[#0E172E] rounded-md'>
<img src={Img} className='w-8' alt="Order Image" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
<p className='text-sm text-slate-500'>Project Manager</p>
</div>
</div>
<div className='flex gap-3 items-center'>
<div className='px-4 py-2 bg-[#0E172E] rounded-md'>
<img src={Img} className='w-8' alt="Order Image" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
<p className='text-sm text-slate-500'>Project Manager</p>
</div>
</div>
{data.map((item, index)=>{
return (
<div key={index} className='flex gap-3 items-center'>
<div className='px-4 py-2 bg-[#0E172E] rounded-md'>
<img src={Img} className='w-8' alt="Order Image" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
<p className='text-sm text-slate-500'>Project Manager</p>
</div>
</div>
)
})}
</div>
</div>
</div>
@@ -1,4 +1,7 @@
import React, { useState } from 'react'
import { useQuery } from "@tanstack/react-query";
import queryKeys from '../../../services/queryKeys'
import { getRecentLoans } from '../../../services/siteServices'
import Icons from '../../Icons'
import Orders from './Orders'
import Tickets from './Tickets'
@@ -13,25 +16,41 @@ export default function RightAsideBar() {
setActive(lowerStr)
}
return (
<div className='w-full h-full flex flex-col gap-8'>
{/* Menu */}
<div className='grid grid-cols-3 gap-8'>
<button name='orders' onClick={() => handleActiveMenu('orders')} className={`flex justify-center items-center px-2 py-3 large:px-4 large:py-5 rounded-md shadow-round_white bg-[#0E172E] text-white-body hover:scale-[1.1] ${active == 'orders' && 'scale-[1.2]'}`}>
<Icons name='dashboard' className='text-3xl' />
</button>
{/*<button name='tickets' onClick={() => handleActiveMenu('tickets')} className={`flex justify-center items-center px-2 py-3 large:px-4 large:py-5 rounded-md shadow-round_white bg-[#0E172E] text-white-body hover:scale-[1.1] ${active == 'tickets' && 'scale-[1.2]'}`}>*/}
{/* <Icons name='settings' className='text-3xl' />*/}
{/*</button>*/}
{/*<button name='tasks' onClick={() => handleActiveMenu('tasks')} className={`flex justify-center items-center px-2 py-3 large:px-4 large:py-5 rounded-md shadow-round_white bg-[#0E172E] text-white-body hover:scale-[1.1] ${active == 'tasks' && 'scale-[1.2]'}`}>*/}
{/* <Icons name='dashboard' className='text-3xl' />*/}
{/*</button>*/}
</div>
const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.recent_loans,
queryFn: () => getRecentLoans()
})
{/* Body */}
{active === 'orders' && <Orders />}
{/*{active == 'tickets' && <Tickets />}*/}
{/*{active == 'tasks' && <Tasks />}*/}
</div>
)
console.log('data', data?.data)
return (
<div className='w-full h-full flex flex-col gap-8'>
{/* Menu */}
<div className='grid grid-cols-3 gap-8'>
<button name='orders' onClick={() => handleActiveMenu('orders')} className={`flex justify-center items-center px-2 py-3 large:px-4 large:py-5 rounded-md shadow-round_white bg-[#0E172E] text-white-body hover:scale-[1.1] ${active == 'orders' && 'scale-[1.2]'}`}>
<Icons name='dashboard' className='text-3xl' />
</button>
{/*<button name='tickets' onClick={() => handleActiveMenu('tickets')} className={`flex justify-center items-center px-2 py-3 large:px-4 large:py-5 rounded-md shadow-round_white bg-[#0E172E] text-white-body hover:scale-[1.1] ${active == 'tickets' && 'scale-[1.2]'}`}>*/}
{/* <Icons name='settings' className='text-3xl' />*/}
{/*</button>*/}
{/*<button name='tasks' onClick={() => handleActiveMenu('tasks')} className={`flex justify-center items-center px-2 py-3 large:px-4 large:py-5 rounded-md shadow-round_white bg-[#0E172E] text-white-body hover:scale-[1.1] ${active == 'tasks' && 'scale-[1.2]'}`}>*/}
{/* <Icons name='dashboard' className='text-3xl' />*/}
{/*</button>*/}
</div>
{/* Body */}
{(isFetching || isError) ?
<div className=''>
{isError ? <p className='p-8 bg-white text-red-500'>{error.message}</p> :
<p className='text-white'>Loading...</p>}
</div>
:
<div className='w-full'>
{active === 'orders' && <Orders data={[1,2,3,4,5]} />}
{/*{active == 'tickets' && <Tickets />}*/}
{/*{active == 'tasks' && <Tasks />}*/}
</div>
}
</div>
)
}
+23 -27
View File
@@ -1,4 +1,5 @@
import {useEffect, useState} from 'react'
import { useQuery } from '@tanstack/react-query'
import {Link} from 'react-router-dom'
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
@@ -10,50 +11,45 @@ import getTimeFromDateString from '../../helpers/GetTimeFromDateString';
import localImgLoader from '../../helpers/localImageLoader';
import RouteLinks from '../../RouteLinks';
import localSiteIcons from '../../helpers/localSiteIcons';
import queryKeys from '../../services/queryKeys'
export default function TransactionsCom() {
const [page, setPage] = useState(1)
const [allTransactions, setAllTransaction] = useState({loading: true, error: '', data: {}})
const [willFilter, setWillFilter] = useState(false)
const [filter, setFilter] = useState({type: '', id: ''})
const handleFilter = ({target: {name, value}}) => {
setFilter(prev => ({...prev, [name]: value}))
const [willFilter, setWillFilter] = useState(false)
const handleFilter = ({target:{name, value}}) => {
setFilter(prev => ({...prev, [name]:value}))
}
const handleFilterByParams = () => {
if (filter.type && !filter.id) {
if(filter.type && !filter.id){
return
} else if (!filter.type) {
}else if(!filter.type){
setPage(1)
setWillFilter(prev => !prev)
setFilter({type: '', id: ''})
} else {
}else{
setPage(1)
setWillFilter(prev => !prev)
}
}
const transactions = allTransactions?.data?.transactions // TRANSACTIONS LIST
const pagination = allTransactions?.data?.pagination
const isFetching = allTransactions?.loading
const isError = allTransactions?.error
useEffect(() => {
setAllTransaction(prev => ({...prev, loading: true}))
const payload = filter?.type ? {[filter?.type]: filter.id} : {}
getTransactions({...payload, page}).then(res => {
if (res?.status != 200) {
setAllTransaction(prev => ({...prev, loading: false}))
return
const {data, isFetching, isError, error} = useQuery({
queryKey: [...queryKeys.transactions, page, willFilter],
queryFn: () => {
const filterData = filter?.type ? {[filter?.type]: filter.id} : {}
const reqData = {
page,
...filterData
}
setAllTransaction({loading: false, error: '', data: res?.data})
}).catch(err => {
setAllTransaction({loading: false, error: 'error occurred', data: {}})
console.log('ERR', err)
})
}, [page, willFilter])
return getTransactions(reqData)
},
staleTime: 0 //0 mins
})
const transactions = data?.data?.transactions // TRANSACTIONS LIST
const pagination = data?.data?.pagination
return (
<div className='w-full flex flex-col gap-8'>
@@ -61,7 +57,7 @@ export default function TransactionsCom() {
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
{isError ?
<p className='text-red-500'>{allTransactions?.error}</p>
<p className='text-red-500'>{error?.message}</p>
:
<>
{/* filter section */}
+4 -1
View File
@@ -1,7 +1,6 @@
const queryKeys = {
dashboard: ['dashboard'],
loans: ['loans'],
transactions: ['transactions'],
repayment_schedule: ['repayment-schedule'],
loan_charges: ['loan-charges'],
offers: ['offers'],
@@ -9,6 +8,10 @@ const queryKeys = {
select_loan: ['select-loan'],
approved_loan: ['approved-loan'],
loan_offers: ['loan-offers'],
//new
transactions: ['transactions'],
recent_loans: ['recent_loans'],
}
export default queryKeys
+2 -2
View File
@@ -15,7 +15,7 @@ axios.interceptors.request.use(
}
);
const postAuxEnd = (path, postData, media=false) => {
const basePath = media ? process.env.REACT_APP_EVENT_API : 'http://10.2.249.133:5000'
const basePath = media ? process.env.REACT_APP_EVENT_API : process.env.REACT_APP_EVENT_API
return axios.post(`${basePath}${path}`, postData).then(res => {
return res
}).catch(err => {
@@ -25,7 +25,7 @@ const postAuxEnd = (path, postData, media=false) => {
}
const getAuxEnd = (path, reqData= null) => {
const basePath = media ? process.env.REACT_APP_EVENT_API : 'http://10.2.249.133:5000'
const basePath = media ? process.env.REACT_APP_EVENT_API : process.env.REACT_APP_EVENT_API
return axios.get(`${basePath}${path}`,{ params: reqData }).then(res => {
return res
+6
View File
@@ -90,4 +90,10 @@ export const getOffers = (reqData) => {
export const getRepaymentSchedule = (reqData) => {
const postData = { ...reqData }
return getAuxEnd(`/repayment-schedules`, postData)
}
// FUNCTION TO GET RECENT LOANS
export const getRecentLoans = (reqData) => {
const postData = { ...reqData }
return getAuxEnd(`/recent-loans`, postData)
}