import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import DatePicker from "../date-picker/DatePicker"; import { Grid } from "../Grid/Grid"; import Textfield from "../Textfeild/Textfeild"; import Typography from "../Typography/Typography"; import { CircleStackIcon, DocumentArrowDownIcon, } from "@heroicons/react/24/outline"; import { checkIsMobile } from "../../utils/checkIsMobile"; import AutoComplete from "../AutoComplete/AutoComplete"; import { Tooltip } from "../Tooltip/Tooltip"; import api from "../../utils/axios"; import { useBackdropStore } from "../../context/zustand-store/appStore"; import { useToast } from "../../hooks/useToast"; import { useApiRequest } from "../../utils/useApiRequest"; import { getNestedValue } from "../../utils/getNestedValue"; import { getFaPermissions } from "../../utils/getFaPermissions"; interface FilterItem { key: number | string; value: string; disabled?: boolean; } interface FilterConfig { key?: string; data?: FilterItem[]; api?: string; selectedKeys: (number | string)[]; onChange: (keys: (number | string)[]) => void; title: string; size?: "small" | "medium" | "large"; inPage?: boolean; selectField?: boolean; keyField?: string; valueField?: string | string[]; valueField2?: string | string[]; valueField3?: string | string[]; filterAddress?: string[]; filterValue?: string[]; valueTemplate?: string; valueTemplateProps?: Array<{ [key: string]: "string" | "number" }>; groupBy?: string | string[]; groupFunction?: (item: any) => string; } type ExcelProps = { title?: string; link?: string; }; interface PaginationParametersProps { noCustomDate?: boolean; defaultActive?: boolean; justOne?: boolean; noSearch?: boolean; startLabel?: string; endLabel?: string; title?: string; onChange?: (data: { date1?: string | null; date2?: string | null; search?: string | null; [key: string]: any; }) => void; getData?: () => void; children?: React.ReactNode; filters?: FilterConfig[]; excelInfo?: ExcelProps; } const ApiBasedFilter: React.FC<{ filter: FilterConfig; }> = ({ filter }) => { const [filterData, setFilterData] = useState([]); if (!filter.api) { return null; } const formatValue = (value: any, fieldKey: string) => { if (!filter.valueTemplate || !filter.valueTemplateProps) return value; const templateProp = filter.valueTemplateProps.find( (prop) => prop[fieldKey] ); if (!templateProp) return value; const fieldType = templateProp[fieldKey]; if (fieldType === "number") { const numValue = typeof value === "number" ? value : Number(value); return !isNaN(numValue) ? numValue.toLocaleString() : String(value); } else if (fieldType === "string") { let result = String(value); if (typeof value === "string" && value.includes(",")) { result = value.replace(/,/g, ""); } return result; } return value; }; const { data: apiData } = useApiRequest({ api: filter.api, params: { page: 1, page_size: 1000 }, queryKey: [filter.api, filter.key], disableBackdrop: true, }); useEffect(() => { if (apiData?.results && filter.api) { let data; if (filter.filterAddress && filter.filterValue) { data = apiData.results?.filter( (item: any) => !filter.filterValue!.includes( getNestedValue(item, filter.filterAddress!) ) ); } else { data = apiData.results; } const keyField = filter.keyField || "id"; const valueField = filter.valueField || "name"; const formattedData = data?.map((option: any) => ({ key: option[keyField], value: filter.valueTemplate ? filter.valueTemplate .replace( /v1/g, formatValue( valueField === "page" ? getFaPermissions(option[valueField]) : typeof valueField === "string" ? option[valueField] : getNestedValue(option, valueField), "v1" ) ) .replace( /v2/g, formatValue( filter.valueField2 ? typeof filter.valueField2 === "string" ? option[filter.valueField2] : getNestedValue(option, filter.valueField2) : "", "v2" ) ) .replace( /v3/g, formatValue( filter.valueField3 ? typeof filter.valueField3 === "string" ? option[filter.valueField3] : getNestedValue(option, filter.valueField3) : "", "v3" ) ) : `${ valueField === "page" ? getFaPermissions(option[valueField]) : typeof valueField === "string" ? option[valueField] : getNestedValue(option, valueField) } ${ filter.valueField2 ? " - " + (typeof filter.valueField2 === "string" ? option[filter.valueField2] : getNestedValue(option, filter.valueField2)) : "" } ${ filter.valueField3 ? "(" + (typeof filter.valueField3 === "string" ? option[filter.valueField3] : getNestedValue(option, filter.valueField3)) + ")" : "" }`, })); setFilterData(formattedData || []); } }, [apiData, filter]); return ( ); }; export const PaginationParameters: React.FC = ({ noCustomDate = false, defaultActive = false, justOne = false, noSearch = false, startLabel = "", endLabel = "تا", title, onChange, getData, children, filters = [], excelInfo, }) => { const [selectedDate1, setSelectedDate1] = useState(); const [selectedDate2, setSelectedDate2] = useState(); const [keyword, setKeyword] = useState(""); const [enableDates, setEnableDates] = useState(defaultActive); const { openBackdrop, closeBackdrop } = useBackdropStore(); const showToast = useToast(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const data = { start: enableDates ? selectedDate1 : null, end: enableDates ? selectedDate2 : null, search: noSearch ? null : keyword, }; await onChange?.(data); getData?.(); }; const handleExcelDownload = () => { openBackdrop(); if (!excelInfo?.link) return; const urlParts = excelInfo.link.split("?"); const baseUrl = urlParts[0]; const existingParams: Record = {}; if (urlParts[1]) { const queryString = urlParts[1]; const params = new URLSearchParams(queryString); params.forEach((value, key) => { if (value) { existingParams[key] = value; } }); } const mergedParams: Record = { ...existingParams, ...(keyword ? { search: keyword } : {}), ...(enableDates && selectedDate1 && selectedDate2 ? { start: selectedDate1, end: selectedDate2 } : enableDates && selectedDate1 ? { start: selectedDate1 } : enableDates && selectedDate2 ? { end: selectedDate2 } : {}), }; const finalParams: Record = {}; Object.keys(mergedParams).forEach((key) => { const value = mergedParams[key]; if (value !== undefined && value !== null && value !== "") { finalParams[key] = value; } }); api .get(baseUrl, { params: finalParams, responseType: "blob", }) .then((response) => { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement("a"); link.href = url; link.setAttribute( "download", `${excelInfo?.title || title || "خروجی"}.xlsx` ); document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); }) .catch((error) => { console.error("Error downloading file:", error); showToast("در حال حاضر امکان دانلود خروجی اکسل وجود ندارد", "error"); }) .finally(() => { closeBackdrop(); }); }; const renderDate1 = ( setSelectedDate1(r)} label={startLabel} /> ); const renderDate2 = !justOne ? ( setSelectedDate2(r)} label={endLabel} /> ) : ( "" ); const isMobile = checkIsMobile(); if (isMobile) { return (
{(title || excelInfo) && (
{title} {excelInfo && (
)}
)} {!noCustomDate && (
فعال‌سازی بازه تاریخی
)}
{renderDate1} {renderDate2}
{filters.length > 0 && (
{filters.map((filter) => filter.api ? ( ) : ( ) )}
)}
{!noSearch && ( setKeyword(e.target.value)} /> )} جستجو
); } return (
{title && ( {title} )}
{filters.map((filter) => ( {filter.api ? ( ) : ( )} ))} {children}
{!noCustomDate && (
)} <> {renderDate1} {renderDate2} {!noSearch && ( setKeyword(e.target.value)} /> )} جستجو {excelInfo && (
)}
); };