import React, { useCallback, useEffect, useRef, useState } from "react"; import { Collapse, Empty, Table as AntdTable } from "antd"; import "./Table.css"; import { useQuery } from "@tanstack/react-query"; import { api } from "../../api"; import parse from "wellknown"; import { useMap } from "react-map-gl"; import { usePointSelection } from "../../stores/usePointSelection"; import { useFilters } from "../../stores/useFilters"; import { useClickedPointConfig } from "../../stores/useClickedPointConfig"; import scrollIntoView from "scroll-into-view-if-needed"; const columns = [ { title: "Id", dataIndex: "location_id", key: "location_id", width: 50, ellipsis: true, }, { title: "Адрес", dataIndex: "address", key: "address", width: 200, }, { title: "Район", dataIndex: "rayon", key: "rayon", width: "120px", ellipsis: true, }, { title: "Округ", dataIndex: "okrug", key: "okrug", width: "120px", ellipsis: true, }, { title: "Название", dataIndex: "name", key: "name", width: "120px", ellipsis: true, }, { title: "Категория", dataIndex: "category", key: "category", width: "120px", ellipsis: true, }, { title: "Статус", dataIndex: "status", key: "status", width: "120px", ellipsis: true, }, { title: "Прогнозный трафик", dataIndex: "prediction_current", key: "prediction_current", width: "120px", ellipsis: true, }, ]; const PAGE_SIZE = 30; const useTableData = (page) => { const [pageSize, setPageSize] = useState(PAGE_SIZE); const { filters } = useFilters(); const { prediction, status, categories, region } = filters; const { selection } = usePointSelection(); const { clickedPointConfig } = useClickedPointConfig(); const [finalData, setFinalData] = useState(); const { data } = useQuery( ["table", page, filters, selection], async () => { const params = new URLSearchParams({ page, page_size: pageSize, "prediction_current[]": prediction, "status[]": status, "categories[]": categories, "included[]": [...selection.included], }); if (region) { if (region.type === "ao") { params.append("ao[]", region.id); } if (region.type === "rayon") { params.append("rayon[]", region.id); } } const { data } = await api.get( `/api/placement_points?${params.toString()}` ); return data; }, { keepPreviousData: true } ); useEffect(() => { if (!data) return; setFinalData(data); }, [data]); const [shouldLoadClickedPoint, setShouldLoadClickedPoint] = useState(false); useEffect(() => { if (!data || clickedPointConfig === null) return; const clickedPoint = data.results.find( (item) => item.location_id === clickedPointConfig.id ); if (clickedPoint) { return; } setShouldLoadClickedPoint(true); }, [data, clickedPointConfig]); const { data: remoteClickedPoint, isInitialLoading, isFetching, } = useQuery( ["clicked-point", clickedPointConfig], async () => { const params = new URLSearchParams({ "location_ids[]": [clickedPointConfig.id], }); const { data } = await api.get( `/api/placement_points?${params.toString()}` ); return data; }, { enabled: shouldLoadClickedPoint, onSuccess: () => setShouldLoadClickedPoint(false), } ); useEffect(() => { if (!remoteClickedPoint) return; setPageSize((prevState) => prevState + 1); setFinalData((prevState) => ({ ...prevState, count: prevState.count + 1, results: [remoteClickedPoint.results[0], ...prevState.results], })); }, [remoteClickedPoint]); useEffect(() => { if (clickedPointConfig === null) { setPageSize(PAGE_SIZE); setFinalData(data); } }, [clickedPointConfig]); return { data: finalData, pageSize, isClickedPointLoading: isInitialLoading || isFetching, }; }; export const Table = React.memo(({ height = 200 }) => { const { map } = useMap(); const tableRef = useRef(null); const [page, setPage] = useState(1); const { selection, include, exclude } = usePointSelection(); const { clickedPointConfig } = useClickedPointConfig(); const { data, pageSize, isClickedPointLoading } = useTableData(page); const SCROLL = { y: `${height}px`, x: "max-content", }; const handlePageChange = useCallback((page) => setPage(page), []); const getSelectedRowKeys = useCallback(() => { const ids = data?.results.map((item) => item.location_id) ?? []; const clickedPoint = data?.results.find( (item) => item.location_id === clickedPointConfig?.id ); const inExcludedList = (id) => selection.excluded.has(id); const shouldNotSelect = (id) => id === clickedPoint?.id && clickedPointConfig?.shouldSelect === false; return [ ...ids.filter((id) => { return !inExcludedList(id) && !shouldNotSelect(id); }), ...selection.included, ]; }, [data, clickedPointConfig, selection]); const rowSelection = { selectedRowKeys: getSelectedRowKeys(), onSelect: (record, selected) => { const { location_id: id } = record; if (selected) { include(id); } else { exclude(id); } }, hideSelectAll: true, }; useEffect(() => { if (clickedPointConfig === null || isClickedPointLoading) return; const row = document.querySelector(".scroll-row"); if (row) { scrollIntoView(row, { behavior: "smooth" }); } }, [clickedPointConfig, data]); return (