Compare commits

..

16 Commits

Author SHA1 Message Date
victorAnumudu 0d9fb7976d removed some build warnings 2025-09-09 19:09:41 +01:00
ameye b303af13f0 Merge branch 'usecontext-fix' of MERMS/MermsFirstOffice into master 2025-09-09 16:48:00 +00:00
victorAnumudu f2671c44a2 fixed use context error 2025-09-09 17:40:41 +01:00
CHIEFSOFT\ameye 59184d38aa Text xhANGES 2025-09-09 12:05:18 -04:00
CHIEFSOFT\ameye 73bc359a77 fix data 2025-09-02 17:03:43 -04:00
CHIEFSOFT\ameye 80fdd6e817 Fix text 2025-09-02 16:52:15 -04:00
ameye 0efa3ffa27 Merge branch 'bug-fix' of MERMS/MermsFirstOffice into master 2025-09-02 20:41:04 +00:00
victorAnumudu 96e6b6853c fixed page error 2025-09-02 20:49:25 +01:00
ameye eddbc7e13f Merge branch 'subscription-table-fix' of MERMS/MermsFirstOffice into master 2025-09-02 19:20:17 +00:00
victorAnumudu 691d9e72fe table fixed 2025-09-02 20:07:49 +01:00
CHIEFSOFT\ameye e4d6725dea fix names 2025-09-02 13:40:09 -04:00
CHIEFSOFT\ameye 607d64c709 removed unsused 2025-08-31 17:51:23 -04:00
CHIEFSOFT\ameye 882f781b75 removed unsused 2025-08-31 17:24:56 -04:00
Olusesan Ameye e9d30d6169 Envrionment support infrastructure 2025-08-27 03:00:35 +00:00
CHIEFSOFT\ameye baf96da5eb fix filter 2025-08-23 04:35:55 -04:00
ameye 88182bdbdf Merge branch 'customers-page' of MERMS/MermsFirstOffice into master 2025-08-22 16:46:21 +00:00
43 changed files with 451 additions and 263 deletions
+17 -1
View File
@@ -3,8 +3,22 @@
# FROM node:alpine
FROM node:22-alpine
# Build args
ARG NODE_ENV
ENV NODE_VERSION 14.19.0
ENV NODE_ENV=$NODE_ENV
# install nginx
RUN apk update
RUN apk add nginx
WORKDIR /app
COPY nginx.conf ./
COPY run.sh ./
COPY package.json .
RUN npm install
@@ -15,5 +29,7 @@ COPY . .
# CMD [ "npm", "run", "preview" ]
CMD [ "npm", "run", "start" ,"--", "--host"]
##CMD [ "npm", "run", "start" ,"--", "--host"]
CMD /bin/sh ./run.sh
+4
View File
@@ -5,10 +5,13 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_ENV=development
restart: unless-stopped
volumes:
- ./:/app
- '/app/node_modules'
- ./run.sh:/app/run.sh
ports:
- 8092:5173
expose:
@@ -21,6 +24,7 @@ services:
- socket.mermsemr.com:10.10.33.15
environment:
- PORT=${DIGIFI_PORT}
- NODE_ENV=${NODE_ENV:-production}
tty: true
stdin_open: true
volumes:
+29
View File
@@ -0,0 +1,29 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
server {
gzip on;
listen 3000;
server_name localhost;
root /usr/src/app/build;
include /etc/nginx/mime.types;
location /nginx_status {
stub_status on;
access_log off;
}
location / {
try_files $uri $uri/ /index.html;
}
}
}
+110 -14
View File
@@ -10,10 +10,13 @@
"dependencies": {
"@reduxjs/toolkit": "^2.5.1",
"@tanstack/react-query": "^5.66.0",
"apexcharts": "^4.5.0",
"axios": "^1.7.9",
"cra-template": "1.2.0",
"formik": "^2.4.6",
"react": "^19.0.0",
"react-apexcharts": "^1.7.0",
"react-countup": "^6.5.3",
"react-dom": "^19.0.0",
"react-icons": "^5.4.0",
"react-redux": "^9.2.0",
@@ -3255,6 +3258,62 @@
"string.prototype.matchall": "^4.0.6"
}
},
"node_modules/@svgdotjs/svg.draggable.js": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz",
"integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==",
"license": "MIT",
"peerDependencies": {
"@svgdotjs/svg.js": "^3.2.4"
}
},
"node_modules/@svgdotjs/svg.filter.js": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.filter.js/-/svg.filter.js-3.0.9.tgz",
"integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==",
"license": "MIT",
"dependencies": {
"@svgdotjs/svg.js": "^3.2.4"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/@svgdotjs/svg.js": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.4.tgz",
"integrity": "sha512-BjJ/7vWNowlX3Z8O4ywT58DqbNRyYlkk6Yz/D13aB7hGmfQTvGX4Tkgtm/ApYlu9M7lCQi15xUEidqMUmdMYwg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Fuzzyma"
}
},
"node_modules/@svgdotjs/svg.resize.js": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.resize.js/-/svg.resize.js-2.0.5.tgz",
"integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==",
"license": "MIT",
"engines": {
"node": ">= 14.18"
},
"peerDependencies": {
"@svgdotjs/svg.js": "^3.2.4",
"@svgdotjs/svg.select.js": "^4.0.1"
}
},
"node_modules/@svgdotjs/svg.select.js": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@svgdotjs/svg.select.js/-/svg.select.js-4.0.3.tgz",
"integrity": "sha512-qkMgso1sd2hXKd1FZ1weO7ANq12sNmQJeGDjs46QwDVsxSRcHmvWKL2NDF7Yimpwf3sl5esOLkPqtV2bQ3v/Jg==",
"license": "MIT",
"engines": {
"node": ">= 14.18"
},
"peerDependencies": {
"@svgdotjs/svg.js": "^3.2.4"
}
},
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz",
@@ -4301,6 +4360,12 @@
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"license": "Apache-2.0"
},
"node_modules/@yr/monotone-cubic-spline": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==",
"license": "MIT"
},
"node_modules/abab": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
@@ -4562,6 +4627,20 @@
"node": ">= 8"
}
},
"node_modules/apexcharts": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-4.7.0.tgz",
"integrity": "sha512-iZSrrBGvVlL+nt2B1NpqfDuBZ9jX61X9I2+XV0hlYXHtTwhwLTHDKGXjNXAgFBDLuvSYCB/rq2nPWVPRv2DrGA==",
"license": "MIT",
"dependencies": {
"@svgdotjs/svg.draggable.js": "^3.0.4",
"@svgdotjs/svg.filter.js": "^3.0.8",
"@svgdotjs/svg.js": "^3.2.4",
"@svgdotjs/svg.resize.js": "^2.0.2",
"@svgdotjs/svg.select.js": "^4.0.1",
"@yr/monotone-cubic-spline": "^1.0.3"
}
},
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
@@ -5949,6 +6028,12 @@
"node": ">=10"
}
},
"node_modules/countup.js": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.9.0.tgz",
"integrity": "sha512-llqrvyXztRFPp6+i8jx25phHWcVWhrHO4Nlt0uAOSKHB8778zzQswa4MU3qKBvkXfJKftRYFJuVHez67lyKdHg==",
"license": "MIT"
},
"node_modules/cra-template": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/cra-template/-/cra-template-1.2.0.tgz",
@@ -13776,6 +13861,19 @@
"node": ">=0.10.0"
}
},
"node_modules/react-apexcharts": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.7.0.tgz",
"integrity": "sha512-03oScKJyNLRf0Oe+ihJxFZliBQM9vW3UWwomVn4YVRTN1jsIR58dLWt0v1sb8RwJVHDMbeHiKQueM0KGpn7nOA==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"apexcharts": ">=4.0.0",
"react": ">=0.13"
}
},
"node_modules/react-app-polyfill": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz",
@@ -13799,6 +13897,18 @@
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"license": "MIT"
},
"node_modules/react-countup": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/react-countup/-/react-countup-6.5.3.tgz",
"integrity": "sha512-udnqVQitxC7QWADSPDOxVWULkLvKUWrDapn5i53HE4DPRVgs+Y5rr4bo25qEl8jSh+0l2cToJgGMx+clxPM3+w==",
"license": "MIT",
"dependencies": {
"countup.js": "^2.8.0"
},
"peerDependencies": {
"react": ">= 16.3.0"
}
},
"node_modules/react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -16472,20 +16582,6 @@
"is-typedarray": "^1.0.0"
}
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/unbox-primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+2 -1
View File
@@ -22,7 +22,8 @@
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build_RE": "react-scripts build",
"build": "GENERATE_SOURCEMAP=false react-scripts build -e .env.production",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
+1 -1
View File
@@ -7,7 +7,7 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="digiFi global back office systems"
content="MERMS BackOffice Systems"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
Executable
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env sh
set -e
set -x
export NODE_ENV="${NODE_ENV:-development}"
if [ $NODE_ENV = "development" ]; then
# this runs webpack-dev-server with hot reloading
echo "Development build"
npm install --legacy-peer-deps
npm run start -- --host
# npm run build
elif [ $NODE_ENV = "qa" -o $NODE_ENV = "test" ]; then
echo "QA build"
export NODE_ENV="test"
npm install --legacy-peer-deps
npm run start -- --host
else
# build the app and serve it via nginx
echo "Production build"
npm install --legacy-peer-deps
npm run build
# Testing sometimes
# npm run start
nginx -g 'daemon off;' -c /usr/src/app/nginx.conf
nginx -c /usr/src/app/nginx.conf
fi
+2 -2
View File
@@ -4,7 +4,7 @@ import { QueryClientProvider, QueryClient } from '@tanstack/react-query'
import SiteRoutes from './SiteRoutes';
import LogoutModal from './components/layouts/LogoutModal';
import { generalLayoutContext } from './context/GeneralLayoutContext';
import { GeneralLayoutContext } from './context/GeneralLayoutContext';
import './App.css';
@@ -24,7 +24,7 @@ function App() {
const {pathname} = useLocation()
const {logoutModal, setLogoutModal} = generalLayoutContext()
const {logoutModal, setLogoutModal} = GeneralLayoutContext()
useEffect(()=>{
window.scrollTo(0,0)
+1 -1
View File
@@ -1,4 +1,4 @@
import { lazy, Suspense } from 'react'
import { Suspense } from 'react'
import { Routes, Route } from 'react-router-dom'
import RouteLinks from './RouteLinks'
+18 -18
View File
@@ -16,41 +16,41 @@ import { FaLongArrowAltRight, FaFilter } from "react-icons/fa";
export default function Icons({name, className}) {
return (
<>
{name.toLowerCase() == 'dashboard' ?
{name.toLowerCase() === 'dashboard' ?
<AiOutlineDashboard className={`text-base ${className}`} />
: name.toLowerCase() == 'money' ?
: name.toLowerCase() === 'money' ?
<FaRegMoneyBill1 className={`text-base ${className}`} />
:name.toLowerCase() == 'dot' ?
:name.toLowerCase() === 'dot' ?
<GoDotFill className={`text-base ${className}`} />
:name.toLowerCase() == 'people' ?
:name.toLowerCase() === 'people' ?
<IoPeople className={`text-base ${className}`} />
:name.toLowerCase() == 'product' ?
:name.toLowerCase() === 'product' ?
<AiFillProduct className={`text-base ${className}`} />
:name.toLowerCase() == 'trash' ?
:name.toLowerCase() === 'trash' ?
<IoTrash className={`text-base ${className}`} />
:name.toLowerCase() == 'eye' ?
:name.toLowerCase() === 'eye' ?
<FaEye className={`text-base ${className}`} />
:name.toLowerCase() == 'next' ?
:name.toLowerCase() === 'next' ?
<TbPlayerTrackNext className={`text-base ${className}`} />
:name.toLowerCase() == 'prev' ?
:name.toLowerCase() === 'prev' ?
<TbPlayerTrackPrev className={`text-base ${className}`} />
:name.toLowerCase() == 'edit' ?
:name.toLowerCase() === 'edit' ?
<FaEdit className={`text-base ${className}`} />
:name.toLowerCase() == 'settings' ?
:name.toLowerCase() === 'settings' ?
<IoMdSettings className={`text-base ${className}`} />
:name.toLowerCase() == 'message' ?
:name.toLowerCase() === 'message' ?
<LuMessageSquareText className={`text-base ${className}`} />
:name.toLowerCase() == 'right-panel' ?
:name.toLowerCase() === 'right-panel' ?
<LuPanelRight className={`text-base ${className}`} />
:name.toLowerCase() == 'google' ?
:name.toLowerCase() === 'google' ?
<FcGoogle className={`text-base ${className}`} />
:name.toLowerCase() == 'apple' ?
:name.toLowerCase() === 'apple' ?
<IoLogoApple className={`text-base ${className}`} />
:name.toLowerCase() == 'sales' ?
:name.toLowerCase() === 'sales' ?
<FcSalesPerformance className={`text-base ${className}`} />
:name.toLowerCase() == 'arrow-right' ?
:name.toLowerCase() === 'arrow-right' ?
<FaLongArrowAltRight className={`text-base ${className}`} />
:name.toLowerCase() == 'filter' ?
:name.toLowerCase() === 'filter' ?
<FaFilter className={`text-base ${className}`} />
:
null
+4 -3
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { useLocation, useNavigate, Link } from 'react-router-dom'
import { useNavigate, Link } from 'react-router-dom'
import { useMutation } from '@tanstack/react-query'
import {Formik, Form} from 'formik'
import * as Yup from "yup";
@@ -10,7 +10,7 @@ import { updateUserDetails } from "../../store/UserDetails";
import { loginUser } from '../../services/siteServices'
import RouteLinks from '../../RouteLinks'
import Icons from '../Icons'
// import Icons from '../Icons'
const initialValues = {
@@ -49,6 +49,7 @@ export default function LoginCom() {
const data = {jwt_token}
dispatch(updateUserDetails({ ...data, ...user }));
}
setLoading(false)
navigate(RouteLinks.homePage, {state:{proceed:'true'}}) // later add redux to dispatch state
}
})
+15 -16
View File
@@ -1,25 +1,24 @@
import { useEffect, useState } from 'react'
import { MdKeyboardDoubleArrowRight } from 'react-icons/md'
import { TiHomeOutline } from 'react-icons/ti'
import DashboardHeader from '../layouts/DashboardHeader'
export default function BreadcrumbCom({title, span, paths}) {
const [stickNav, setStickNav] = useState(false)
// const [stickNav, setStickNav] = useState(false)
useEffect(()=>{
// var rect = navRef?.current?.getBoundingClientRect()?.bottom;
var rect = 10;
window.addEventListener('scroll', ()=>{
if(window.scrollY >= rect + 20){
setStickNav(true)
console.log('tru')
}else{
setStickNav(false)
console.log('false')
}
})
},[])
// useEffect(()=>{
// // var rect = navRef?.current?.getBoundingClientRect()?.bottom;
// var rect = 10;
// window.addEventListener('scroll', ()=>{
// if(window.scrollY >= rect + 20){
// setStickNav(true)
// console.log('tru')
// }else{
// setStickNav(false)
// console.log('false')
// }
// })
// },[])
return (
// ${stickNav ? 'sticky top-0 transition-[top] duration-1000 shadow-md shadow-black' : '-top-[100px] static'}
@@ -35,7 +34,7 @@ export default function BreadcrumbCom({title, span, paths}) {
{paths.map((item, index) => (
<div className='flex gap-2 items-center text-black dark:text-white-body text-10 sm:text-sm' key={index}>
<MdKeyboardDoubleArrowRight />
<p className={`${index + 1 == paths.length ? 'text-sky-600 dark:text-white-body/70' : ''}`}>{item}</p>
<p className={`${index + 1 === paths.length ? 'text-sky-600 dark:text-white-body/70' : ''}`}>{item}</p>
</div>
))}
</div>
+3 -3
View File
@@ -6,9 +6,9 @@ import TablePaginatedWrapper from '../tableWrapper/TablePaginatedWrapper'
import Icons from '../Icons'
import { getCustomers } from '../../services/siteServices'
import getDateFromDateString from '../../helpers/GetDateFromDateString';
import getTimeFromDateString from '../../helpers/GetTimeFromDateString';
import localImgLoader from '../../helpers/localImageLoader';
import RouteLinks from '../../RouteLinks';
// import getTimeFromDateString from '../../helpers/GetTimeFromDateString';
// import localImgLoader from '../../helpers/localImageLoader';
// import RouteLinks from '../../RouteLinks';
export default function CustomerCom() {
+3 -1
View File
@@ -124,7 +124,7 @@ export default function HomeCom() {
</td>
<td className="px-2">
<div className="text-left">
<div className="text-base font-semibold"><a href={`https://${item?.internal_url}`} target='_blank'>{item?.internal_url}</a></div>
<div className="text-base font-semibold"><a href={`https://${item?.internal_url}`} target='_blank' rel="noreferrer">{item?.internal_url}</a></div>
<div className="font-normal text-gray-500">{item?.status}</div>
</div>
</td>
@@ -153,6 +153,8 @@ export default function HomeCom() {
</td>
</tr>
)
}else{
return null
}
}
)
+4 -4
View File
@@ -1,7 +1,7 @@
import { LuSunDim } from "react-icons/lu";
import { IoMdSunny } from "react-icons/io";
import { generalLayoutContext } from "../../context/GeneralLayoutContext"
import { GeneralLayoutContext } from "../../context/GeneralLayoutContext"
import UserAvatar from '../../assets/user_avatar.jpg'
import HandBurger from "./HandBurger"
@@ -15,7 +15,7 @@ export default function DashboardHeader() {
// let {pathname} = useLocation()
const {theme, handleTheme, setLogoutModal, activeMenu, handleActiveMenu, showAsideDrawer, setShowAsideDrawer} = generalLayoutContext()
const {theme, handleTheme, setLogoutModal, activeMenu, handleActiveMenu, showAsideDrawer, setShowAsideDrawer} = GeneralLayoutContext()
return (
<>
@@ -47,7 +47,7 @@ export default function DashboardHeader() {
{/* THEME SELECTION */}
<div onClick={handleTheme} className='w-10 h-10 border border-slate-300 text-slate-500 dark:text-white-body rounded-md px-2 flex justify-center items-center gap-2 cursor-pointer' title='Switch Color Mode'>
{theme == 'dark' ?
{theme === 'dark' ?
<IoMdSunny className="text-sm md:text-xl font-bold" />
:
<LuSunDim className="text-sm md:text-xl font-bold" />
@@ -56,7 +56,7 @@ 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' &&
{activeMenu === 'avatar' &&
<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">
+7 -7
View File
@@ -1,7 +1,7 @@
import { Outlet } from 'react-router-dom'
import DashboardHeader from './DashboardHeader'
import { generalLayoutContext } from '../../context/GeneralLayoutContext'
import { GeneralLayoutContext } from '../../context/GeneralLayoutContext'
import DashboardAside from './aside/DashboardAside'
import RightAsideBar from './rightaside/RightAsideBar'
@@ -9,7 +9,7 @@ export default function DashboardLayout() {
// let {pathname} = useLocation()
const {showAsideDrawer, setShowAsideDrawer} = generalLayoutContext()
const {showAsideDrawer, setShowAsideDrawer} = GeneralLayoutContext()
return (
<div className='w-full flex gap-10 relative m-auto h-screen overflow-x-hidden overflow-y-auto bg-white-body dark:bg-black-body p-8 pt-0 lg:p-10'>
@@ -17,8 +17,8 @@ export default function DashboardLayout() {
<DashboardAside />
</div>
<div className={`${showAsideDrawer =='aside' ? 'left-0' : '-left-full'} lg:hidden w-full fixed inset-0 z-[999]`}>
<div className={`${showAsideDrawer =='aside' ? 'fixed left-0 top-0 inset-0' : '-left-full'} w-full bg-[rgba(0,_0,_0,_0.2)] dark:bg-[rgba(0,_0,_0,_0.4)] transition-all cursor-pointer`} onClick={()=>setShowAsideDrawer('')} ></div>
<div className={`${showAsideDrawer ==='aside' ? 'left-0' : '-left-full'} lg:hidden w-full fixed inset-0 z-[999]`}>
<div className={`${showAsideDrawer ==='aside' ? 'fixed left-0 top-0 inset-0' : '-left-full'} w-full bg-[rgba(0,_0,_0,_0.2)] dark:bg-[rgba(0,_0,_0,_0.4)] transition-all cursor-pointer`} onClick={()=>setShowAsideDrawer('')} ></div>
<div className={`fixed px-8 py-4 h-full w-4/5 sm:w-[400px] bg-white-aside dark:bg-black-aside dark:text-white-light`}>
<DashboardAside />
</div>
@@ -45,9 +45,9 @@ export default function DashboardLayout() {
<div className={`px-8 py-4 hidden large:flex fixed right-5 top-0 bottom-0 sm:w-[400px] bg-[#192440] dark:bg-[#1E1E2D] text-white-body`}>
<RightAsideBar />
</div>
<div className={`${showAsideDrawer =='right-aside' ? 'right-0 w-full' : '-right-full w-0'} fixed inset-0 z-[999] large:hidden bg-[rgba(0,_0,_0,_0.2)] dark:bg-[rgba(0,_0,_0,_0.4)] transition-all cursor-pointer`} onClick={()=>setShowAsideDrawer('')}>
{/* <div className={`${showAsideDrawer =='right-aside' ? 'right-0' : '-right-full'} fixed z-[999] right-0 top-0 inset-0 w-full bg-white/20 bg-red-400 transition-all cursor-pointer`} onClick={()=>setShowAsideDrawer('')} ></div> */}
<div onClick={(e)=>e.stopPropagation()} className={`${showAsideDrawer =='right-aside' ? 'right-0' : '-right-full'} fixed z-[999] top-0 botom-0 px-8 py-4 h-full w-4/5 sm:w-[400px] bg-[#192440] dark:bg-[#1E1E2D] text-white-body`}>
<div className={`${showAsideDrawer ==='right-aside' ? 'right-0 w-full' : '-right-full w-0'} fixed inset-0 z-[999] large:hidden bg-[rgba(0,_0,_0,_0.2)] dark:bg-[rgba(0,_0,_0,_0.4)] transition-all cursor-pointer`} onClick={()=>setShowAsideDrawer('')}>
{/* <div className={`${showAsideDrawer ==='right-aside' ? 'right-0' : '-right-full'} fixed z-[999] right-0 top-0 inset-0 w-full bg-white/20 bg-red-400 transition-all cursor-pointer`} onClick={()=>setShowAsideDrawer('')} ></div> */}
<div onClick={(e)=>e.stopPropagation()} className={`${showAsideDrawer ==='right-aside' ? 'right-0' : '-right-full'} fixed z-[999] top-0 botom-0 px-8 py-4 h-full w-4/5 sm:w-[400px] bg-[#192440] dark:bg-[#1E1E2D] text-white-body`}>
<RightAsideBar />
</div>
</div>
+3 -3
View File
@@ -11,21 +11,21 @@ export default function HandBurger({showAside, barColor}) {
></div> */}
<div
className={`absolute left-0 w-5 h-1 rounded-md ${barColor ? barColor :'bg-black-box'} dark:bg-white-light ${
showAside =='aside'
showAside ==='aside'
? "bottom-1/2 translate-y-1/2 rotate-45"
: ""
}`}
></div>
<div
className={`absolute left-0 top-1/2 -translate-y-1/2 w-5 h-1 rounded-md ${barColor ? barColor :'bg-black-box/50'} dark:bg-white-light transition-all duration-300 ${
showAside =='aside'
showAside ==='aside'
? "rotate-[2000deg] opacity-0"
: ""
}`}
></div>
<div
className={`absolute left-0 w-5 h-1 rounded-md ${barColor ? barColor :'bg-black-box/50'} dark:bg-white-light ${
showAside =='aside'
showAside ==='aside'
? "top-1/2 -translate-y-1/2 -rotate-45"
: "bottom-0"
}`}
@@ -4,7 +4,6 @@ import { FaArrowRight, FaArrowLeft } from "react-icons/fa6";
import DashboardAside from './aside/DashboardAside'
import DashboardHeader from './DashboardHeader'
import { generalLayoutContext } from '../../context/GeneralLayoutContext'
export default function DashboardLayout() {
const [shrinkAside, setShrinkAside] = useState(false)
+3 -3
View File
@@ -1,16 +1,16 @@
import { Link, useLocation } from "react-router-dom"
import Icons from "../../Icons"
import { generalLayoutContext } from "../../../context/GeneralLayoutContext"
import { GeneralLayoutContext } from "../../../context/GeneralLayoutContext"
export default function AsideLink({name, to, icon}) {
const {shrinkAside, setShowAsideDrawer} = generalLayoutContext()
const {shrinkAside, setShowAsideDrawer} = GeneralLayoutContext()
const {pathname} = useLocation()
return (
<Link
className={`w-full flex items-center gap-2 px-4 py-2 my-1 text-[13px] sm:text-sm font-semibold rounded-md hover:bg-white dark:hover:bg-black-box text-slate-500 dark:text-white-body/80 ${pathname == to ? 'bg-white-body dark:bg-black-box' : ''}`}
className={`w-full flex items-center gap-2 px-4 py-2 my-1 text-[13px] sm:text-sm font-semibold rounded-md hover:bg-white dark:hover:bg-black-box text-slate-500 dark:text-white-body/80 ${pathname === to ? 'bg-white-body dark:bg-black-box' : ''}`}
to={to}
onClick={()=>setShowAsideDrawer(false)}
>
@@ -1,17 +1,17 @@
import { useState } from "react";
import { useLocation } from "react-router-dom"
// import { useLocation } from "react-router-dom"
import { FaCaretDown } from "react-icons/fa";
import Icons from "../../Icons";
import { generalLayoutContext } from "../../../context/GeneralLayoutContext";
import { GeneralLayoutContext } from "../../../context/GeneralLayoutContext";
export default function AsideLinkWithSubLinks({name, icon, to, children, isOpen}) {
const {shrinkAside} = generalLayoutContext()
const {shrinkAside} = GeneralLayoutContext()
const {pathname} = useLocation()
// const {pathname} = useLocation()
const isMatchedPath = pathname.split('/').includes('')
// const isMatchedPath = pathname.split('/').includes('')
// isMatchedPath.splice(0,1)
const [hideSubMenu, setHideSubMenu] = useState(isOpen)
+15 -24
View File
@@ -4,8 +4,8 @@ import DummyLogo from "../../DummyLogo";
import MainBtn from "../../MainBtn";
import AsideLink from "./AsideLink";
import AsideLinkWithSubLinks from "./AsideLinkWithSubLinks";
import { useSelector } from "react-redux";
import { generalLayoutContext } from "../../../context/GeneralLayoutContext";
// import { useSelector } from "react-redux";
import { GeneralLayoutContext } from "../../../context/GeneralLayoutContext";
import { TbLogout2 } from "react-icons/tb";
import UserAvatar from '../../../assets/user_avatar.jpg'
import Icons from "../../Icons";
@@ -14,10 +14,10 @@ export default function DashboardAside() {
const {pathname} = useLocation()
const {setLogoutModal, activeMenu, handleActiveMenu} = generalLayoutContext()
const {setLogoutModal, handleActiveMenu} = GeneralLayoutContext()
const {userDetails} = useSelector((state) => state.userDetails) // GETS LOGGED IN USER ROLE DETAILS
const {role}= userDetails
// const {userDetails} = useSelector((state) => state.userDetails) // GETS LOGGED IN USER ROLE DETAILS
// const {role}= userDetails
return (
<div className='w-full h-full flex flex-col'>
@@ -28,7 +28,7 @@ export default function DashboardAside() {
<div className="aside-scroll-design w-full flex flex-col gap-2 h-full overflow-y-auto">
{asideNavLinks.map((link, index) => {
let active = link.status == 1 ? true : false
let active = link.status === 1 ? true : false
let hasSubLinks = (link.subLinks && link.subLinks.length > 0) ? true : false
if(active && !hasSubLinks){
return (
@@ -53,10 +53,10 @@ export default function DashboardAside() {
{link.title &&
<h1 className="px-4 py-2 text-sm sm:text-sm text-slate-500 dark:text-white font-semibold uppercase mt-3 mb-1 border-b border-slate-500 dark:border-white">{link.title}</h1>
}
<AsideLinkWithSubLinks name={link.name} icon={link.icon} isOpen={subLinkList.includes(pathname) || index==1} >
<AsideLinkWithSubLinks name={link.name} icon={link.icon} isOpen={subLinkList.includes(pathname) || index===1} >
<>
{link.subLinks.map((subItem, index)=>{
let active = subItem.status == 1 ? true : false
let active = subItem.status === 1 ? true : false
let hasSubLinks = (subItem.subLinks && subItem.subLinks.length > 0) ? true : false
if(active && !hasSubLinks){
return (
@@ -74,13 +74,15 @@ export default function DashboardAside() {
<AsideLinkWithSubLinks key={subItem.name} name={subItem.name} icon={subItem.icon} isOpen={subLinkList.includes(pathname)}>
<>
{subItem.subLinks.map((item, index)=>{
let active = item.status == 1 ? true : false
let active = item.status === 1 ? true : false
if(active){
return (
<div key={index}>
<AsideLink key={index} to={item.to} name={item.name} icon={item.icon} />
</div>
)
}else{
return null
}
})}
</>
@@ -94,6 +96,8 @@ export default function DashboardAside() {
</AsideLinkWithSubLinks>
</div>
)
}else{
return null
}
})}
</div>
@@ -139,27 +143,14 @@ const asideNavLinks = [
{name:'Dashboard', status:1, icon: 'dashboard', to: RouteLinks.homePage},
{name:'Deployments', title:'Activities', status:1, icon: 'arrow-right', subLinks: [
{name: 'Active', status:1, icon: 'dot', to: RouteLinks.transactionsPage},
{name: 'Subscriptions', status:1, icon: 'dot', to: RouteLinks.subscriptions},
{name: 'Provisions', status:1, icon: 'dot', to: RouteLinks.subscriptions},
{name: 'Customers', status:1, icon: 'dot', to: RouteLinks.customerPage},
{name: 'Billings', status:1, icon: 'dot', to: RouteLinks.billings},
{name: 'Configurations', status:1, icon: 'arrow-right', subLinks: [
{name: 'Product Settings', status:1, icon: 'dot', to: RouteLinks.offers },
{name: 'Manage 2', status:1, icon: 'dot', to: RouteLinks.offers },
{name: 'Admin Manager', status:1, icon: 'dot', to: RouteLinks.offers },
]
},
],
},
// {name:'Product 2', title:'Product 2', status:1, icon: 'product', subLinks: [
// {name: 'Applications', status:1, icon: 'dot', to: ''},
// ]
// },
// {name:'Product 3', title:'Product 3', status:1, icon: 'product', subLinks: [
// {name: 'Applications', status:1, icon: 'dot', to: ''},
// {name: 'Configuration', status:1, icon: 'dot', to: ''},
// ]
// },
// {name:'Administration', title:'Admin', status:1, icon: 'people', subLinks: [
// {name: 'Users', status:1, icon: 'dot', to: RouteLinks.usersPage},
// ]
// },
]
@@ -6,7 +6,7 @@ import MainBtn from "../../MainBtn";
import AsideLink from "./AsideLink";
import AsideLinkWithSubLinks from "./AsideLinkWithSubLinks";
import { useSelector } from "react-redux";
import { generalLayoutContext } from "../../../context/GeneralLayoutContext";
import { GeneralLayoutContext } from "../../../context/GeneralLayoutContext";
import { TbLogout2 } from "react-icons/tb";
@@ -14,7 +14,7 @@ export default function DashboardAside({shrinkAside=false}) {
const {pathname} = useLocation()
const {setLogoutModal} = generalLayoutContext()
const {setLogoutModal} = GeneralLayoutContext()
const {userDetails} = useSelector((state) => state.userDetails) // GETS LOGGED IN USER ROLE DETAILS
const {role}= userDetails
@@ -6,7 +6,7 @@ import MainBtn from "../../MainBtn";
import AsideLink from "./AsideLink";
import AsideLinkWithSubLinks from "./AsideLinkWithSubLinks";
import { useSelector } from "react-redux";
import { generalLayoutContext } from "../../../context/GeneralLayoutContext";
import { GeneralLayoutContext } from "../../../context/GeneralLayoutContext";
import { TbLogout2 } from "react-icons/tb";
@@ -14,7 +14,7 @@ export default function DashboardAside({shrinkAside=false}) {
const {pathname} = useLocation()
const {setLogoutModal} = generalLayoutContext()
const {setLogoutModal} = GeneralLayoutContext()
const {userDetails} = useSelector((state) => state.userDetails) // GETS LOGGED IN USER ROLE DETAILS
const {role}= userDetails
+4 -4
View File
@@ -39,7 +39,7 @@ export default function Orders() {
<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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -48,7 +48,7 @@ export default function Orders() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -57,7 +57,7 @@ export default function Orders() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -66,7 +66,7 @@ export default function Orders() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -17,21 +17,21 @@ export default function RightAsideBar() {
<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]'}`}>
<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]'}`}>
<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]'}`}>
<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 */}
{active == 'orders' && <Orders />}
{active == 'tickets' && <Tickets />}
{active == 'tasks' && <Tasks />}
{active === 'orders' && <Orders />}
{active === 'tickets' && <Tickets />}
{active === 'tasks' && <Tasks />}
</div>
)
}
+4 -4
View File
@@ -39,7 +39,7 @@ export default function Tasks() {
<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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -48,7 +48,7 @@ export default function Tasks() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -57,7 +57,7 @@ export default function Tasks() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -66,7 +66,7 @@ export default function Tasks() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -39,7 +39,7 @@ export default function Tickets() {
<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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -48,7 +48,7 @@ export default function Tickets() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -57,7 +57,7 @@ export default function Tickets() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
@@ -66,7 +66,7 @@ export default function Tickets() {
</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" />
<img src={Img} className='w-8' alt="Order" />
</div>
<div className='flex-col'>
<p className='text-base font-bold text-white-body'>Project Briefing</p>
+48 -50
View File
@@ -1,21 +1,22 @@
import { useEffect, useState } from 'react'
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
import queryKeys from '../../services/queryKeys'
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
import TablePaginatedWrapper from '../tableWrapper/TablePaginatedWrapper'
import Icons from '../Icons'
import { getBillings } from '../../services/siteServices'
import getDateFromDateString from '../../helpers/GetDateFromDateString';
import formatNumber from '../../helpers/formatNumber'
import Avatar from '../../assets/user_avatar.jpg'
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
// import formatNumber from '../../helpers/formatNumber'
// import Avatar from '../../assets/user_avatar.jpg'
export default function BillingsCom() {
const [page, setPage] = useState(1)
const [allBillings, setAllBillings] = useState({loading:true, error:'', data:{}})
const [willFilter, setWillFilter] = useState(false)
const [filter, setFilter] = useState({type: '', id: ''})
const [willFilter, setWillFilter] = useState(false)
const handleFilter = ({target:{name, value}}) => {
setFilter(prev => ({...prev, [name]:value}))
}
@@ -33,25 +34,20 @@ export default function BillingsCom() {
}
}
const billings = allBillings?.data?.loan_charges // LOAN CHARGES LIST
const pagination = allBillings?.data?.pagination
const isFetching = allBillings?.loading
const isError = allBillings?.error
useEffect(()=>{
setAllBillings(prev => ({...prev, loading:true}))
const payload = filter?.type ? {[filter?.type]: filter.id} : {}
getBillings({...payload, page}).then(res => {
if(res?.status != 200){
setAllBillings(prev => ({...prev, error:'Opps, an error occurred', loading:false}))
return
const {data, isFetching, isError, error} = useQuery({
queryKey: [...queryKeys.billings, page, willFilter],
queryFn: () => {
const filterData = filter?.type ? {[filter?.type]: filter.id} : {}
const reqData = {
page,
...filterData
}
setAllBillings({loading:false, error:'', data:res?.data})
}).catch(err => {
setAllBillings({loading:false, error:'error occurred', data:{}})
console.log('ERR', err)
})
},[page, willFilter])
return getBillings(reqData)
},
staleTime: 0 //0 mins
})
const billingData = data?.data?.payments // BILLINGS LIST
const pagination = data?.data?.pagination
return (
<div className='w-full flex flex-col gap-8'>
@@ -59,7 +55,7 @@ export default function BillingsCom() {
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
{ isError ?
<p className='text-red-500'>{allBillings?.error}</p>
<p className='text-red-500'>{error?.message}</p>
:
<>
{/* filter section */}
@@ -68,8 +64,9 @@ export default function BillingsCom() {
<div className='w-full sm:max-w-48'>
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md' onChange={handleFilter}>
<option value=''>All</option>
<option value='transaction_id'>Transaction ID</option>
<option value='account_id'>Account ID</option>
<option value='option_name'>Option Name</option>
<option value='member_id'>Member ID</option>
</select>
</div>
<div className='w-full sm:max-w-48'>
@@ -79,26 +76,26 @@ export default function BillingsCom() {
</div>
{/* end of filter section */}
<TablePaginatedWrapper data={billings} isFetching={isFetching} setPage={setPage} itemsPerPage={pagination?.limit} pagination={pagination}>
<TablePaginatedWrapper data={billingData} isFetching={isFetching} setPage={setPage} itemsPerPage={pagination?.limit} pagination={pagination}>
{({ data }) => (
<>
<table className="py-2 w-full text-sm">
<thead className="py-2 text-sm text-slate-500 text-left">
<tr>
<th scope="col" className="px-2 py-2">
Name
Added
</th>
<th scope="col" className="px-2">
Option Name
</th>
<th scope="col" className="px-2">
Member ID
</th>
{/* <th scope="col" className="px-2">
Loan
</th> */}
<th scope="col" className="px-2 text-right">
Amount
</th>
<th scope="col" className="px-2 text-right">
Added
</th>
<th scope="col" className="px-2 text-right">
Action
Status
</th>
</tr>
</thead>
@@ -107,31 +104,32 @@ export default function BillingsCom() {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<div className="text-left">
<div className="text-base font-semibold">{item?.transaction_id || ''}</div>
<div className="font-normal text-gray-500 line-clamp-1">{item?.code}</div>
<div className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
</div>
</div>
</td>
<td className="px-2">
<div className="text-left">
<div className="text-base font-semibold">{item?.option_name}</div>
</div>
</td>
<td className="px-2">
<div className="text-left">
<div className="text-base font-semibold">{item?.member_id}</div>
</div>
</td>
<td className="px-2">
<div className="text-right">
{/* <div className="text-base font-semibold">{formatNumber(item?.initial_loan_amount)}</div> */}
<div className="font-normal text-gray-500">{formatNumber(item?.amount)}</div>
<div className="text-base font-semibold">${item?.amount}</div>
{/* <div className="font-normal text-gray-500">{item?.external_url}</div> */}
</div>
</td>
<td className="px-2">
<div className="text-right">
<div className="font-normal text-gray-500">{getDateFromDateString(item?.created_at)}</div>
<div className="text-base font-semibold">{item?.status}</div>
</div>
</td>
<td className="px-2 text-right">
<div className='flex items-center justify-end gap-3 md:gap-4'>
<div className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
<Icons name='eye' />
</div>
</div>
</td>
</tr>
))
:
+1 -1
View File
@@ -111,7 +111,7 @@ export default function LoansCom() {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese" />
<div className="text-left">
<div className="text-base font-semibold">{item?.account_id || ''}</div>
<div className="font-normal text-gray-500">{item?.id} : {item?.transaction_id}</div>
+2 -2
View File
@@ -8,7 +8,7 @@ import Icons from '../Icons'
import Avatar from '../../assets/user_avatar.jpg'
import queryKeys from '../../services/queryKeys'
import { getOffers } from '../../services/siteServices'
import getDateFromDateString from '../../helpers/GetDateFromDateString';
// import getDateFromDateString from '../../helpers/GetDateFromDateString';
import formatNumber from '../../helpers/formatNumber';
export default function OffersCom() {
@@ -72,7 +72,7 @@ export default function OffersCom() {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese" />
<div className="text-left">
<div className="text-base font-semibold">{item?.product_id || ''}</div>
{/* <div className="font-normal text-gray-500 line-clamp-1">{item?.description}</div> */}
+1 -1
View File
@@ -103,7 +103,7 @@ export default function RepaymentsCom() {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese" />
<div className="text-left">
<div className="text-base font-semibold">{item?.customer_id || ''}</div>
<div className="font-normal text-gray-500">{item?.loan_id} : {item?.transaction_id}</div>
@@ -1,4 +1,4 @@
import { useState } from "react";
// import { useState } from "react";
import MainBtn from "../MainBtn";
import Icons from "../Icons";
@@ -1,11 +1,11 @@
import React, { useState } from 'react'
import { useQuery } from "@tanstack/react-query";
import Icons from '../Icons'
// import Icons from '../Icons'
import Avatar from '../../assets/user_avatar.jpg'
import queryKeys from '../../services/queryKeys'
import { getLoanCharges } from '../../services/siteServices'
//import { getLoanCharges } from '../../services/siteServices'
import getDateFromDateString from '../../helpers/GetDateFromDateString';
import formatNumber from '../../helpers/formatNumber';
@@ -15,7 +15,7 @@ export default function LoanChargeDetails({transactionID}) {
const {data, isFetching, isError, error} = useQuery({
queryKey: [...queryKeys.loan_charges, page],
queryFn: () => getLoanCharges({transaction_id: transactionID, page}),
// queryFn: () => getLoanCharges({transaction_id: transactionID, page}),
staleTime: 0,
// placeholderData: keepPreviousData,
})
@@ -58,7 +58,7 @@ export default function LoanChargeDetails({transactionID}) {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese" />
<div className="text-left">
<div className="text-base font-semibold">{item?.transaction_id || ''}</div>
{/* <div className="font-normal text-gray-500 line-clamp-1">{item?.description}</div> */}
@@ -62,7 +62,7 @@ export default function LoanDetails({transactionID}) {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese" />
<div className="text-left">
<div className="text-base font-semibold">{item?.account_id || ''}</div>
<div className="font-normal text-gray-500">{item?.id} : {item?.transaction_id}</div>
@@ -68,7 +68,7 @@ export default function RepaymentScheduleDetails({transactionID}) {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese image" />
<img className="w-10 h-10 rounded-md" src={Avatar} alt="Jese" />
<div className="text-left">
<div className="text-base font-semibold">{item?.loan_id || ''}</div>
{/* <div className="font-normal text-gray-500 line-clamp-1">{item?.description}</div> */}
@@ -4,7 +4,7 @@ import { useQuery } from "@tanstack/react-query";
import Icons from '../Icons'
import queryKeys from '../../services/queryKeys'
import { getTransactions } from '../../services/siteServices'
//import { getTransactions } from '../../services/siteServices'
import getDateFromDateString from '../../helpers/GetDateFromDateString';
import getTimeFromDateString from '../../helpers/GetTimeFromDateString';
import localImgLoader from '../../helpers/localImageLoader';
@@ -15,7 +15,7 @@ export default function TransactionDetails({transactionID}) {
const {data, isFetching, isError, error} = useQuery({
queryKey: [...queryKeys.transactions, page],
queryFn: () => getTransactions({transaction_id: transactionID, page}),
//queryFn: () => getTransactions({transaction_id: transactionID, page}),
staleTime: 0,
// placeholderData: keepPreviousData,
})
@@ -1,22 +1,22 @@
import { useEffect, useState } from 'react'
import {Link} from 'react-router-dom'
import { useState } from 'react'
// import {Link} from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import queryKeys from '../../services/queryKeys'
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
import TablePaginatedWrapper from '../tableWrapper/TablePaginatedWrapper'
import Icons from '../Icons'
import { getSubcriptions } from '../../services/siteServices'
import getDateFromDateString from '../../helpers/GetDateFromDateString';
import getTimeFromDateString from '../../helpers/GetTimeFromDateString';
import localImgLoader from '../../helpers/localImageLoader';
import RouteLinks from '../../RouteLinks';
import { getSubscriptions } from '../../services/siteServices'
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
// import localImgLoader from '../../helpers/localImageLoader';
// import RouteLinks from '../../RouteLinks';
export default function SubscriptionsCom() {
const [page, setPage] = useState(1)
const [allSubcriptions, setAllSubcriptions] = useState({loading:true, error:'', data:{}})
const [willFilter, setWillFilter] = useState(false)
const [filter, setFilter] = useState({type: '', id: ''})
const [willFilter, setWillFilter] = useState(false)
const handleFilter = ({target:{name, value}}) => {
setFilter(prev => ({...prev, [name]:value}))
}
@@ -34,33 +34,28 @@ export default function SubscriptionsCom() {
}
}
const subcriptions = allSubcriptions?.data?.transactions // TRANSACTIONS LIST
const pagination = allSubcriptions?.data?.pagination
const isFetching = allSubcriptions?.loading
const isError = allSubcriptions?.error
useEffect(()=>{
setAllSubcriptions(prev => ({...prev, loading:true}))
const payload = filter?.type ? {[filter?.type]: filter.id} : {}
getSubcriptions({...payload, page}).then(res => {
if(res?.status != 200){
setAllSubcriptions(prev => ({...prev, error:'Opps, an error occurred', loading:false}))
return
const {data, isFetching, isError, error} = useQuery({
queryKey: [...queryKeys.subscriptions, page, willFilter],
queryFn: () => {
const filterData = filter?.type ? {[filter?.type]: filter.id} : {}
const reqData = {
page,
...filterData
}
setAllSubcriptions({loading:false, error:'', data:res?.data})
}).catch(err => {
setAllSubcriptions({loading:false, error:'error occurred', data:{}})
console.log('ERR', err)
})
},[page, willFilter])
return getSubscriptions(reqData)
},
staleTime: 0 //0 mins
})
const subscriptionData = data?.data?.subscriptions // SUBSCRIPTION LIST
const pagination = data?.data?.pagination
return (
<div className='w-full flex flex-col gap-8'>
<BreadcrumbCom title='Subscriptions' paths={['Dashboard', 'Subscriptions']} />
<BreadcrumbCom title='Provisions' paths={['Dashboard', 'Provisions']} />
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
{ isError ?
<p className='text-red-500'>{allSubcriptions?.error}</p>
<p className='text-red-500'>{error?.message}</p>
:
<>
{/* filter section */}
@@ -69,8 +64,8 @@ export default function SubscriptionsCom() {
<div className='w-full sm:max-w-48'>
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md' onChange={handleFilter}>
<option value=''>All</option>
<option value='transaction_id'>Transaction ID</option>
<option value='account_id'>Account ID</option>
<option value='member_id'>Member ID</option>
<option value='product_id'>Product ID</option>
</select>
</div>
<div className='w-full sm:max-w-48'>
@@ -80,23 +75,23 @@ export default function SubscriptionsCom() {
</div>
{/* end of filter section */}
<TablePaginatedWrapper data={subcriptions} isFetching={isFetching} setPage={setPage} itemsPerPage={pagination?.limit} pagination={pagination}>
<TablePaginatedWrapper data={subscriptionData} isFetching={isFetching} setPage={setPage} itemsPerPage={pagination?.limit} pagination={pagination}>
{({ data }) => (
<>
<table className="py-2 w-full text-sm">
<thead className="py-2 text-sm text-slate-500 text-left">
<tr>
<th scope="col" className="px-2 py-2">
Request
Added
</th>
<th scope="col" className="px-2">
Account
Product
</th>
<th scope="col" className="px-2">
Activity
URL
</th>
<th scope="col" className="px-2 text-right">
Action
Status
</th>
</tr>
</thead>
@@ -105,36 +100,28 @@ export default function SubscriptionsCom() {
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
<td className="px-2 py-2">
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
<img className="w-10 h-10 rounded-md" src={localImgLoader(`loan_icons/${item?.type}.png`)} alt="Icon" />
{/* <img className="w-10 h-10 rounded-md" src={localImgLoader(`loan_icons/${item?.type}.png`)} alt="Icon" /> */}
<div className="text-left">
<div className="text-base font-semibold">{item?.transaction_id}</div>
<div className="font-normal text-gray-500">{getDateFromDateString(item?.created_at)} {getTimeFromDateString(item?.created_at)}</div>
<div className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
</div>
</div>
</td>
<td className="px-2">
<div className="text-left">
<div className="text-base font-semibold">{item?.account_id}</div>
<div className="font-normal text-gray-500">{item?.type}</div>
<div className="text-base font-semibold">{item?.product_id}</div>
</div>
</td>
<td className="px-2">
<div className="text-left">
<div className="text-base font-semibold">{item?.internal_url}</div>
<div className="font-normal text-gray-500">{item?.external_url}</div>
</div>
</td>
<td className="px-2">
<div className="text-left">
<div className="font-normal text-gray-500">50%</div>
<div className="relative h-[6px] w-full bg-white-body dark:bg-black-body rounded-full overflow-hidden">
<div className={`absolute left-0 h-full w-1/2 bg-emerald-600`}></div>
</div>
<div className="text-right">
<div className="text-base font-semibold">{item?.status}</div>
</div>
</td>
<td className="px-2 text-right">
<div className='flex items-center justify-end gap-3 md:gap-4'>
<div className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
<Link to={RouteLinks.transaction_details_page} state={{transactionID: item?.transaction_id}}>
<Icons name='eye' />
</Link>
</div>
</div>
</td>
</tr>
))
:
+9 -9
View File
@@ -1,8 +1,8 @@
import { createContext, useContext, useEffect, useState } from 'react'
const GeneralContextProvider = createContext({})
const GeneralContextProviderInt = createContext({})
export default function GeneralLayoutContext({children}) {
export default function GeneralLayoutContextInt({children}) {
const [theme, setTheme] = useState(null)
@@ -21,7 +21,7 @@ export default function GeneralLayoutContext({children}) {
const [showAsideDrawer, setShowAsideDrawer] = useState('')
const handleActiveMenu = (name) => {
if(activeMenu == name){
if(activeMenu === name){
setActiveMenu('')
}else{
setActiveMenu(name)
@@ -32,7 +32,7 @@ export default function GeneralLayoutContext({children}) {
setDrawer((prev)=>{
if(!prev){
return drawerToOpen
}else if(drawerToOpen == prev){
}else if(drawerToOpen === prev){
return ''
}else{
return drawerToOpen
@@ -44,7 +44,7 @@ export default function GeneralLayoutContext({children}) {
setBooking((prev)=>{
if(!prev){
return bookingToOpen
}else if(bookingToOpen == prev){
}else if(bookingToOpen === prev){
return ''
}else{
return bookingToOpen
@@ -101,13 +101,13 @@ export default function GeneralLayoutContext({children}) {
}
return (
<GeneralContextProvider.Provider value={value}>
<GeneralContextProviderInt.Provider value={value}>
{children}
</GeneralContextProvider.Provider>
</GeneralContextProviderInt.Provider>
)
}
export const generalLayoutContext = () => {
return useContext(GeneralContextProvider)
export const GeneralLayoutContext = () => {
return useContext(GeneralContextProviderInt)
}
+33
View File
@@ -0,0 +1,33 @@
function getDateTimeFromDateString(dateString) {
const date = new Date(dateString);
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const dayName = days[date.getDay()];
const monthName = months[date.getMonth()];
const day = date.getDate();
const year = date.getFullYear();
// Add ordinal suffix
function getOrdinal(n) {
if (n > 3 && n < 21) return "th"; // 4-20 are all "th"
switch (n % 10) {
case 1: return "st";
case 2: return "nd";
case 3: return "rd";
default: return "th";
}
}
// Format time in 12hr with AM/PM
let hours = date.getHours();
const minutes = date.getMinutes().toString().padStart(2, "0");
const ampm = hours >= 12 ? "PM" : "AM";
hours = hours % 12 || 12;
return `${dayName}, ${monthName} ${day}${getOrdinal(day)} ${year} ${hours}:${minutes}${ampm}`;
}
export default getDateTimeFromDateString
+3 -3
View File
@@ -6,7 +6,7 @@ import { Provider } from "react-redux";
import './index.css';
import App from './App';
import store from './store/store.js'
import GeneralLayoutContext from './context/GeneralLayoutContext.jsx';
import GeneralLayoutContextInt from './context/GeneralLayoutContext.jsx';
const root = ReactDOM.createRoot(document.getElementById('root'));
@@ -14,9 +14,9 @@ root.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<GeneralLayoutContext>
<GeneralLayoutContextInt>
<App />
</GeneralLayoutContext>
</GeneralLayoutContextInt>
</Provider>
</BrowserRouter>
</React.StrictMode>
+1 -1
View File
@@ -11,7 +11,7 @@ export default function TransactionDetailsPage() {
if(!state?.transactionID){
navigate('/', {replace: true})
}
},[])
},[state])
return (
<TransactionDetailsCom id={state?.transactionID} />
)
+4
View File
@@ -10,6 +10,10 @@ const queryKeys = {
select_loan: ['select-loan'],
approved_loan: ['approved-loan'],
loan_offers: ['loan-offers'],
// new
subscriptions: ['subscriptions'],
billings: ['billings'],
}
export default queryKeys
+1 -1
View File
@@ -69,7 +69,7 @@ export const getBillings = (reqData) => {
}
// FUNCTION TO GET SUBSCRIPTIONS
export const getSubcriptions = (reqData) => {
export const getSubscriptions = (reqData) => {
const postData = { ...reqData }
return getAuxEnd(`/subcriptions`, postData)
}