diff --git a/src/Map/Layers/layers-config.js b/src/Map/Layers/layers-config.js index 692b077..1f85979 100644 --- a/src/Map/Layers/layers-config.js +++ b/src/Map/Layers/layers-config.js @@ -24,7 +24,17 @@ const getPointConfig = (color = INITIAL_COLOR, size = POINT_SIZE) => { paint: { ...DEFAULT_POINT_CONFIG.paint, "circle-color": color, - "circle-radius": size, + "circle-radius": [ + "interpolate", + ["linear"], + ["zoom"], + 3, + 0, + 9, + 2, + 11, + size, + ], }, }; }; diff --git a/src/Map/Popup/mode-popup/FeatureProperties.jsx b/src/Map/Popup/mode-popup/FeatureProperties.jsx index 4ca853d..e585776 100644 --- a/src/Map/Popup/mode-popup/FeatureProperties.jsx +++ b/src/Map/Popup/mode-popup/FeatureProperties.jsx @@ -1,15 +1,16 @@ import { CATEGORIES, STATUSES } from "../../../config"; import { - popupConfig, - residentialPointConfig, + commonPopupConfig, + residentialPopupConfig, rivalsConfig, workingPointFields, } from "./config"; import { Col, Row } from "antd"; import { twMerge } from "tailwind-merge"; import { LAYER_IDS } from "../../Layers/constants"; +import { isNil } from "../../../utils.js"; -export const FeatureProperties = ({ feature, dynamicStatus }) => { +export const FeatureProperties = ({ feature, dynamicStatus, postamatId }) => { const isResidential = feature.properties.category === CATEGORIES.residential; const isWorking = feature.properties.status === STATUSES.working; const isRivals = @@ -20,25 +21,36 @@ export const FeatureProperties = ({ feature, dynamicStatus }) => { return rivalsConfig; } - const config = isResidential ? residentialPointConfig : popupConfig; + const config = isResidential ? residentialPopupConfig : commonPopupConfig; return isWorking ? [...config, ...workingPointFields] : config; }; + const getValue = ({ field, render, empty }) => { + let value = feature.properties[field]; + + if (field === "status" && dynamicStatus) { + value = dynamicStatus; + } + + if (field === "postamat_id" && postamatId) { + value = postamatId; + } + + value = render ? render(value) : value; + value = isNil(value) && empty ? empty : value; + + return value; + }; + return (
- {getConfig().map(({ field, name, render }) => { - const value = - dynamicStatus && field === "status" - ? dynamicStatus - : feature.properties[field]; - const renderedValue = render ? render(value) : value; - + {getConfig().map((row) => { return ( - + - {name} + {row.name} - {renderedValue} + {getValue(row)} ); })} diff --git a/src/Map/Popup/mode-popup/OnApprovalPointPopup.jsx b/src/Map/Popup/mode-popup/OnApprovalPointPopup.jsx index 59d6382..0f14c52 100644 --- a/src/Map/Popup/mode-popup/OnApprovalPointPopup.jsx +++ b/src/Map/Popup/mode-popup/OnApprovalPointPopup.jsx @@ -5,45 +5,119 @@ import { Title } from "../../../components/Title"; import { useQueryClient } from "@tanstack/react-query"; import { useUpdateStatus } from "../../../hooks/useUpdateStatus"; import { StatusSelect } from "../../../components/StatusSelect"; -import { useCanEdit } from "../../../api"; +import { useCanEdit, useUpdatePostamatId } from "../../../api"; +import { Button, InputNumber } from "antd"; +import { STATUSES } from "../../../config"; +import { isNil } from "../../../utils.js"; export const OnApprovalPointPopup = ({ feature }) => { const featureId = feature.properties.id; const { setClickedPointConfig } = useClickedPointConfig(); - const [status, setStatus] = useState(feature.properties.status); + + const { status: initialStatus, postamat_id: initialPostamatId } = + feature.properties; + const [status, setStatus] = useState(initialStatus); + + const [postamatId, setPostamatId] = useState(initialPostamatId); + const [needToFillPostamatId, setNeedToFillPostamatId] = useState( + status === STATUSES.working && isNil(postamatId) + ); + + const [error, setError] = useState(""); useEffect(() => setClickedPointConfig(featureId, false), [feature]); const queryClient = useQueryClient(); - const { mutate: updateStatus } = useUpdateStatus({ - onSuccess: () => { - queryClient.invalidateQueries(["on-approval-points"]); - queryClient.invalidateQueries(["clicked-point", featureId]); - }, - }); + const onSuccess = () => { + queryClient.invalidateQueries(["on-approval-points"]); + queryClient.invalidateQueries(["clicked-point", featureId]); + }; - const handleStatusChange = (value) => { - setStatus(value); + const { mutateAsync: updateStatus, isLoading: isStatusUpdating } = + useUpdateStatus({}); + const { mutateAsync: updatePostamatId, isLoading: isPostamatIdUpdating } = + useUpdatePostamatId(); + + const isUpdating = isStatusUpdating || isPostamatIdUpdating; + + const makeWorking = async () => { + const updatePostamatIdParams = new URLSearchParams({ + id: featureId, + postamat_id: postamatId, + }); - const params = new URLSearchParams({ - status: value, + const updateStatusParams = new URLSearchParams({ + status: STATUSES.working, "location_ids[]": [featureId], }); - updateStatus(params); + try { + await updatePostamatId(updatePostamatIdParams); + } catch (err) { + setError("Указанный id уже существует, попробуйте другой"); + return; + } + + await updateStatus(updateStatusParams); + + onSuccess(); + setNeedToFillPostamatId(false); + }; + + const handleStatusChange = (value) => { + setStatus(value); + + if (value === STATUSES.working) { + setNeedToFillPostamatId(true); + } else { + setNeedToFillPostamatId(false); + const params = new URLSearchParams({ + status: value, + "location_ids[]": [featureId], + }); + + updateStatus(params).then(onSuccess); + } }; const canEdit = useCanEdit(); return ( <> - + {canEdit && (
-
+
<StatusSelect value={status} onChange={handleStatusChange} /> + {needToFillPostamatId && ( + <> + <Title text="Укажите id постамата" /> + <InputNumber + className="w-full" + min={0} + precision={0} + value={postamatId} + onChange={(value) => setPostamatId(value)} + /> + {error && ( + <div className="text-primary text-center">{error}</div> + )} + <Button + type="primary" + disabled={isNil(postamatId)} + onClick={makeWorking} + loading={isUpdating} + > + Обновить статус + </Button> + </> + )} </div> </div> )} diff --git a/src/Map/Popup/mode-popup/config.js b/src/Map/Popup/mode-popup/config.js index 98b81df..0acd75a 100644 --- a/src/Map/Popup/mode-popup/config.js +++ b/src/Map/Popup/mode-popup/config.js @@ -1,6 +1,6 @@ import { STATUS_LABEL_MAPPER } from "../../../config"; -export const popupConfig = [ +export const commonPopupConfig = [ { name: "Id", field: "id", @@ -11,11 +11,11 @@ export const popupConfig = [ }, { name: "Район", - field: "rayon_id", + field: "area_id", }, { name: "Округ", - field: "okrug_id", + field: "district_id", }, { name: "Название", @@ -36,40 +36,8 @@ export const popupConfig = [ }, ]; -export const residentialPointConfig = [ - { - name: "Id", - field: "id", - }, - { - name: "Адрес", - field: "address", - }, - { - name: "Район", - field: "rayon_id", - }, - { - name: "Округ", - field: "okrug_id", - }, - { - name: "Название", - field: "name", - }, - { - name: "Категория", - field: "category", - }, - { - name: "Статус", - field: "status", - render: (value) => STATUS_LABEL_MAPPER[value], - }, - { - name: "Прогнозный трафик", - field: "prediction_current", - }, +export const residentialPopupConfig = [ + ...commonPopupConfig, { name: "Кол-во квартир", field: "flat_cnt", @@ -92,6 +60,7 @@ export const workingPointFields = [ { name: "Факт", field: "fact" }, { name: "Расхождение с прогнозом", field: "delta_current" }, { name: "Зрелость", field: "age_day" }, + { name: "id постамата", field: "postamat_id", empty: "Не указан" }, ]; export const rivalsConfig = [ diff --git a/src/api.js b/src/api.js index fe19a9d..eaedbba 100644 --- a/src/api.js +++ b/src/api.js @@ -1,5 +1,5 @@ import axios from "axios"; -import { useQuery } from "@tanstack/react-query"; +import { useMutation, useQuery } from "@tanstack/react-query"; import { STATUSES } from "./config"; import { usePointSelection } from "./stores/usePointSelection"; import { usePendingPointsFilters } from "./stores/usePendingPointsFilters"; @@ -113,3 +113,13 @@ export const useCanEdit = () => { return data === "editor"; }; + +export const useUpdatePostamatId = () => { + return useMutation({ + mutationFn: (params) => { + return api.put( + `/api/placement_points/update_postamat_id?${params.toString()}` + ); + }, + }); +}; diff --git a/src/modules/Table/OnApprovalTable/MakeWorkingTable/MakeWorkingModal.jsx b/src/modules/Table/OnApprovalTable/MakeWorkingTable/MakeWorkingModal.jsx index 0379793..1dfec91 100644 --- a/src/modules/Table/OnApprovalTable/MakeWorkingTable/MakeWorkingModal.jsx +++ b/src/modules/Table/OnApprovalTable/MakeWorkingTable/MakeWorkingModal.jsx @@ -1,5 +1,5 @@ -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { api, getPoints } from "../../../../api"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { getPoints, useUpdatePostamatId } from "../../../../api"; import { Button, Modal } from "antd"; import { MakeWorkingTable } from "./MakeWorkingTable"; import { useEffect, useState } from "react"; @@ -7,16 +7,6 @@ import { usePopup } from "../../../../stores/usePopup"; import { useUpdateStatus } from "../../../../hooks/useUpdateStatus"; import { STATUSES } from "../../../../config"; -const useUpdatePostamatId = () => { - return useMutation({ - mutationFn: (params) => { - return api.put( - `/api/placement_points/update_postamat_id?${params.toString()}` - ); - }, - }); -}; - export const MakeWorkingModal = ({ selectedIds, onClose, onSuccess }) => { const { data } = useQuery(["make-working-table", selectedIds], async () => { const params = new URLSearchParams({ diff --git a/src/modules/Table/columns.js b/src/modules/Table/columns.js index 2614c7b..dd29cd4 100644 --- a/src/modules/Table/columns.js +++ b/src/modules/Table/columns.js @@ -9,15 +9,15 @@ export const columns = [ }, { title: "Район", - dataIndex: "rayon", - key: "rayon", + dataIndex: "area", + key: "area", width: "120px", ellipsis: true, }, { title: "Округ", - dataIndex: "okrug", - key: "okrug", + dataIndex: "district", + key: "district", width: "120px", ellipsis: true, }, diff --git a/src/stores/useLayersVisibility.js b/src/stores/useLayersVisibility.js index a8a9a63..65a3f6a 100644 --- a/src/stores/useLayersVisibility.js +++ b/src/stores/useLayersVisibility.js @@ -8,8 +8,8 @@ const INITIAL_STATE = { [LAYER_IDS.working]: false, [LAYER_IDS.filteredWorking]: false, [LAYER_IDS.cancelled]: false, - [LAYER_IDS.pvz]: false, - [LAYER_IDS.other]: false, + [LAYER_IDS.pvz]: true, + [LAYER_IDS.other]: true, }; const STATIC_LAYERS = [LAYER_IDS.pvz, LAYER_IDS.other]; diff --git a/src/utils.js b/src/utils.js index f7aca1c..cc59667 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,3 +10,6 @@ export function download(filename, data) { downloadLink.click(); document.body.removeChild(downloadLink); } + +export const isNil = (value) => + value === undefined || value === null || value === "";