Update status from approve table

dev
Platon Yasev 3 years ago
parent 266c3bd597
commit cacef77eda

@ -12,12 +12,21 @@ import { useClickedPointConfig } from "../stores/useClickedPointConfig";
import { Legend } from "../modules/Sidebar/Legend"; import { Legend } from "../modules/Sidebar/Legend";
import { AddressSearch } from "../modules/Sidebar/AddressSearch"; import { AddressSearch } from "../modules/Sidebar/AddressSearch";
import { TableWrapper } from "../modules/Table/TableWrapper"; import { TableWrapper } from "../modules/Table/TableWrapper";
import { useFilters } from "../stores/useFilters";
import { useMode } from "../stores/useMode";
import { MODE_TO_STATUS_MAPPER } from "../config";
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 { setStatus } = useFilters();
const { mode } = useMode();
useEffect(() => {
setStatus(MODE_TO_STATUS_MAPPER[mode]);
}, [mode]);
const handleClick = (event) => { const handleClick = (event) => {
if (!event.features) { if (!event.features) {

@ -6,6 +6,7 @@ import { useEffect, useState } from "react";
import { CATEGORIES, MODES } from "../config"; 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";
const popupConfig = [ const popupConfig = [
{ {
@ -114,6 +115,8 @@ const SingleFeaturePopup = ({ feature }) => {
const doesMatchFilter = feature.layer.id === "match-points"; const doesMatchFilter = feature.layer.id === "match-points";
const featureId = feature.properties.location_id; const featureId = feature.properties.location_id;
const { updateCounter } = useUpdateLayerCounter();
useEffect(() => setClickedPointConfig(featureId, doesMatchFilter), [feature]); useEffect(() => setClickedPointConfig(featureId, doesMatchFilter), [feature]);
const isResidential = feature.properties.category === CATEGORIES.residential; const isResidential = feature.properties.category === CATEGORIES.residential;
@ -134,7 +137,7 @@ const SingleFeaturePopup = ({ feature }) => {
return ( return (
<> <>
<div> <div key={`popup-${updateCounter}`}>
{config.map(({ field, name }) => { {config.map(({ field, name }) => {
return ( return (
<Row className={twMerge("p-1")} key={field}> <Row className={twMerge("p-1")} key={field}>

@ -22,3 +22,9 @@ export const MODES = {
APPROVE: "APPROVE", APPROVE: "APPROVE",
WORKING: "WORKING", WORKING: "WORKING",
}; };
export const MODE_TO_STATUS_MAPPER = {
[MODES.INITIAL]: [STATUSES.initial],
[MODES.APPROVE]: [STATUSES.approve, STATUSES.working],
[MODES.WORKING]: [STATUSES.working],
};

@ -0,0 +1,19 @@
import { useMutation } from "@tanstack/react-query";
import { api } from "../api";
import { useUpdateLayerCounter } from "../stores/useUpdateLayerCounter";
export const useUpdateStatus = ({ onSuccess }) => {
const { toggleUpdateCounter } = useUpdateLayerCounter();
return useMutation({
mutationFn: (params) => {
return api.put(
`/api/placement_points/update_status?${params.toString()}`
);
},
onSuccess: () => {
toggleUpdateCounter();
onSuccess();
},
});
};

@ -1,44 +1,36 @@
import { Alert, Button, Modal } from "antd"; import { Alert, Button, Modal } from "antd";
import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useQueryClient } from "@tanstack/react-query";
import { api } from "../../../api";
import { useFilters } from "../../../stores/useFilters"; import { useFilters } from "../../../stores/useFilters";
import { usePointSelection } from "../../../stores/usePointSelection"; import { usePointSelection } from "../../../stores/usePointSelection";
import { STATUSES } from "../../../config"; import { STATUSES } from "../../../config";
import { useUpdateLayerCounter } from "../../../stores/useUpdateLayerCounter";
import { useState } from "react"; import { useState } from "react";
import { useUpdateStatus } from "../../../hooks/useUpdateStatus";
export const TakeToWorkButton = () => { export const TakeToWorkButton = () => {
const { filters } = useFilters(); const { filters } = useFilters();
const { prediction, categories } = filters; const { prediction, categories } = filters;
const { selection } = usePointSelection(); const { selection } = usePointSelection();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { toggleUpdateCounter } = useUpdateLayerCounter();
const [isSuccessModalOpened, setIsSuccessModalOpened] = useState(false); const [isSuccessModalOpened, setIsSuccessModalOpened] = useState(false);
const { mutate } = useMutation({ const { mutate: updateStatus } = useUpdateStatus({
mutationFn: () => {
const params = new URLSearchParams({
status: STATUSES.approve,
"prediction_current[]": prediction,
"categories[]": categories,
"included[]": [...selection.included],
"excluded[]": [...selection.excluded],
});
return api.put(
`/api/placement_points/update_status?${params.toString()}`
);
},
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries(["table", 1, filters]); queryClient.invalidateQueries(["table", 1, filters]);
toggleUpdateCounter();
setIsSuccessModalOpened(true); setIsSuccessModalOpened(true);
}, },
}); });
const takeToWork = () => { const takeToWork = () => {
mutate(); const params = new URLSearchParams({
status: STATUSES.approve,
"prediction_current[]": prediction,
"categories[]": categories,
"included[]": [...selection.included],
"excluded[]": [...selection.excluded],
});
updateStatus(params);
}; };
return ( return (

@ -1,17 +1,105 @@
import { Table } from "../Table"; import { Table } from "../Table";
import { columns } from "../InitialTable/columns"; import { columns } from "../InitialTable/columns";
import { useQuery } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api } from "../../../api"; import { api } 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";
import { useMergeTableData } from "../useMergeTableData"; import { useMergeTableData } from "../useMergeTableData";
import { Button, Select } from "antd";
import { useUpdateStatus } from "../../../hooks/useUpdateStatus";
const statusOptions = [
{ label: STATUSES.approve, value: STATUSES.approve },
{ label: STATUSES.working, value: STATUSES.working },
];
const StatusSelect = ({ value, onChange, disabled }) => {
const handleClick = (e) => e.stopPropagation();
const handleChange = (value) => {
onChange(value);
};
return (
<Select
style={{
width: 250,
}}
value={value}
onChange={handleChange}
options={statusOptions}
disabled={disabled}
placeholder="Выберите статус"
onClick={handleClick}
/>
);
};
const ChangeStatusButton = ({ selectedIds, selectedStatus }) => {
const queryClient = useQueryClient();
const { mutate: updateStatus } = useUpdateStatus({
onSuccess: () => {
queryClient.invalidateQueries(["approve-points"]);
},
});
const handleClick = (e) => {
e.stopPropagation();
const params = new URLSearchParams({
status: selectedStatus,
"location_ids[]": selectedIds,
});
updateStatus(params);
};
return (
<Button type="primary" onClick={handleClick}>
Обновить статус
</Button>
);
};
const Header = ({ selectedIds, onClearSelected }) => {
const [status, setStatus] = useState(STATUSES.approve);
const handleClear = (e) => {
e.stopPropagation();
onClearSelected();
};
return (
<div className={"flex items-center w-full justify-between"}>
<div className={"flex items-center gap-x-4"}>
<span className="py-[5px]">Таблица атрибутов</span>
{selectedIds.length > 0 && (
<>
<StatusSelect value={status} onChange={setStatus} />
<ChangeStatusButton
selectedIds={selectedIds}
selectedStatus={status}
/>
</>
)}
</div>
{selectedIds.length > 0 && (
<Button type="text" onClick={handleClear}>
Очистить все
</Button>
)}
</div>
);
};
export const ApproveTable = () => { export const ApproveTable = () => {
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([]);
console.log(selectedIds);
const clearSelected = () => setSelectedIds([]);
const { data } = useQuery(["approve-points"], async () => { const { data } = useQuery(["approve-points"], async () => {
const params = new URLSearchParams({ const params = new URLSearchParams({
@ -35,13 +123,16 @@ export const ApproveTable = () => {
const handlePageChange = useCallback((page) => setPage(page), []); const handlePageChange = useCallback((page) => setPage(page), []);
const rowSelection = { const rowSelection = {
onChange: (selectedRowKeys) => { selectedRowKeys: selectedIds,
setSelectedIds(selectedRowKeys); onChange: (selectedRowKeys) => setSelectedIds(selectedRowKeys),
}, hideSelectAll: true,
}; };
return ( return (
<Table <Table
header={
<Header selectedIds={selectedIds} onClearSelected={clearSelected} />
}
rowSelection={rowSelection} rowSelection={rowSelection}
data={mergedData} data={mergedData}
onPageChange={handlePageChange} onPageChange={handlePageChange}

@ -58,3 +58,11 @@
.ant-table-tbody > tr.ant-table-row.scroll-row:hover > td { .ant-table-tbody > tr.ant-table-row.scroll-row:hover > td {
@apply bg-lime-200; @apply bg-lime-200;
} }
.ant-collapse > .ant-collapse-item > .ant-collapse-header {
@apply !items-center;
}
.ant-collapse-header-text {
@apply flex items-center;
}

@ -5,6 +5,7 @@ import parse from "wellknown";
import { useMap } from "react-map-gl"; import { useMap } from "react-map-gl";
import { useClickedPointConfig } from "../../stores/useClickedPointConfig"; import { useClickedPointConfig } from "../../stores/useClickedPointConfig";
import scrollIntoView from "scroll-into-view-if-needed"; import scrollIntoView from "scroll-into-view-if-needed";
import { twMerge } from "tailwind-merge";
export const Table = React.memo( export const Table = React.memo(
({ ({
@ -16,6 +17,7 @@ export const Table = React.memo(
page, page,
onPageChange, onPageChange,
columns, columns,
header,
}) => { }) => {
const { clickedPointConfig } = useClickedPointConfig(); const { clickedPointConfig } = useClickedPointConfig();
const { map } = useMap(); const { map } = useMap();
@ -38,7 +40,16 @@ export const Table = React.memo(
return ( return (
<div className="w-screen"> <div className="w-screen">
<Collapse> <Collapse>
<Collapse.Panel key="1" header="Таблица атрибутов"> <Collapse.Panel
key="1"
header={
header ? (
header
) : (
<span className="py-[5px]">Таблица атрибутов</span>
)
}
>
<AntdTable <AntdTable
ref={tableRef} ref={tableRef}
className="table" className="table"
@ -74,9 +85,10 @@ export const Table = React.memo(
}} }}
rowSelection={rowSelection} rowSelection={rowSelection}
rowClassName={(record) => rowClassName={(record) =>
record.location_id === clickedPointConfig?.id twMerge(
? "scroll-row" "cursor-pointer",
: "" record.location_id === clickedPointConfig?.id && "scroll-row"
)
} }
/> />
</Collapse.Panel> </Collapse.Panel>

@ -1,11 +1,12 @@
import { create } from "zustand"; import { create } from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
import { STATUSES } from "../config";
const INITIAL = { const INITIAL = {
prediction: [200, 299], prediction: [200, 299],
categories: [], categories: [],
region: null, region: null,
status: ["К рассмотрению"], status: [STATUSES.initial],
}; };
const store = (set) => ({ const store = (set) => ({

@ -1,26 +1,13 @@
import { create } from "zustand"; import { create } from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
import { MODES, STATUSES } from "../config"; import { MODES } from "../config";
import { useFilters } from "./useFilters";
const store = (set) => ({ const store = (set) => ({
mode: MODES.INITIAL, mode: MODES.APPROVE,
setMode: (mode) => { setMode: (mode) => {
set((state) => { set((state) => {
state.mode = mode; state.mode = mode;
if (mode === MODES.INITIAL) {
useFilters.getState().setStatus([STATUSES.initial]);
return state;
}
if (mode === MODES.APPROVE) {
useFilters.getState().setStatus([STATUSES.approve, STATUSES.working]);
return state;
}
if (mode === MODES.WORKING) {
useFilters.getState().setStatus([STATUSES.working]);
return state;
}
}); });
}, },
}); });

Loading…
Cancel
Save