LFFE-10 report page filter completed and problem of request solved and working on excel export
This commit is contained in:
@@ -478,14 +478,21 @@
|
||||
"cost_of_loan_refer_to_bank": "مبلغ وام های معرفی به بانک",
|
||||
"number_of_loan_refer_to_bank": "تعداد وام های معرفی به بانک",
|
||||
"cost_of_payed_loan": "مبلغ وام های پرداخت شده",
|
||||
"number_of_payed_loan": "تعداد وام های پرداخت شده"
|
||||
"number_of_payed_loan": "تعداد وام های پرداخت شده",
|
||||
"loading_fetching_reports": "درحال دریافت گزارشات",
|
||||
"error_fetching_reports": "خطا در دریافت گزارشات"
|
||||
},
|
||||
"filters": {
|
||||
"choose_province": "انتخاب استان",
|
||||
"choose_year": "انتخاب سال",
|
||||
"provinces": "استان های",
|
||||
"province": "استان",
|
||||
"year": "سال",
|
||||
"years": "سال های",
|
||||
"text_field_loading_provinces_list": "درحال دریافت استان ها",
|
||||
"text_field_error_fetching_provinces": "خطا در دریافت استان ها"
|
||||
"text_field_error_fetching_provinces": "خطا در دریافت استان ها",
|
||||
"filter": "اعمال فیلتر",
|
||||
"excel_export": "خروجی به اکسل",
|
||||
"export": "دریافت"
|
||||
}
|
||||
}
|
||||
|
||||
44
src/components/dashboard/reports/ExcelExport/index.jsx
Normal file
44
src/components/dashboard/reports/ExcelExport/index.jsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import {Accordion, AccordionDetails, AccordionSummary, Box, Button, Stack, Typography} from "@mui/material";
|
||||
import FileUploadIcon from '@mui/icons-material/FileUpload';
|
||||
import AssignmentIcon from '@mui/icons-material/Assignment';
|
||||
import {useTranslations} from "next-intl";
|
||||
|
||||
const ExcelExport = () => {
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<Accordion elevation={0} sx={{
|
||||
width: "95%",
|
||||
mx: "auto",
|
||||
mb: 2,
|
||||
borderBottom: 2,
|
||||
borderBottomColor: "divider",
|
||||
backgroundColor: "#f1f1f1"
|
||||
}}>
|
||||
<AccordionSummary>
|
||||
<Box sx={{width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between"}}>
|
||||
<Box sx={{display: "flex", alignItems: "center", gap: 0.5}}>
|
||||
<AssignmentIcon sx={{color: "primary.main"}}/>
|
||||
<Typography sx={{fontWeight: 500, color: "primary.main"}}>
|
||||
{t("filters.excel_export")}
|
||||
</Typography>
|
||||
</Box>
|
||||
<FileUploadIcon sx={{color: "primary.main"}}/>
|
||||
</Box>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails
|
||||
sx={{display: "flex", justifyContent: "space-between", alignItems: "center", mx: "auto",}}>
|
||||
<Stack sx={{flexDirection: {xs: "column", sm: "row"}, alignItems: "center", flexWrap: 'wrap'}}>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Button variant="contained" sx={{backgroundColor: "success.main"}}>
|
||||
{t("filters.export")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</AccordionDetails>
|
||||
|
||||
</Accordion>
|
||||
)
|
||||
};
|
||||
|
||||
export default ExcelExport;
|
||||
@@ -34,7 +34,7 @@ const ProvinceFilter = ({formik, multiple, setFilteredText}) => {
|
||||
};
|
||||
return (
|
||||
<FormControl sx={{width: 300, mx: 1}}>
|
||||
<InputLabel size="small">انتخاب استان</InputLabel>
|
||||
<InputLabel size="small">{t("filters.choose_province")}</InputLabel>
|
||||
<Select
|
||||
name="province_id"
|
||||
multiple={multiple}
|
||||
@@ -43,7 +43,7 @@ const ProvinceFilter = ({formik, multiple, setFilteredText}) => {
|
||||
value={formik.values.province_id}
|
||||
onChange={provinceChange}
|
||||
onBlur={formik.handleBlur("province_id")}
|
||||
input={<OutlinedInput label="انتخاب استان"/>}
|
||||
input={<OutlinedInput label={t("filters.choose_province")}/>}
|
||||
disabled={isLoadingProvinceList || errorProvinceList}
|
||||
renderValue={multiple ? (selected) => (
|
||||
<Box sx={{
|
||||
|
||||
@@ -5,12 +5,25 @@ import {useTranslations} from "next-intl";
|
||||
const currentShamsiYear = moment().format('jYYYY');
|
||||
const shamsiYearList = Array.from({length: currentShamsiYear - 1399}, (_, index) => (currentShamsiYear - index).toString());
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
const YearFilter = ({formik, multiple, setFilteredText}) => {
|
||||
const t = useTranslations();
|
||||
const yearChange = (event) => {
|
||||
const {target: {value}} = event;
|
||||
formik.handleChange(event);
|
||||
formik.setFieldValue('date', value);
|
||||
const {from, to} = periodOfYear(value);
|
||||
formik.setFieldValue('from_date', from);
|
||||
formik.setFieldValue('to_date', to);
|
||||
if (Array.isArray(value)) {
|
||||
setFilteredText(prevState => ({
|
||||
...prevState,
|
||||
@@ -25,7 +38,7 @@ const YearFilter = ({formik, multiple, setFilteredText}) => {
|
||||
};
|
||||
return (
|
||||
<FormControl sx={{width: 300, mx: 1}}>
|
||||
<InputLabel size="small">انتخاب سال</InputLabel>
|
||||
<InputLabel size="small">{t("filters.choose_year")}</InputLabel>
|
||||
<Select
|
||||
name="date"
|
||||
multiple={multiple}
|
||||
@@ -34,7 +47,7 @@ const YearFilter = ({formik, multiple, setFilteredText}) => {
|
||||
value={formik.values.date}
|
||||
onChange={yearChange}
|
||||
onBlur={formik.handleBlur("date")}
|
||||
input={<OutlinedInput label="انتخاب سال"/>}
|
||||
input={<OutlinedInput label={t("filters.choose_year")}/>}
|
||||
renderValue={multiple ? (selected) => (
|
||||
<Box sx={{display: 'flex', flexWrap: 'wrap', gap: 0.5}}>
|
||||
{selected.map((value) => (
|
||||
@@ -44,14 +57,16 @@ const YearFilter = ({formik, multiple, setFilteredText}) => {
|
||||
</Box>
|
||||
) : undefined}
|
||||
>
|
||||
{shamsiYearList.map((year) => (
|
||||
<MenuItem
|
||||
key={year}
|
||||
value={year}
|
||||
>
|
||||
{year}
|
||||
</MenuItem>
|
||||
))}
|
||||
{
|
||||
shamsiYearList.map((year) => (
|
||||
<MenuItem
|
||||
key={year}
|
||||
value={year}
|
||||
>
|
||||
{year}
|
||||
</MenuItem>
|
||||
))
|
||||
}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)
|
||||
|
||||
@@ -1,25 +1,14 @@
|
||||
import {Accordion, AccordionDetails, AccordionSummary, Box, Button, Stack, Typography} from "@mui/material";
|
||||
import {useFormik} from "formik";
|
||||
import ProvinceFilter from "./ProvinceFilter";
|
||||
import YearFilter from "./YearFilter";
|
||||
import ProvinceFilter from "../Filter/ProvinceFilter";
|
||||
import YearFilter from "../Filter/YearFilter";
|
||||
import FilterAltIcon from '@mui/icons-material/FilterAlt';
|
||||
import EqualizerIcon from '@mui/icons-material/Equalizer';
|
||||
import {useTranslations} from "next-intl";
|
||||
import TroubleshootIcon from '@mui/icons-material/Troubleshoot';
|
||||
import moment from "jalali-moment";
|
||||
import {useState} from "react";
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
const Filter = ({title, filterItem, expanded}) => {
|
||||
const Filter = ({title, filterItem, setFilterOption}) => {
|
||||
const t = useTranslations();
|
||||
const filter_by_province = filterItem.find((item) => item.type === "province");
|
||||
const filter_by_year = filterItem.find((item) => item.type === "year");
|
||||
@@ -33,8 +22,26 @@ const Filter = ({title, filterItem, expanded}) => {
|
||||
}),
|
||||
...(filter_by_province && {
|
||||
province_id: filter_by_province.multiple ? [] : ""
|
||||
})
|
||||
}),
|
||||
from_date: "",
|
||||
to_date: ""
|
||||
}, onSubmit: (values, {setSubmitting}) => {
|
||||
const province = values.province_id;
|
||||
const fields = [
|
||||
values.from_date ? {key: "from_date", value: values.from_date} : null,
|
||||
values.to_date ? {key: "to_date", value: values.to_date} : null,
|
||||
...(Array.isArray(province)
|
||||
? province.length !== 0
|
||||
? province.map((item, index) => ({key: `province_id[${index}]`, value: item}))
|
||||
: []
|
||||
: province
|
||||
? [{key: "province_id", value: province}]
|
||||
: []
|
||||
),
|
||||
].filter(Boolean);
|
||||
console.log("fields", fields)
|
||||
setFilterOption(fields)
|
||||
setSubmitting(false)
|
||||
},
|
||||
});
|
||||
return (
|
||||
@@ -48,7 +55,7 @@ const Filter = ({title, filterItem, expanded}) => {
|
||||
<Box sx={{width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between"}}>
|
||||
<Box sx={{display: "flex", alignItems: "center", gap: 0.5}}>
|
||||
<EqualizerIcon sx={{color: "primary.main"}}/>
|
||||
<Typography sx={{fontWeight: 500, color: "primary.main"}}>{title}</Typography>
|
||||
<Typography sx={{fontWeight: 500, color: "primary.main"}}>دریافت گزارش تکمیلی</Typography>
|
||||
<Typography variant="caption" sx={{fontWeight: 500}} color="error">
|
||||
{filteredText.province} {filteredText.year}
|
||||
</Typography>
|
||||
@@ -71,7 +78,7 @@ const Filter = ({title, filterItem, expanded}) => {
|
||||
<Button onClick={formik.handleSubmit} variant="contained"
|
||||
disabled={formik.isSubmitting || !formik.dirty}
|
||||
startIcon={<TroubleshootIcon/>}
|
||||
>اعمال فیلتر</Button>
|
||||
>{t("filters.filter")}</Button>
|
||||
</Stack>
|
||||
</AccordionDetails>
|
||||
|
||||
|
||||
@@ -5,17 +5,10 @@ const Pie = ({data}) => {
|
||||
title: {
|
||||
text: undefined,
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
fill: {
|
||||
colors: ['#F99417', '#363062', '#005B41', '#C70039', '#EE9322']
|
||||
}
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
opacity: 0.9,
|
||||
},
|
||||
labels: [' آیتم 1', ' آیتم 2', ' آیتم 3', ' آیتم 4', ' آیتم 5'],
|
||||
labels: data.map((item) => ` ${item.state_name}`),
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
@@ -24,7 +17,7 @@ const Pie = ({data}) => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const series = [14, 23, 21, 17, 15]
|
||||
const series = data.map((item) => +item.percentage)
|
||||
return (
|
||||
<Chart chartId="LoanDistributionPie" type="pie" specialOption={specialOption} series={series}/>
|
||||
)
|
||||
|
||||
@@ -11,15 +11,12 @@ const PolarChart = ({data}) => {
|
||||
strokeWidth: 2,
|
||||
strokeColor: '#e3e3e3',
|
||||
},
|
||||
fill: {
|
||||
colors: ['#F99417', '#363062', '#005B41', '#C70039', '#EE9322']
|
||||
}
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
opacity: 0.9,
|
||||
},
|
||||
labels: [' آیتم 1', ' آیتم 2', ' آیتم 3', ' آیتم 4', ' آیتم 5'],
|
||||
labels: data.map((item) => ` ${item.state_name}`),
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
style: {
|
||||
@@ -28,7 +25,7 @@ const PolarChart = ({data}) => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const series = [14, 23, 21, 17, 15]
|
||||
const series = data.map((item) => +item.percentage)
|
||||
return (
|
||||
<Chart chartId="LoanDistributionPolar" type="polarArea" specialOption={specialOption} series={series}/>
|
||||
)
|
||||
|
||||
@@ -1,60 +1,56 @@
|
||||
import {Grid, Paper} from "@mui/material";
|
||||
import {Box, CircularProgress, Grid, Paper, Typography} from "@mui/material";
|
||||
import PolarChart from "./PolarChart";
|
||||
import Pie from "./PieChart";
|
||||
import {useTranslations} from "next-intl";
|
||||
import Filter from "@/components/dashboard/reports/Filter";
|
||||
|
||||
const fakeData = [
|
||||
{name: "آذربایجان شرقی", data: 0},
|
||||
{name: "آذربایجان غربی", data: 33},
|
||||
{name: "اردبیل", data: 90},
|
||||
{name: "اصفهان", data: 30},
|
||||
{name: "البرز", data: 70},
|
||||
{name: "ایلام", data: 32},
|
||||
{name: "بوشهر", data: 12},
|
||||
{name: "تهران", data: 44},
|
||||
{name: "چهارمحال و بختیاری", data: 95},
|
||||
{name: "خراسان جنوبی", data: 30},
|
||||
{name: "خراسان رضوی", data: 70},
|
||||
{name: "خراسان شمالی", data: 10},
|
||||
{name: "خوزستان", data: 28},
|
||||
{name: "زنجان", data: 85},
|
||||
{name: "سمنان", data: 30},
|
||||
{name: "سیستان و بلوچستان", data: 70},
|
||||
{name: "فارس", data: 10},
|
||||
{name: "قزوین", data: 12},
|
||||
{name: "قم", data: 40},
|
||||
{name: "کردستان", data: 85},
|
||||
{name: "کرمان", data: 30},
|
||||
{name: "کرمانشاه", data: 67},
|
||||
{name: "کهگیلویه و بویراحمد", data: 100},
|
||||
{name: "گلستان", data: 97},
|
||||
{name: "گیلان", data: 5},
|
||||
{name: "لرستان", data: 27},
|
||||
{name: "مازندران", data: 31},
|
||||
{name: "مرکزی", data: 37},
|
||||
{name: "هرمزگان", data: 46},
|
||||
{name: "همدان", data: 52},
|
||||
{name: "یزد", data: 60}
|
||||
];
|
||||
import useChart from "@/lib/app/hooks/useChart";
|
||||
import {GET_LOAN_DISTRIBUTION} from "@/core/data/apiRoutes";
|
||||
|
||||
const LoanDistribution = () => {
|
||||
const t = useTranslations();
|
||||
const {errorReportList, isLoadingReportList, reportList, setFilterOption} = useChart(GET_LOAN_DISTRIBUTION);
|
||||
|
||||
return (
|
||||
<Paper elevation={2} sx={{width: "95%", mx: "auto", my: 2, pb: 2, background: "#f7f7f7e6"}}>
|
||||
<Filter title={t("reports.loan_distribution")}
|
||||
filterItem={[
|
||||
{type: "province", type_fa: "استان", multiple: false},
|
||||
{type: "province", type_fa: "استان", multiple: true},
|
||||
{type: "year", type_fa: "سال", multiple: false}
|
||||
]}
|
||||
setFilterOption={setFilterOption}
|
||||
/>
|
||||
<Grid container sx={{justifyContent: {xs: "center", md: "space-between"}}}>
|
||||
<Grid item xs={12} sm={10} md={5} sx={{aspectRatio: "1/0.75"}}>
|
||||
<PolarChart data={fakeData}/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={10} md={5} sx={{aspectRatio: "1/0.75"}}>
|
||||
<Pie data={fakeData}/>
|
||||
</Grid>
|
||||
{isLoadingReportList ? (
|
||||
<Box sx={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}>
|
||||
<Grid item xs={12} sx={{aspectRatio: "1/0.75"}}>
|
||||
<CircularProgress sx={{mb: 1, color: "#c2c2c2"}}/>
|
||||
<Typography variant="h6"
|
||||
sx={{color: "#c2c2c2", letterSpacing: "0.2rem"}}
|
||||
>
|
||||
{t("reports.loading_fetching_reports")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Box>
|
||||
) : errorReportList ? (
|
||||
<Grid item xs={12} sx={{aspectRatio: "1/0.75"}}>
|
||||
<Typography variant="caption">{t("reports.error_fetching_reports")}</Typography>
|
||||
</Grid>
|
||||
) : (
|
||||
<>
|
||||
<Grid item xs={12} sm={10} md={5} sx={{aspectRatio: "1/0.75"}}>
|
||||
<PolarChart data={reportList}/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={10} md={5} sx={{aspectRatio: "1/0.75"}}>
|
||||
<Pie data={reportList}/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Paper>
|
||||
)
|
||||
|
||||
@@ -2,10 +2,9 @@ import {calculateGradientColor} from "@/core/utils/gradientColorHandler";
|
||||
import Chart from "@/core/components/Chart";
|
||||
|
||||
const BarChart = ({data}) => {
|
||||
console.log(data)
|
||||
const usableArray = data.map(({province_name, percentage, ...rest}) => ({
|
||||
x: province_name,
|
||||
y: percentage,
|
||||
y: +percentage,
|
||||
...rest,
|
||||
}));
|
||||
let colorArray = data.map((obj) => calculateGradientColor(obj.percentage));
|
||||
|
||||
@@ -7,19 +7,18 @@ import {GET_PROVINCE_PROGRESS} from "@/core/data/apiRoutes";
|
||||
|
||||
const LoanProgress = () => {
|
||||
const t = useTranslations();
|
||||
const {errorReportList, isLoadingReportList, reportList} = useChart(GET_PROVINCE_PROGRESS);
|
||||
|
||||
console.log(reportList)
|
||||
const {errorReportList, isLoadingReportList, reportList, setFilterOption} = useChart(GET_PROVINCE_PROGRESS);
|
||||
return (
|
||||
<Paper elevation={2} sx={{width: "95%", mx: "auto", my: 2, pb: 2, background: "#f7f7f7e6"}}>
|
||||
<Filter title={t("reports.loan_progress")}
|
||||
filterItem={[
|
||||
{type: "year", type_fa: "سال", multiple: false}
|
||||
]}
|
||||
setFilterOption={setFilterOption}
|
||||
/>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sx={{aspectRatio: {xs: "1/1", sm: "1/1", md: "1/0.4", xl: "1/0.3"}}}>
|
||||
{1 === 1 ? (
|
||||
{isLoadingReportList ? (
|
||||
<Box sx={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
@@ -31,11 +30,11 @@ const LoanProgress = () => {
|
||||
<Typography variant="h6"
|
||||
sx={{color: "#c2c2c2", letterSpacing: "0.2rem"}}
|
||||
>
|
||||
درحال دریافت اطلاعات
|
||||
{t("reports.loading_fetching_reports")}
|
||||
</Typography>
|
||||
</Box>
|
||||
) : errorReportList ? (
|
||||
<Typography variant="caption">درحال دریافت اطلاعات</Typography>
|
||||
<Typography variant="caption">{t("reports.error_fetching_reports")}</Typography>
|
||||
) : (
|
||||
<BarChart data={reportList}/>
|
||||
)}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import LoanProgress from "@/components/dashboard/reports/LoanProgress";
|
||||
import LoanDistribution from "@/components/dashboard/reports/LoanDistribution";
|
||||
import LoanDetails from "@/components/dashboard/reports/LoanDetails";
|
||||
import ExcelExport from "@/components/dashboard/reports/ExcelExport";
|
||||
|
||||
const DashboardReportsComponent = (props) => {
|
||||
return (
|
||||
<>
|
||||
<ExcelExport/>
|
||||
<LoanProgress/>
|
||||
<LoanDistribution/>
|
||||
<LoanDetails/>
|
||||
|
||||
@@ -199,5 +199,7 @@ export const GET_PERMISSIONS_LIST =
|
||||
//role management
|
||||
|
||||
// reports
|
||||
export const GET_EXPORTS = 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
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
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('&')}`
|
||||
: '';
|
||||
console.log("check query", queryString)
|
||||
//swr config
|
||||
const fetcher = (...args) => {
|
||||
return requestServer(args, 'get').then(({data}) => {
|
||||
@@ -12,7 +17,7 @@ const useChart = (chart_url) => {
|
||||
})
|
||||
};
|
||||
|
||||
const {data, isLoading} = useSWR(chart_url, fetcher, {
|
||||
const {data, isLoading} = useSWR(`${chart_url}${queryString}`, fetcher, {
|
||||
revalidateIfStale: false,
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false
|
||||
@@ -21,7 +26,8 @@ const useChart = (chart_url) => {
|
||||
return {
|
||||
reportList: data,
|
||||
isLoadingReportList: isLoading,
|
||||
errorReportList: !data
|
||||
errorReportList: !data,
|
||||
setFilterOption: setFilterOption
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user