/* send component */ : }
>)}
renderBottomToolbarCustomActions={({table}) => (<>
diff --git a/src/core/components/DownloadSection.jsx b/src/core/components/DownloadSection.jsx
new file mode 100644
index 0000000..fc20d9c
--- /dev/null
+++ b/src/core/components/DownloadSection.jsx
@@ -0,0 +1,38 @@
+import FileDownloadOutlinedIcon from '@mui/icons-material/FileDownloadOutlined';
+import Check from '@mui/icons-material/Check';
+import {CircularProgress} from "@mui/material"
+const DownloadSection = ({ downloadStatus, onDownloadClick }) => {
+ return (
+
+ {downloadStatus === 'completed' ? (
+ <>
+
+ >
+ ) : downloadStatus === 'downloading' ? (
+
+ ) : (
+ <>
+
+ >
+ )}
+
+ );
+};
+
+export default DownloadSection;
diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js
index dba065e..d184ab2 100644
--- a/src/core/data/apiRoutes.js
+++ b/src/core/data/apiRoutes.js
@@ -21,6 +21,9 @@ export const CONFIRM_PASSENGER_OFFICE =
export const REJECT_PASSENGER_OFFICE =
BASE_URL + "/dashboard/passenger_office_chief/reject";
+
+export const EXPORT_PASSENGER_OFFICE =
+ BASE_URL + "/dashboard/passenger_office_chief/export"
//passenger office
//passenger boss
@@ -32,17 +35,23 @@ export const CONFIRM_PASSENGER_BOSS =
export const REJECT_PASSENGER_BOSS =
BASE_URL + "/dashboard/province_working_group/reject";
+export const EXPORT_PASSENGER_BOSS =
+ BASE_URL + "/dashboard/province_working_group/export";
//passenger boss
//transportation assistance
export const GET_TRANSPORTATION_ASSISTANCE =
BASE_URL + "/dashboard/transportation_assistant/show";
+export const GET_TRANSPORTATION_ASSISTANCE_DETAILS =
+ BASE_URL + "/dashboard/transportation_assistant";
export const CONFIRM_TRANSPORTATION_ASSISTANCE =
BASE_URL + "/dashboard/transportation_assistant/confirm";
export const REJECT_TRANSPORTATION_ASSISTANCE =
BASE_URL + "/dashboard/transportation_assistant/reject";
+export const EXPORT_TRANSPORTATION_ASSISTANCE =
+ BASE_URL + "/dashboard/transportation_assistant/export";
//transportation assistance
//machinary office
@@ -54,6 +63,8 @@ export const CONFIRM_MACHINARY_OFFICE =
export const REJECT_MACHINARY_OFFICE =
BASE_URL + "/dashboard/machinery_expert/reject";
+export const EXPORT_MACHINARY_OFFICE =
+ BASE_URL + "/dashboard/machinery_expert/export";
//machinary office
//commercial chief
@@ -76,6 +87,8 @@ export const CONFIRM_NAVGAN_PROVINCE_MANAGER =
export const REJECT_NAVGAN_PROVINCE_MANAGER =
BASE_URL + "/dashboard/province_manager/reject";
+export const EXPORT_NAVGAN_PROVINCE_MANAGER =
+ BASE_URL + "/dashboard/province_manager/export";
//navgan province manager
// refahi province manager
@@ -197,3 +210,13 @@ export const DELETE_ROLE_MANAGEMENT =
export const GET_PERMISSIONS_LIST =
BASE_URL + "/dashboard/permissions/list"
//role management
+
+// reports
+export const GET_EXPORT = BASE_URL + "/dashboard/exports/navgan"
+export const GET_PROVINCE_PROGRESS = BASE_URL + "/dashboard/reports/navgan/province_progress"
+export const GET_LOAN_DISTRIBUTION = BASE_URL + "/dashboard/reports/navgan/loan_distribution"
+// reports
+
+//loan history
+export const GET_LOAN_HISTORY = BASE_URL + "/dashboard/navgan_loans"
+export const GET_HISTORY_DETAIL = BASE_URL + "/dashboard/navgan_loans"
diff --git a/src/core/data/sidebarMenu.jsx b/src/core/data/sidebarMenu.jsx
index c54bbca..2fd6792 100644
--- a/src/core/data/sidebarMenu.jsx
+++ b/src/core/data/sidebarMenu.jsx
@@ -13,6 +13,8 @@ import PaidIcon from '@mui/icons-material/Paid';
import ManageAccountsIcon from '@mui/icons-material/ManageAccounts';
import PersonIcon from '@mui/icons-material/Person';
import AccessibilityIcon from '@mui/icons-material/Accessibility';
+import AssessmentIcon from '@mui/icons-material/Assessment';
+import SecurityIcon from '@mui/icons-material/Security';
const sidebarMenu = [
[
@@ -24,6 +26,15 @@ const sidebarMenu = [
selected: false,
permission: "all",
},
+ {
+ key: "sidebar.reports",
+ name: "reports",
+ type: "page",
+ route: "/dashboard/reports",
+ icon: ,
+ selected: false,
+ permission: "all",
+ },
{
key: "sidebar.passenger-office-chief",
secondary: "secondary.passenger-office",
@@ -146,7 +157,7 @@ const sidebarMenu = [
route: "/dashboard/expert-management",
icon: ,
selected: false,
- permission: "manage_navgan_loan",
+ permission: "manage_experts",
},
{
key: "sidebar.user-management",
@@ -166,6 +177,15 @@ const sidebarMenu = [
selected: false,
permission: "manage_roles",
},
+ {
+ key: "sidebar.loan-history",
+ name: "loan-history",
+ type: "page",
+ route: "/dashboard/loan-history",
+ icon: ,
+ selected: false,
+ permission: "manage_navgan_loan",
+ },
],
];
diff --git a/src/core/utils/gradientColorHandler.js b/src/core/utils/gradientColorHandler.js
new file mode 100644
index 0000000..e16b42a
--- /dev/null
+++ b/src/core/utils/gradientColorHandler.js
@@ -0,0 +1,31 @@
+export const calculateGradientColor = (percentage) => {
+ let colorStops = [
+ {percent: 0, color: [173, 3, 23]}, // 0%: #3D0C11
+ {percent: 33, color: [245, 81, 81]}, // 33%: #D80032
+ {percent: 34, color: [237, 204, 101]}, // 34%: #F2F7A1
+ {percent: 66, color: [240, 184, 7]}, // 66%: #E9B824
+ {percent: 67, color: [167, 211, 151]}, // 67%: #B0D9B1
+ {percent: 100, color: [0, 91, 65]} // 100%: #005B41
+ ];
+
+ let segment;
+ for (let i = 0; i < colorStops.length - 1; i++) {
+ if (percentage >= colorStops[i].percent && percentage <= colorStops[i + 1].percent) {
+ segment = i;
+ break;
+ }
+ }
+
+ let color1 = colorStops[segment].color;
+ let color2 = colorStops[segment + 1].color;
+ let ratio = (percentage - colorStops[segment].percent) / (colorStops[segment + 1].percent - colorStops[segment].percent);
+
+ let color = [
+ Math.round(color1[0] + ratio * (color2[0] - color1[0])),
+ Math.round(color1[1] + ratio * (color2[1] - color1[1])),
+ Math.round(color1[2] + ratio * (color2[2] - color1[2]))
+ ];
+
+ return `rgb(${color[0]}, ${color[1]}, ${color[2]})`;
+
+}
\ No newline at end of file
diff --git a/src/core/utils/yearPeriodFinder.js b/src/core/utils/yearPeriodFinder.js
new file mode 100644
index 0000000..73c01b9
--- /dev/null
+++ b/src/core/utils/yearPeriodFinder.js
@@ -0,0 +1,11 @@
+import moment from "jalali-moment";
+
+export const periodOfYear = (year) => {
+ const isLeapYear = moment.jIsLeapYear(year);
+ const firstDayGeorgian = moment.from(`${year}/01/01`, 'fa').format('YYYY-MM-DD');
+ const lastDayGeorgian = moment.from(`${year}/12/${isLeapYear ? '30' : '29'}`, 'fa').format('YYYY-MM-DD');
+ return {
+ from: firstDayGeorgian,
+ to: lastDayGeorgian
+ }
+}
\ No newline at end of file
diff --git a/src/lib/app/contexts/language.jsx b/src/lib/app/contexts/language.jsx
index 03e3bc3..243d7e8 100644
--- a/src/lib/app/contexts/language.jsx
+++ b/src/lib/app/contexts/language.jsx
@@ -13,7 +13,7 @@ export const LanguageProvider = ({children}) => {
key: "fa",
dir: "rtl",
name: "فارسی",
- fontFamily: `IRANSans, sans-serif`,
+ fontFamily: `IRANSansFaNum, sans-serif`,
tableLocalization: FA_DATATABLE_LOCALIZATION,
chartLocalization: FA_CHART_LOCALIZATION
}
diff --git a/src/lib/app/hooks/useChart.jsx b/src/lib/app/hooks/useChart.jsx
new file mode 100644
index 0000000..d1dd454
--- /dev/null
+++ b/src/lib/app/hooks/useChart.jsx
@@ -0,0 +1,39 @@
+import useRequest from "@/lib/app/hooks/useRequest";
+import useSWR from "swr";
+import {useState} from "react";
+
+const useChart = (chart_url) => {
+ const requestServer = useRequest({auth: true, notification: false})
+ const [filterOption, setFilterOption] = useState([]);
+ const queryString = filterOption.length !== 0
+ ? `?${filterOption.map((option) => `${option.key}=${option.value}`).join('&')}`
+ : '';
+ //swr config
+ const fetcher = (...args) => {
+ return requestServer(args, 'get').then(({data}) => {
+ return data.data;
+ }).catch(() => {
+ })
+ };
+
+ const {
+ data,
+ isValidating,
+ mutate
+ } = useSWR(filterOption.length !== 0 ? `${chart_url}${queryString}` : "", fetcher, {
+ revalidateIfStale: true,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ keepPreviousData: true
+ });
+
+ return {
+ reportList: data,
+ isLoadingReportList: isValidating,
+ errorReportList: !data,
+ setFilterOption: setFilterOption,
+ mutate: mutate
+ }
+};
+
+export default useChart;
\ No newline at end of file
diff --git a/src/lib/app/hooks/useProvince.jsx b/src/lib/app/hooks/useProvince.jsx
index d0fbda0..3443a6e 100644
--- a/src/lib/app/hooks/useProvince.jsx
+++ b/src/lib/app/hooks/useProvince.jsx
@@ -16,7 +16,8 @@ const useProvince = () => {
const {data, isLoading} = useSWR(GET_PROVINCE_LIST, fetcher, {
revalidateIfStale: false,
revalidateOnFocus: false,
- revalidateOnReconnect: false
+ revalidateOnReconnect: false,
+ keepPreviousData: true
});
return {
diff --git a/src/lib/app/hooks/useRole.jsx b/src/lib/app/hooks/useRole.jsx
index fc3dd18..b4c231c 100644
--- a/src/lib/app/hooks/useRole.jsx
+++ b/src/lib/app/hooks/useRole.jsx
@@ -16,7 +16,8 @@ const useRole = () => {
const {data, isLoading} = useSWR(GET_ROLE_LIST, fetcher, {
revalidateIfStale: false,
revalidateOnFocus: false,
- revalidateOnReconnect: false
+ revalidateOnReconnect: false,
+ keepPreviousData: true
});
return {
diff --git a/src/pages/dashboard/loan-history/index.jsx b/src/pages/dashboard/loan-history/index.jsx
new file mode 100644
index 0000000..d84d43e
--- /dev/null
+++ b/src/pages/dashboard/loan-history/index.jsx
@@ -0,0 +1,21 @@
+import {parse} from "next-useragent";
+import DashboardLoanHistoryComponent from "@/components/dashboard/loan-history";
+
+export default function LoanHistory() {
+ return (
+
+ );
+}
+
+export async function getServerSideProps({req, locale}) {
+ const {isBot} = parse(req.headers["user-agent"]);
+ return {
+ props: {
+ messages: (await import(`&/locales/${locale}/app.json`)).default,
+ title: "Dashboard.loan_history",
+ isBot,
+ locale,
+ layout: {name: 'DashboardLayout', props: {permissions: ["manage_navgan_loan"]}}
+ },
+ };
+}
diff --git a/src/pages/dashboard/reports/index.jsx b/src/pages/dashboard/reports/index.jsx
new file mode 100644
index 0000000..9dba421
--- /dev/null
+++ b/src/pages/dashboard/reports/index.jsx
@@ -0,0 +1,20 @@
+import DashboardReportsComponent from "@/components/dashboard/reports";
+import {parse} from "next-useragent";
+
+export default function Reports() {
+ return (
+
+ );
+}
+
+export async function getServerSideProps({req, locale}) {
+ const {isBot} = parse(req.headers["user-agent"]);
+ return {
+ props: {
+ messages: (await import(`&/locales/${locale}/app.json`)).default,
+ title: "Dashboard.reports",
+ isBot,
+ layout: {name: 'DashboardLayout'}
+ },
+ };
+}