Add permissions; validate making working form

dev
Platon Yasev 3 years ago
parent 558dbb3940
commit 455ecc4122

@ -4,8 +4,8 @@ import { MODES } from "../../config";
import { useMode } from "../../stores/useMode"; import { useMode } from "../../stores/useMode";
import { LAYER_IDS } from "../Layers/constants"; import { LAYER_IDS } from "../Layers/constants";
import { PopupWrapper } from "./PopupWrapper"; import { PopupWrapper } from "./PopupWrapper";
import { InitialPointPopup } from "./mode-popup/InitialPointPopup"; import { PendingPointPopup } from "./mode-popup/PendingPointPopup";
import { ApproveWorkingPointPopup } from "./mode-popup/ApproveWorkingPointPopup"; import { OnApprovalPointPopup } from "./mode-popup/OnApprovalPointPopup";
import { WorkingPointPopup } from "./mode-popup/WorkingPointPopup"; import { WorkingPointPopup } from "./mode-popup/WorkingPointPopup";
import { FeatureProperties } from "./mode-popup/FeatureProperties"; import { FeatureProperties } from "./mode-popup/FeatureProperties";
@ -22,7 +22,7 @@ const SingleFeaturePopup = ({ feature }) => {
} }
if (mode === MODES.ON_APPROVAL) { if (mode === MODES.ON_APPROVAL) {
return <ApproveWorkingPointPopup feature={feature} />; return <OnApprovalPointPopup feature={feature} />;
} }
if (mode === MODES.WORKING) { if (mode === MODES.WORKING) {
@ -30,7 +30,7 @@ const SingleFeaturePopup = ({ feature }) => {
} }
if (mode === MODES.PENDING && isInitialLayer) if (mode === MODES.PENDING && isInitialLayer)
return <InitialPointPopup feature={feature} />; return <PendingPointPopup feature={feature} />;
return <FeatureProperties feature={feature} />; return <FeatureProperties feature={feature} />;
}; };

@ -5,8 +5,9 @@ import { Title } from "../../../components/Title";
import { useQueryClient } from "@tanstack/react-query"; import { useQueryClient } from "@tanstack/react-query";
import { useUpdateStatus } from "../../../hooks/useUpdateStatus"; import { useUpdateStatus } from "../../../hooks/useUpdateStatus";
import { StatusSelect } from "../../../components/StatusSelect"; import { StatusSelect } from "../../../components/StatusSelect";
import { useCanEdit } from "../../../api";
export const ApproveWorkingPointPopup = ({ feature }) => { export const OnApprovalPointPopup = ({ feature }) => {
const featureId = feature.properties.id; const featureId = feature.properties.id;
const { setClickedPointConfig } = useClickedPointConfig(); const { setClickedPointConfig } = useClickedPointConfig();
const [status, setStatus] = useState(feature.properties.status); const [status, setStatus] = useState(feature.properties.status);
@ -33,15 +34,19 @@ export const ApproveWorkingPointPopup = ({ feature }) => {
updateStatus(params); updateStatus(params);
}; };
const canEdit = useCanEdit();
return ( return (
<> <>
<FeatureProperties feature={feature} dynamicStatus={status} /> <FeatureProperties feature={feature} dynamicStatus={status} />
<div className="flex justify-center mt-4"> {canEdit && (
<div className={"flex flex-col items-center"}> <div className="flex justify-center mt-4">
<Title text="Изменить статус" /> <div className={"flex flex-col items-center"}>
<StatusSelect value={status} onChange={handleStatusChange} /> <Title text="Изменить статус" />
<StatusSelect value={status} onChange={handleStatusChange} />
</div>
</div> </div>
</div> )}
</> </>
); );
}; };

@ -4,8 +4,9 @@ import { LAYER_IDS } from "../../Layers/constants";
import { useEffect } from "react"; import { useEffect } from "react";
import { FeatureProperties } from "./FeatureProperties"; import { FeatureProperties } from "./FeatureProperties";
import { Button } from "antd"; import { Button } from "antd";
import { useCanEdit } from "../../../api";
export const InitialPointPopup = ({ feature }) => { export const PendingPointPopup = ({ feature }) => {
const { include, selection, exclude } = usePointSelection(); const { include, selection, exclude } = usePointSelection();
const { setClickedPointConfig } = useClickedPointConfig(); const { setClickedPointConfig } = useClickedPointConfig();
const doesMatchFilter = feature.layer.id === LAYER_IDS["initial-match"]; const doesMatchFilter = feature.layer.id === LAYER_IDS["initial-match"];
@ -25,17 +26,21 @@ export const InitialPointPopup = ({ feature }) => {
} }
}; };
const canEdit = useCanEdit();
return ( return (
<> <>
<FeatureProperties feature={feature} /> <FeatureProperties feature={feature} />
<Button {canEdit && (
type="primary" <Button
className="mt-2 mx-auto" type="primary"
block className="mt-2 mx-auto"
onClick={handleSelect} block
> onClick={handleSelect}
{isSelected ? "Исключить из выборки" : "Добавить в выборку"} >
</Button> {isSelected ? "Исключить из выборки" : "Добавить в выборку"}
</Button>
)}
</> </>
); );
}; };

