Split layers

dev
Platon Yasev 3 years ago
parent ea19b9938f
commit c2900763c7

@ -0,0 +1,32 @@
import { Layer } from "react-map-gl";
import { approvePointLayer } from "./layers-config";
import { useLayersVisibility } from "../../stores/useLayersVisibility";
import { STATUSES } from "../../config";
import { useRegionFilterExpression } from "./useRegionFilterExpression";
import { LAYER_IDS } from "./constants";
const statusExpression = ["==", ["get", "status"], STATUSES.approve];
export const ApprovePoints = () => {
const { isVisible } = useLayersVisibility();
const regionFilterExpression = useRegionFilterExpression();
const filter = regionFilterExpression
? ["all", statusExpression, regionFilterExpression]
: statusExpression;
return (
<>
<Layer
{...approvePointLayer}
id={LAYER_IDS.approve}
source={"points"}
source-layer={"public.service_placementpoint"}
layout={{
visibility: isVisible[LAYER_IDS.approve] ? "visible" : "none",
}}
filter={filter}
/>
</>
);
};

@ -0,0 +1,114 @@
import { Layer } from "react-map-gl";
import {
matchInitialPointLayer,
unmatchInitialPointLayer,
} from "./layers-config";
import { useLayersVisibility } from "../../stores/useLayersVisibility";
import { useFilters } from "../../stores/useFilters";
import { usePointSelection } from "../../stores/usePointSelection";
import { STATUSES } from "../../config";
import { useRegionFilterExpression } from "./useRegionFilterExpression";
import { LAYER_IDS } from "./constants";
const statusExpression = ["==", ["get", "status"], STATUSES.initial];
const useFilterExpression = () => {
const { filters } = useFilters();
const { prediction, categories, region } = filters;
const { selection } = usePointSelection();
const includedArr = [...selection.included];
const excludedArr = [...selection.excluded];
const regionExpression = useRegionFilterExpression();
const includedExpression = [
"in",
["get", "location_id"],
["literal", includedArr],
];
const excludedExpression = [
"in",
["get", "location_id"],
["literal", excludedArr],
];
const predictionExpression = [
[">=", ["get", "prediction_current"], prediction[0]],
["<=", ["get", "prediction_current"], prediction[1]],
];
const categoryExpression =
categories.length > 0
? ["in", ["get", "category"], ["literal", categories]]
: true;
const matchFilterExpression = [
"all",
statusExpression,
["!", excludedExpression],
[
"any",
region
? ["all", ...predictionExpression, categoryExpression, regionExpression]
: ["all", ...predictionExpression, categoryExpression],
includedExpression,
],
];
const unmatchFilterExpression = [
"all",
statusExpression,
["!", includedExpression],
[
"any",
[
"!",
region
? [
"all",
...predictionExpression,
categoryExpression,
regionExpression,
]
: ["all", ...predictionExpression, categoryExpression],
],
excludedExpression,
],
];
return { match: matchFilterExpression, unmatch: unmatchFilterExpression };
};
export const InitialPoints = () => {
const { isVisible } = useLayersVisibility();
const { match: matchFilterExpression, unmatch: unmatchFilterExpression } =
useFilterExpression();
return (
<>
<Layer
{...matchInitialPointLayer}
id={LAYER_IDS["initial-unmatch"]}
source={"points"}
source-layer={"public.service_placementpoint"}
layout={{
...matchInitialPointLayer.layout,
visibility: isVisible[LAYER_IDS.initial] ? "visible" : "none",
}}
filter={unmatchFilterExpression}
paint={unmatchInitialPointLayer.paint}
/>
<Layer
{...matchInitialPointLayer}
id={LAYER_IDS["initial-match"]}
source={"points"}
source-layer={"public.service_placementpoint"}
layout={{
...matchInitialPointLayer.layout,
visibility: isVisible[LAYER_IDS.initial] ? "visible" : "none",
}}
filter={matchFilterExpression}
paint={matchInitialPointLayer.paint}
/>
</>
);
};