@ -95,3 +95,21 @@ export const useGetFilteredPendingPointsCount = () => {
{ select: (data) => data.count, keepPreviousData: true } { select: (data) => data.count, keepPreviousData: true }
); );
}; };
export const useGetPermissions = () => {
return useQuery(["permissions"], async () => {
const { data } = await api.get("/api/me");
if (data?.groups?.includes("Редактор")) {
return "editor";
}
return "viewer";
});
};
export const useCanEdit = () => {
const { data } = useGetPermissions();
return data === "editor";
};

@ -9,7 +9,7 @@
.mapboxgl-popup-content, .mapboxgl-popup-content,
.maplibregl-popup-content { .maplibregl-popup-content {
@apply bg-grey-light shadow-lg rounded-md max-h-[300px] overflow-y-auto; @apply bg-grey-light shadow-lg rounded-md max-h-[500px] overflow-y-auto;
} }
.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip, .mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip,

@ -13,6 +13,7 @@ import {
import { usePendingPointsFilters } from "../../../stores/usePendingPointsFilters"; import { usePendingPointsFilters } from "../../../stores/usePendingPointsFilters";
import { ClearFiltersButton } from "../../../components/ClearFiltersButton"; import { ClearFiltersButton } from "../../../components/ClearFiltersButton";
import { getDynamicActiveFilters } from "../utils"; import { getDynamicActiveFilters } from "../utils";
import { useCanEdit } from "../../../api";
export const PendingPointsFilters = ({ fullRange }) => { export const PendingPointsFilters = ({ fullRange }) => {
const hasManualEdits = useHasManualEdits(); const hasManualEdits = useHasManualEdits();
@ -46,6 +47,8 @@ export const PendingPointsFilters = ({ fullRange }) => {
activeDynamicFilters.prediction || activeDynamicFilters.prediction ||
filters.categories.length !== 0; filters.categories.length !== 0;
const canEdit = useCanEdit();
return ( return (
<div className="flex flex-col flex-1 justify-between"> <div className="flex flex-col flex-1 justify-between">
<div> <div>
@ -83,7 +86,7 @@ export const PendingPointsFilters = ({ fullRange }) => {
<div> <div>
<SelectedLocations /> <SelectedLocations />
<TakeToWorkButton /> {canEdit && <TakeToWorkButton />}
</div> </div>
</div> </div>
); );

@ -28,8 +28,12 @@ export const MakeWorkingModal = ({ selectedIds, onClose, onSuccess }) => {
return await getPoints(params); return await getPoints(params);
}); });
const [hasError, setHasError] = useState(false);
const [dataSource, setDataSource] = useState([]); const [dataSource, setDataSource] = useState([]);
const [updateError, setUpdateError] = useState(null);
useEffect(() => { useEffect(() => {
setDataSource(data?.results); setDataSource(data?.results);
}, [data]); }, [data]);
@ -58,12 +62,19 @@ export const MakeWorkingModal = ({ selectedIds, onClose, onSuccess }) => {
const updateStatusPromise = updateStatus(updateStatusParams); const updateStatusPromise = updateStatus(updateStatusParams);
Promise.all([...updatePostamatPromises, updateStatusPromise]).then(() => { Promise.all([...updatePostamatPromises, updateStatusPromise])
queryClient.invalidateQueries(["on-approval-points"]); .then(() => {
setPopup(null); queryClient.invalidateQueries(["on-approval-points"]);
onSuccess(); setUpdateError(null);
onClose(); setPopup(null);
}); onSuccess();
onClose();
})
.catch(() =>
setUpdateError(
"Введенные идентификаторы уже существуют, попробуйте другие"
)
);
}; };
return ( return (
@ -73,13 +84,27 @@ export const MakeWorkingModal = ({ selectedIds, onClose, onSuccess }) => {
onCancel={onClose} onCancel={onClose}
width={800} width={800}
footer={[ footer={[
<Button key="ok-button" type="primary" onClick={handleUpdate}> updateError && (
<span key="error" className="mr-2 text-primary">
{updateError}
</span>
),
<Button
key="ok-button"
type="primary"
onClick={handleUpdate}
disabled={hasError}
>
Обновить статус Обновить статус
</Button>, </Button>,
]} ]}
> >
{dataSource && ( {dataSource && (
<MakeWorkingTable data={dataSource} onChange={setDataSource} /> <MakeWorkingTable
data={dataSource}
onChange={setDataSource}
setHasError={setHasError}
/>
)} )}
</Modal> </Modal>
); );

@ -24,6 +24,7 @@ const EditableCell = ({
dataIndex, dataIndex,
record, record,
handleSave, handleSave,
setHasError,
...restProps ...restProps
}) => { }) => {
const [editing, setEditing] = useState(false); const [editing, setEditing] = useState(false);
@ -47,6 +48,8 @@ const EditableCell = ({
try { try {
const values = await form.validateFields(); const values = await form.validateFields();
setHasError(false);
toggleEdit(); toggleEdit();
handleSave({ handleSave({
...record, ...record,
@ -54,6 +57,7 @@ const EditableCell = ({
}); });
} catch (errInfo) { } catch (errInfo) {
console.log("Save failed:", errInfo); console.log("Save failed:", errInfo);
setHasError(true);
} }
}; };
@ -98,7 +102,7 @@ const EditableCell = ({
return <td {...restProps}>{childNode}</td>; return <td {...restProps}>{childNode}</td>;
}; };
export const MakeWorkingTable = ({ data, onChange }) => { export const MakeWorkingTable = ({ data, onChange, setHasError }) => {
const handleSave = (row) => { const handleSave = (row) => {
const newData = [...data]; const newData = [...data];
const index = newData.findIndex((item) => row.id === item.id); const index = newData.findIndex((item) => row.id === item.id);
@ -130,6 +134,7 @@ export const MakeWorkingTable = ({ data, onChange }) => {
dataIndex: col.dataIndex, dataIndex: col.dataIndex,
title: col.title, title: col.title,
handleSave, handleSave,
setHasError,
}), }),
}; };
}); });

@ -7,7 +7,7 @@
cursor: pointer; cursor: pointer;
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
border-radius: 4px; border-radius: 4px;
min-height: 24px; min-height: 30px;
} }
.editable-row:hover .editable-cell-value-wrap { .editable-row:hover .editable-cell-value-wrap {

@ -1,7 +1,7 @@
import { Table } from "../Table"; import { Table } from "../Table";
import { columns } from "../columns"; import { columns } from "../columns";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { getPoints } from "../../../api"; import { getPoints, useCanEdit } 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";
@ -60,6 +60,8 @@ export const OnApprovalTable = ({ fullWidth }) => {
hideSelectAll: true, hideSelectAll: true,
}; };
const canEdit = useCanEdit();
return ( return (
<> <>
<Table <Table
@ -70,7 +72,7 @@ export const OnApprovalTable = ({ fullWidth }) => {
onOpenMakeWorkingModal={() => setIsMakeWorkingModalOpened(true)} onOpenMakeWorkingModal={() => setIsMakeWorkingModalOpened(true)}
/> />
} }
rowSelection={rowSelection} rowSelection={canEdit ? rowSelection : undefined}
data={mergedData} data={mergedData}
onPageChange={handlePageChange} onPageChange={handlePageChange}
page={page} page={page}

@ -6,6 +6,7 @@ import { usePendingTableData } from "./usePendingTableData";
import { columns } from "../columns"; import { columns } from "../columns";
import { HeaderWrapper } from "../HeaderWrapper"; import { HeaderWrapper } from "../HeaderWrapper";
import { useExportPendingData } from "./useExportPendingData"; import { useExportPendingData } from "./useExportPendingData";
import { useCanEdit } from "../../../api";
export const PendingTable = ({ fullWidth }) => { export const PendingTable = ({ fullWidth }) => {
const { selection, include, exclude } = usePointSelection(); const { selection, include, exclude } = usePointSelection();
@ -48,9 +49,11 @@ export const PendingTable = ({ fullWidth }) => {
const handlePageChange = useCallback((page) => setPage(page), []); const handlePageChange = useCallback((page) => setPage(page), []);
const canEdit = useCanEdit();
return ( return (
<Table <Table
rowSelection={rowSelection} rowSelection={canEdit ? rowSelection : undefined}
data={data} data={data}
onPageChange={handlePageChange} onPageChange={handlePageChange}
page={page} page={page}

@ -3,7 +3,7 @@ import { immer } from "zustand/middleware/immer";
import { MODES } from "../config"; import { MODES } from "../config";
const store = (set) => ({ const store = (set) => ({
mode: MODES.ON_APPROVAL, mode: MODES.PENDING,
setMode: (mode) => { setMode: (mode) => {
set((state) => { set((state) => {

Loading…
Cancel
Save