@ -1,9 +1,9 @@
import { Points } from "./Points"; import { Points } from "./Points";
import { Layer, Source } from "react-map-gl"; import { Layer, Source } from "react-map-gl";
import { aoLayer, rayonLayer, selectedRegionLayer } from "./layers-config"; import { aoLayer, rayonLayer, selectedRegionLayer } from "./layers-config";
import { useLayersVisibility } from "../stores/useLayersVisibility"; import { useLayersVisibility } from "../../stores/useLayersVisibility";
import { useFilters } from "../stores/useFilters"; import { useFilters } from "../../stores/useFilters";
import { BASE_URL } from "../api"; import { BASE_URL } from "../../api";
export const Layers = () => { export const Layers = () => {
const { const {

@ -0,0 +1,27 @@
import { Source } from "react-map-gl";
import { BASE_URL } from "../../api";
import { useUpdateLayerCounter } from "../../stores/useUpdateLayerCounter";
import { InitialPoints } from "./InitialPoints";
import { ApprovePoints } from "./ApprovePoints";
import { WorkingPoints } from "./WorkingPoints";
export const Points = () => {
const { updateCounter } = useUpdateLayerCounter();
return (
<>
<Source
id="points"
type="vector"
key={`points-${updateCounter}`}
tiles={[
`${BASE_URL}/martin/public.service_placementpoint/{z}/{x}/{y}.pbf`,
]}
>
<InitialPoints />
<ApprovePoints />
<WorkingPoints />
</Source>
</>
);
};

@ -0,0 +1,32 @@
import { Layer } from "react-map-gl";
import { workingPointLayer } from "./layers-config";
import { useLayersVisibility } from "../../stores/useLayersVisibility";
import { STATUSES } from "../../config";
import { useRegionFilterExpression } from "./useRegionFilterExpression";
import { LAYER_IDS } from "./constants";
const statusExpression = ["==", ["get", "status"], STATUSES.working];
export const WorkingPoints = () => {
const { isVisible } = useLayersVisibility();
const regionFilterExpression = useRegionFilterExpression();
const filter = regionFilterExpression
? ["all", statusExpression, regionFilterExpression]
: statusExpression;
return (
<>
<Layer
{...workingPointLayer}
id={LAYER_IDS.working}
source={"points"}
source-layer={"public.service_placementpoint"}
layout={{
visibility: isVisible[LAYER_IDS.working] ? "visible" : "none",
}}
filter={filter}
/>
</>
);
};

@ -0,0 +1,9 @@
export const LAYER_IDS = {
initial: "initial",
"initial-match": "initial-match-points",
"initial-unmatch": "initial-unmatch-points",
approve: "approve-points",
working: "working-points",
cancelled: "cancelled-points",
atd: "atd",
};

@ -0,0 +1,86 @@
const POINT_SIZE = 5;
const UNMATCH_POINT_SIZE = 3;
const INITIAL_COLOR = "#CC2222";
const CANCELLED_COLOR = "#CC2222";
const APPROVE_COLOR = "#ff7d00";
const WORKING_COLOR = "#006e01";
const UNMATCHED_COLOR = "#b4b4b4";
const DEFAULT_POINT_CONFIG = {
type: "circle",
paint: {
"circle-stroke-width": 0.4,
"circle-stroke-color": "#fff",
"circle-opacity": 0.8,
},
};
const getPointConfig = (color = INITIAL_COLOR, size = POINT_SIZE) => {
return {
...DEFAULT_POINT_CONFIG,
paint: {
...DEFAULT_POINT_CONFIG.paint,
"circle-color": color,
"circle-radius": size,
},
};
};
export const matchInitialPointLayer = getPointConfig();
export const unmatchInitialPointLayer = getPointConfig(
UNMATCHED_COLOR,
UNMATCH_POINT_SIZE
);
export const approvePointLayer = getPointConfig(APPROVE_COLOR);
export const workingPointLayer = getPointConfig(WORKING_COLOR);
export const cancelledPointLayer = getPointConfig(CANCELLED_COLOR);
const regionColor = "#676767";
export const aoLayer = {
id: "ao",
type: "line",
source: "ao",
"source-layer": "public.service_ao",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": regionColor,
"line-width": 1.5,
"line-opacity": 0.8,
},
};
export const rayonLayer = {
id: "rayon",
type: "line",
source: "rayon",
"source-layer": "public.service_rayon",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": regionColor,
"line-width": 0.5,
"line-opacity": 0.8,
},
};
export const selectedRegionLayer = {
id: "selected-region",
type: "line",
source: "selected-region",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": "#47006e",
"line-width": 2,
"line-opacity": 1,
},
};

@ -0,0 +1,21 @@
import { useFilters } from "../../stores/useFilters";
import { useMemo } from "react";
const REGION_FIELD_MAPPER = {
ao: "okrug_id",
rayon: "rayon_id",
};
export const useRegionFilterExpression = () => {
const {
filters: { region },
} = useFilters();
return useMemo(
() =>
region
? ["==", ["get", REGION_FIELD_MAPPER[region.type]], region.id]
: null,
[region]
);
};

@ -3,6 +3,7 @@ import { Checkbox } from "antd";
import { useLayersVisibility } from "../../stores/useLayersVisibility"; import { useLayersVisibility } from "../../stores/useLayersVisibility";
import { useMode } from "../../stores/useMode"; import { useMode } from "../../stores/useMode";
import { MODES } from "../../config"; import { MODES } from "../../config";
import { LAYER_IDS } from "../Layers/constants";
export const LayersVisibility = () => { export const LayersVisibility = () => {
const { toggleVisibility, isVisible } = useLayersVisibility(); const { toggleVisibility, isVisible } = useLayersVisibility();
@ -14,17 +15,35 @@ export const LayersVisibility = () => {
<div className={"space-y-1 flex flex-col"}> <div className={"space-y-1 flex flex-col"}>
{mode === MODES.INITIAL && ( {mode === MODES.INITIAL && (
<Checkbox <Checkbox
onChange={() => toggleVisibility("points")} onChange={() => toggleVisibility(LAYER_IDS.initial)}
checked={isVisible.points} checked={isVisible[LAYER_IDS.initial]}
> >
Локации к рассмотрению Локации к рассмотрению
</Checkbox> </Checkbox>
)} )}
{mode === MODES.APPROVE && (
<>
<Checkbox
onChange={() => toggleVisibility(LAYER_IDS.approve)}
checked={isVisible[LAYER_IDS.approve]}
>
Согласование-установка
</Checkbox>
<Checkbox
className={"!ml-0"}
onChange={() => toggleVisibility(LAYER_IDS.working)}
checked={isVisible[LAYER_IDS.working]}
>
Работает
</Checkbox>
</>
)}
<Checkbox <Checkbox
className={"!ml-0"} className={"!ml-0"}
onChange={() => toggleVisibility("atd")} onChange={() => toggleVisibility(LAYER_IDS.atd)}
checked={isVisible.atd} checked={isVisible[LAYER_IDS.atd]}
> >
Единицы АТД Единицы АТД
</Checkbox> </Checkbox>

@ -2,7 +2,7 @@ import maplibregl from "maplibre-gl";
import Map, { MapProvider } from "react-map-gl"; import Map, { MapProvider } from "react-map-gl";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Sidebar } from "../modules/Sidebar/Sidebar"; import { Sidebar } from "../modules/Sidebar/Sidebar";
import { Layers } from "./Layers"; import { Layers } from "./Layers/Layers";
import { MapPopup } from "./Popup"; import { MapPopup } from "./Popup";
import { Basemap } from "./Basemap"; import { Basemap } from "./Basemap";
import { SignOut } from "../SignOut"; import { SignOut } from "../SignOut";
@ -14,23 +14,30 @@ import { AddressSearch } from "../modules/Sidebar/AddressSearch";
import { TableWrapper } from "../modules/Table/TableWrapper"; import { TableWrapper } from "../modules/Table/TableWrapper";
import { useFilters } from "../stores/useFilters"; import { useFilters } from "../stores/useFilters";
import { useMode } from "../stores/useMode"; import { useMode } from "../stores/useMode";
import { MODE_TO_STATUS_MAPPER } from "../config"; import {
MODE_TO_LAYER_VISIBILITY_MAPPER,
MODE_TO_STATUS_MAPPER,
} from "../config";
import { FiltersButton } from "../modules/Sidebar/FiltersButton"; import { FiltersButton } from "../modules/Sidebar/FiltersButton";
import { LayersControl } from "./LayersControl/LayersControl"; import { LayersControl } from "./LayersControl/LayersControl";
import { useTable } from "../stores/useTable"; import { useTable } from "../stores/useTable";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { useLayersVisibility } from "../stores/useLayersVisibility";
import { LAYER_IDS } from "./Layers/constants";
export const MapComponent = () => { export const MapComponent = () => {
const mapRef = useRef(null); const mapRef = useRef(null);
const mapContainerRef = useRef(null); const mapContainerRef = useRef(null);
const { popup, setPopup } = usePopup(); const { popup, setPopup } = usePopup();
const { setClickedPointConfig } = useClickedPointConfig(); const { setClickedPointConfig } = useClickedPointConfig();
const { setLayersVisibility } = useLayersVisibility();
const { setStatus } = useFilters(); const { setStatus } = useFilters();
const { mode } = useMode(); const { mode } = useMode();
const { tableState, openTable } = useTable(); const { tableState, openTable } = useTable();
useEffect(() => { useEffect(() => {
setStatus(MODE_TO_STATUS_MAPPER[mode]); setStatus(MODE_TO_STATUS_MAPPER[mode]);
setLayersVisibility(MODE_TO_LAYER_VISIBILITY_MAPPER[mode]);
}, [mode]); }, [mode]);
const handleClick = (event) => { const handleClick = (event) => {
@ -119,7 +126,12 @@ export const MapComponent = () => {
}} }}
dragRotate={false} dragRotate={false}
ref={mapRef} ref={mapRef}
interactiveLayerIds={["match-points", "unmatch-points"]} interactiveLayerIds={[
LAYER_IDS["initial-match"],
LAYER_IDS["initial-unmatch"],
LAYER_IDS.approve,
LAYER_IDS.working,
]}
onClick={handleClick} onClick={handleClick}
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}

@ -1,121 +0,0 @@
import { Layer, Source } from "react-map-gl";
import { pointLayer, unmatchPointLayer } from "./layers-config";
import { useLayersVisibility } from "../stores/useLayersVisibility";
import { BASE_URL } from "../api";
import { useFilters } from "../stores/useFilters";
import { usePointSelection } from "../stores/usePointSelection";
import { useUpdateLayerCounter } from "../stores/useUpdateLayerCounter";
const getRegionField = (selectedRegion) => {
if (!selectedRegion) return null;
if (selectedRegion.type === "ao") {
return "okrug_id";
}
return "rayon_id";
};
export const Points = () => {
const { isVisible } = useLayersVisibility();
const { filters } = useFilters();
const { prediction, status, categories, region } = filters;
const { selection } = usePointSelection();
const includedArr = [...selection.included];
const excludedArr = [...selection.excluded];
const { updateCounter } = useUpdateLayerCounter();
const includedExpression = [
"in",
["get", "location_id"],
["literal", includedArr],
];
const excludedExpression = [
"in",
["get", "location_id"],
["literal", excludedArr],
];
const predictionExpression = [
[">=", ["get", "prediction_current"], prediction[0]],
["<=", ["get", "prediction_current"], prediction[1]],
];
const statusExpression = ["in", ["get", "status"], ["literal", status]];
const categoryExpression =
categories.length > 0
? ["in", ["get", "category"], ["literal", categories]]
: true;
const regionExpression = ["==", ["get", getRegionField(region)], region?.id];
const matchFilterExpression = [
"all",
statusExpression,
["!", excludedExpression],
[
"any",
region
? ["all", ...predictionExpression, categoryExpression, regionExpression]
: ["all", ...predictionExpression, categoryExpression],
includedExpression,
],
];
const unmatchFilterExpression = [
"all",
statusExpression,
["!", includedExpression],
[
"any",
[
"!",
region
? [
"all",
...predictionExpression,
categoryExpression,
regionExpression,
]
: ["all", ...predictionExpression, categoryExpression],
],
excludedExpression,
],
];
return (
<>
<Source
id="points"
type="vector"
key={`points-${updateCounter}`}
tiles={[
`${BASE_URL}/martin/public.service_placementpoint/{z}/{x}/{y}.pbf`,
]}
>
<Layer
{...pointLayer}
id={"unmatch-points"}
source={"points"}
source-layer={"public.service_placementpoint"}
layout={{
...pointLayer.layout,
visibility: isVisible.points ? "visible" : "none",
}}
filter={unmatchFilterExpression}
paint={unmatchPointLayer.paint}
/>
<Layer
{...pointLayer}
id={"match-points"}
source={"points"}
source-layer={"public.service_placementpoint"}
layout={{
...pointLayer.layout,
visibility: isVisible.points ? "visible" : "none",
}}
filter={matchFilterExpression}
paint={pointLayer.paint}
/>
</Source>
</>
);
};

@ -7,6 +7,7 @@ import { CATEGORIES, MODES } from "../config";
import { useClickedPointConfig } from "../stores/useClickedPointConfig"; import { useClickedPointConfig } from "../stores/useClickedPointConfig";
import { useMode } from "../stores/useMode"; import { useMode } from "../stores/useMode";
import { useUpdateLayerCounter } from "../stores/useUpdateLayerCounter"; import { useUpdateLayerCounter } from "../stores/useUpdateLayerCounter";
import { LAYER_IDS } from "./Layers/constants";
const popupConfig = [ const popupConfig = [
{ {
@ -112,7 +113,7 @@ const SingleFeaturePopup = ({ feature }) => {
const { include, selection, exclude } = usePointSelection(); const { include, selection, exclude } = usePointSelection();
const { setClickedPointConfig } = useClickedPointConfig(); const { setClickedPointConfig } = useClickedPointConfig();
const { mode } = useMode(); const { mode } = useMode();
const doesMatchFilter = feature.layer.id === "match-points"; const doesMatchFilter = feature.layer.id === LAYER_IDS["initial-match"];
const featureId = feature.properties.location_id; const featureId = feature.properties.location_id;
const { updateCounter } = useUpdateLayerCounter(); const { updateCounter } = useUpdateLayerCounter();

@ -1,109 +0,0 @@
//kiosk - городские киоски
// mfc - многофункциональные центры предоставления государственных и муниципальных услуг
// library - библиотеки
// dk - дома культуры и клубы
// sport - спортивные объекты
import { CATEGORIES } from "../config";
export const pointColors = {
[CATEGORIES.kiosk]: "#4561ff",
[CATEGORIES.mfc]: "#932301",
[CATEGORIES.library]: "#a51eda",
[CATEGORIES.dk]: "#ff5204",
[CATEGORIES.sport]: "#138c44",
[CATEGORIES.residential]: "#f8e502",
[CATEGORIES.retail]: "#002398",
};
export const pointLayer = {
type: "circle",
layout: {},
paint: {
"circle-color": "#a51eda",
"circle-radius": [
"interpolate",
["linear"],
["get", "prediction_current"],
0,
0,
200,
2,
300,
10,
],
"circle-stroke-width": 0.4,
"circle-stroke-color": "#fff",
"circle-opacity": 0.8,
},
};
export const unmatchPointLayer = {
type: "circle",
layout: {},
paint: {
"circle-color": "#b4b4b4",
"circle-radius": 3,
"circle-stroke-width": 0.4,
"circle-stroke-color": "#fff",
"circle-opacity": 0.8,
},
};
export const gridLayer = {
type: "fill",
layout: {},
paint: {
"fill-opacity": 0.5,
"fill-outline-color": "transparent",
},
};
const regionColor = "#676767";
export const aoLayer = {
id: "ao",
type: "line",
source: "ao",
"source-layer": "public.service_ao",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": regionColor,
"line-width": 1.5,
"line-opacity": 0.8,
},
};
export const rayonLayer = {
id: "rayon",
type: "line",
source: "rayon",
"source-layer": "public.service_rayon",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": regionColor,
"line-width": 0.5,
"line-opacity": 0.8,
},
};
export const selectedRegionLayer = {
id: "selected-region",
type: "line",
source: "selected-region",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": "#47006e",
"line-width": 2,
"line-opacity": 1,
},
};

@ -11,3 +11,40 @@ export const api = axios.create({
xsrfHeaderName: "X-CSRFToken", xsrfHeaderName: "X-CSRFToken",
xsrfCookieName: "csrftoken", xsrfCookieName: "csrftoken",
}); });
const enrichParamsWithRegionFilter = (params, region) => {
const resultParams = params ? params : new URLSearchParams();
if (region) {
if (region.type === "ao") {
resultParams.append("ao[]", region.id);
}
if (region.type === "rayon") {
resultParams.append("rayon[]", region.id);
}
}
return resultParams;
};
export const getPoints = async (params, region) => {
const resultParams = enrichParamsWithRegionFilter(params, region);
const { data } = await api.get(
`/api/placement_points?${resultParams.toString()}`
);
return data;
};
export const exportPoints = async (params, region) => {
const resultParams = enrichParamsWithRegionFilter(params, region);
const { data } = await api.get(
`/api/placement_points/to_excel?${resultParams.toString()}`,
{ responseType: "arraybuffer" }
);
return data;
};

@ -1,3 +1,5 @@
import { LAYER_IDS } from "./Map/Layers/constants";
export const STATUSES = { export const STATUSES = {
initial: "К рассмотрению", initial: "К рассмотрению",
approve: "Согласование-установка", approve: "Согласование-установка",
@ -28,3 +30,18 @@ export const MODE_TO_STATUS_MAPPER = {
[MODES.APPROVE]: [STATUSES.approve, STATUSES.working], [MODES.APPROVE]: [STATUSES.approve, STATUSES.working],
[MODES.WORKING]: [STATUSES.working], [MODES.WORKING]: [STATUSES.working],
}; };
export const MODE_TO_LAYER_VISIBILITY_MAPPER = {
[MODES.INITIAL]: {
visible: [LAYER_IDS.initial],
invisible: [LAYER_IDS.approve, LAYER_IDS.working],
},
[MODES.APPROVE]: {
visible: [LAYER_IDS.approve, LAYER_IDS.working],
invisible: [LAYER_IDS.initial],
},
[MODES.WORKING]: {
visible: [LAYER_IDS.working],
invisible: [LAYER_IDS.initial, LAYER_IDS.approve],
},
};

@ -1,7 +1,7 @@
import { Table } from "../Table"; import { Table } from "../Table";
import { columns } from "../InitialTable/columns"; import { columns } from "../InitialTable/columns";
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "../../../api"; import { getPoints } from "../../../api";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { PAGE_SIZE } from "../constants"; import { PAGE_SIZE } from "../constants";
import { STATUSES } from "../../../config"; import { STATUSES } from "../../../config";
@ -10,6 +10,7 @@ import { Button, Select } from "antd";
import { useUpdateStatus } from "../../../hooks/useUpdateStatus"; import { useUpdateStatus } from "../../../hooks/useUpdateStatus";
import { HeaderWrapper } from "../HeaderWrapper"; import { HeaderWrapper } from "../HeaderWrapper";
import { useExportApproveAndWorkingData } from "./useExportApproveAndWorkingData"; import { useExportApproveAndWorkingData } from "./useExportApproveAndWorkingData";
import { useFilters } from "../../../stores/useFilters";
const statusOptions = [ const statusOptions = [
{ label: STATUSES.approve, value: STATUSES.approve }, { label: STATUSES.approve, value: STATUSES.approve },
@ -107,11 +108,14 @@ export const ApproveAndWorkingTable = ({ fullWidth }) => {
const [pageSize, setPageSize] = useState(PAGE_SIZE); const [pageSize, setPageSize] = useState(PAGE_SIZE);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [selectedIds, setSelectedIds] = useState([]); const [selectedIds, setSelectedIds] = useState([]);
const {
filters: { region },
} = useFilters();
const clearSelected = () => setSelectedIds([]); const clearSelected = () => setSelectedIds([]);
const { data, isInitialLoading } = useQuery( const { data, isInitialLoading } = useQuery(
["approve-working-points"], ["approve-working-points", region],
async () => { async () => {
const params = new URLSearchParams({ const params = new URLSearchParams({
page, page,
@ -119,11 +123,7 @@ export const ApproveAndWorkingTable = ({ fullWidth }) => {
"status[]": [STATUSES.approve, STATUSES.working], "status[]": [STATUSES.approve, STATUSES.working],
}); });
const { data } = await api.get( return await getPoints(params, region);
`/api/placement_points?${params.toString()}`
);
return data;
} }
); );

@ -1,23 +1,26 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { download } from "../../../utils";
import { exportData } from "../utils";
import { STATUSES } from "../../../config"; import { STATUSES } from "../../../config";
import { exportPoints } from "../../../api";
import { handleExportSuccess } from "../ExportButton";
import { useFilters } from "../../../stores/useFilters";
export const useExportApproveAndWorkingData = (enabled, onSettled) => { export const useExportApproveAndWorkingData = (enabled, onSettled) => {
const {
filters: { region },
} = useFilters();
return useQuery( return useQuery(
["export-approve-working"], ["export-approve-working", region],
async () => { async () => {
const params = new URLSearchParams({ const params = new URLSearchParams({
"status[]": [STATUSES.approve, STATUSES.working], "status[]": [STATUSES.approve, STATUSES.working],
}); });
return await exportData(params); return await exportPoints(params, region);
}, },
{ {
enabled, enabled,
onSuccess: (data) => { onSuccess: handleExportSuccess,
download("postamates.xlsx", data);
},
onSettled, onSettled,
} }
); );

@ -1,6 +1,11 @@
import { useState } from "react"; import { useState } from "react";
import { Button } from "antd"; import { Button } from "antd";
import { DownloadOutlined } from "@ant-design/icons"; import { DownloadOutlined } from "@ant-design/icons";
import { download } from "../../utils";
export const handleExportSuccess = (data) => {
download("postamates.xlsx", data);
};
export const ExportButton = ({ provider }) => { export const ExportButton = ({ provider }) => {
const [startExport, setStartExport] = useState(false); const [startExport, setStartExport] = useState(false);

@ -1,12 +1,12 @@
import { useFilters } from "../../../stores/useFilters"; import { useFilters } from "../../../stores/useFilters";
import { usePointSelection } from "../../../stores/usePointSelection"; import { usePointSelection } from "../../../stores/usePointSelection";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { download } from "../../../utils"; import { exportPoints } from "../../../api";
import { exportData } from "../utils"; import { handleExportSuccess } from "../ExportButton";
export const useExportInitialData = (enabled, onSettled) => { export const useExportInitialData = (enabled, onSettled) => {
const { filters } = useFilters(); const { filters } = useFilters();
const { prediction, status, categories } = filters; const { prediction, status, categories, region } = filters;
const { selection } = usePointSelection(); const { selection } = usePointSelection();
return useQuery( return useQuery(
@ -20,13 +20,11 @@ export const useExportInitialData = (enabled, onSettled) => {
"excluded[]": [...selection.excluded], "excluded[]": [...selection.excluded],
}); });
return await exportData(params); return await exportPoints(params, region);
}, },
{ {
enabled, enabled,
onSuccess: (data) => { onSuccess: handleExportSuccess,
download("postamates.xlsx", data);
},
onSettled, onSettled,
} }
); );

@ -3,7 +3,7 @@ import { PAGE_SIZE } from "../constants";
import { useFilters } from "../../../stores/useFilters"; import { useFilters } from "../../../stores/useFilters";
import { usePointSelection } from "../../../stores/usePointSelection"; import { usePointSelection } from "../../../stores/usePointSelection";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { api } from "../../../api"; import { getPoints } from "../../../api";
import { useMergeTableData } from "../useMergeTableData"; import { useMergeTableData } from "../useMergeTableData";
import { STATUSES } from "../../../config"; import { STATUSES } from "../../../config";
@ -25,21 +25,7 @@ export const useInitialTableData = (page) => {
"included[]": [...selection.included], "included[]": [...selection.included],
}); });
if (region) { return await getPoints(params, 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 } { keepPreviousData: true }
); );

@ -2,30 +2,33 @@ import { useCallback, useState } from "react";
import { PAGE_SIZE } from "../constants"; import { PAGE_SIZE } from "../constants";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { STATUSES } from "../../../config"; import { STATUSES } from "../../../config";
import { api } from "../../../api"; import { getPoints } from "../../../api";
import { useMergeTableData } from "../useMergeTableData"; import { useMergeTableData } from "../useMergeTableData";
import { Table } from "../Table"; import { Table } from "../Table";
import { columns } from "../InitialTable/columns"; import { columns } from "../InitialTable/columns";
import { HeaderWrapper } from "../HeaderWrapper"; import { HeaderWrapper } from "../HeaderWrapper";
import { useExportWorkingData } from "./useExportWorkingData"; import { useExportWorkingData } from "./useExportWorkingData";
import { useFilters } from "../../../stores/useFilters";
export const WorkingTable = ({ fullWidth }) => { export const WorkingTable = ({ fullWidth }) => {
const [pageSize, setPageSize] = useState(PAGE_SIZE); const [pageSize, setPageSize] = useState(PAGE_SIZE);
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const {
filters: { region },
} = useFilters();
const { data, isInitialLoading } = useQuery(["working-points"], async () => { const { data, isInitialLoading } = useQuery(
const params = new URLSearchParams({ ["working-points", region],
page, async () => {
page_size: pageSize, const params = new URLSearchParams({
"status[]": [STATUSES.working], page,
}); page_size: pageSize,
"status[]": [STATUSES.working],
});
const { data } = await api.get( return await getPoints(params, region);
`/api/placement_points?${params.toString()}` }
); );
return data;
});
const { data: mergedData, isClickedPointLoading } = useMergeTableData( const { data: mergedData, isClickedPointLoading } = useMergeTableData(
data, data,

@ -1,23 +1,26 @@
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { download } from "../../../utils";
import { exportData } from "../utils";
import { STATUSES } from "../../../config"; import { STATUSES } from "../../../config";
import { exportPoints } from "../../../api";
import { useFilters } from "../../../stores/useFilters";
import { handleExportSuccess } from "../ExportButton";
export const useExportWorkingData = (enabled, onSettled) => { export const useExportWorkingData = (enabled, onSettled) => {
const {
filters: { region },
} = useFilters();
return useQuery( return useQuery(
["export-working"], ["export-working", region],
async () => { async () => {
const params = new URLSearchParams({ const params = new URLSearchParams({
"status[]": [STATUSES.working], "status[]": [STATUSES.working],
}); });
return await exportData(params); return await exportPoints(params, region);
}, },
{ {
enabled, enabled,
onSuccess: (data) => { onSuccess: handleExportSuccess,
download("postamates.xlsx", data);
},
onSettled, onSettled,
} }
); );

@ -1,10 +0,0 @@
import { api } from "../../api";
export const exportData = async (params) => {
const { data } = await api.get(
`/api/placement_points/to_excel?${params.toString()}`,
{ responseType: "arraybuffer" }
);
return data;
};

@ -1,17 +1,31 @@
import { create } from "zustand"; import { create } from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
import { LAYER_IDS } from "../Map/Layers/constants";
const INITIAL_STATE = { const INITIAL_STATE = {
points: true, [LAYER_IDS.initial]: true,
atd: true, [LAYER_IDS.approve]: false,
[LAYER_IDS.working]: false,
[LAYER_IDS.atd]: true,
}; };
const store = (set) => ({ const store = (set) => ({
isVisible: INITIAL_STATE, isVisible: INITIAL_STATE,
toggleVisibility: (layerId) => toggleVisibility: (layerId) =>
set((state) => { set((state) => {
state.isVisible[layerId] = !state.isVisible[layerId]; state.isVisible[layerId] = !state.isVisible[layerId];
}), }),
setLayersVisibility: (config) =>
set((state) => {
config.visible.forEach((layerId) => {
state.isVisible[layerId] = true;
});
config.invisible.forEach((layerId) => {
state.isVisible[layerId] = false;
});
}),
}); });
export const useLayersVisibility = create(immer(store)); export const useLayersVisibility = create(immer(store));

Loading…
Cancel
Save