You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
9.3 KiB

import axios from "axios";
import { useMutation, useQuery } from "@tanstack/react-query";
import { STATUSES } from "./config";
import { usePointSelection } from "./stores/usePointSelection";
import { RANGE_FILTERS_KEYS, usePendingPointsFilters } from "./stores/usePendingPointsFilters";
import { appendFiltersInUse } from "./utils.js";
import { useMode } from "./stores/useMode.js";
import { useMemo } from "react";
import { useUpdateLayerCounter } from "./stores/useUpdateLayerCounter.js";
import { keycloak } from "./keycloak.js";
import { useKeycloak } from "@react-keycloak/web";
export const BASE_URL = import.meta.env.VITE_API_URL;
export const api = axios.create({
baseURL:
import.meta.env.MODE === "development"
? "http://localhost:5173/"
: BASE_URL,
});
api.interceptors.request.use(async function (config) {
const token = keycloak.token;
if (token) {
config.headers.Authorization = `Bearer ${ token }`;
}
return config;
});
export const useDbTableName = () => {
const {isImportMode} = useMode();
if (isImportMode) return "pre_placement_points";
return "placement_points";
}
export const useSourceLayerName = () => {
const {isImportMode} = useMode();
if (isImportMode) return "public.prepoints_with_dist";
return "public.points_with_dist";
}
const enrichParamsWithRegionFilter = (params, region) => {
const resultParams = params ? params : new URLSearchParams();
if (region) {
if (region.type === "ao") {
resultParams.append("district[]", region.id);
}
if (region.type === "rayon") {
resultParams.append("area[]", region.id);
}
}
return resultParams;
};
export const getPoints = async (params, region, dbTable = "placement_points", signal) => {
const resultParams = enrichParamsWithRegionFilter(params, region);
const { data } = await api.get(
`/api/${dbTable}/?${resultParams.toString()}`, {signal}
);
return data;
};
export const exportPoints = async (params, region, dbTable = "placement_points") => {
const resultParams = enrichParamsWithRegionFilter(params, region);
const { data } = await api.get(
`/api/${dbTable}/to_excel/?${resultParams.toString()}`,
{ responseType: "arraybuffer" }
);
return data;
};
export const downloadImportTemplate = async () => {
const { data } = await api.get(
'/api/pre_placement_points/download_template/',
{ responseType: "arraybuffer" }
);
return data;
};
export const uploadPointsFile = async (file, config) => {
const formData = new FormData();
formData.append("file", file);
const { data } = await api.post(
`/api/pre_placement_points/load_matching_file/`,
formData,
config
);
return data;
};
export const importPoints = async (id) => {
const formData = new FormData();
formData.append("id", id);
const { data } = await api.post(
`/api/pre_placement_points/start_matching/`,
formData
);
return data;
};
export const getImportStatus = async () => {
const { data } = await api.get(
`/api/pre_placement_points/import_status/`
);
return data;
};
export const useGetTotalInitialPointsCount = () => {
const dbTable = useDbTableName();
const { updateCounter } = useUpdateLayerCounter();
return useQuery(
["all-initial-count", dbTable, updateCounter],
async ({signal}) => {
const params = new URLSearchParams({
page: 1,
page_size: 1,
});
params.append("status[]", [STATUSES.pending, STATUSES.cancelled]);
return await getPoints(params, null, dbTable, signal);
},
{
select: (data) => data.count,
refetchOnWindowFocus: false
}
);
};
export const useGetFilteredPendingPointsCount = (isMerge) => {
const { filters, ranges } = usePendingPointsFilters();
const { updateCounter } = useUpdateLayerCounter();
const {
categories,
region,
} = filters;
const {
selection: { included },
} = usePointSelection();
const includedIds = [...included];
const getParams = () => {
const params = new URLSearchParams({
page: 1,
page_size: 1,
"categories[]": categories,
"included[]": includedIds,
});
params.append("status[]", STATUSES.pending);
appendFiltersInUse(params, filters, ranges);
return params;
}
const getMergeParams = () => {
return new URLSearchParams({
"matching_status": "New",
});
}
const dbTable = useDbTableName();
return useQuery(
["filtered-points", filters, dbTable, includedIds, updateCounter],
async ({signal}) => {
const params = isMerge ? getMergeParams() : getParams();
return await getPoints(params, region, dbTable, signal);
},
{
select: (data) => data.count,
keepPreviousData: true,
refetchOnWindowFocus: false
}
);
};
export const useGetPointsToMergeCount = () => {
const getMergeParams = () => {
return new URLSearchParams({
"matching_status": "New",
});
}
const dbTable = useDbTableName();
return useQuery(
["filtered-points", dbTable],
async () => {
const params = getMergeParams();
return await getPoints(params, null, dbTable);
},
{ select: (data) => data.count, keepPreviousData: true }
);
};
export const useMergePointsToDb = () => {
return useMutation({
mutationFn: () => {
return api.post(
`/api/pre_placement_points/move_points/`
);
},
});
};
export const useGetPermissions = () => {
const {setImportMode} = useMode();
return useQuery(["permissions"], async () => {
const { data } = await api.get("/api/me/");
if (data?.groups?.includes("postnet_editor")) {
return "editor";
}
setImportMode(false);
return "viewer";
});
};
const TASK_STATUSES = {
finished: "Перерасчет ML завершен"
}
export const useCanEdit = () => {
const { keycloak } = useKeycloak();
const { data: statusData } = useLastMLRun();
const hasFinishedUpdate = useMemo(() => {
return statusData?.task_status === TASK_STATUSES.finished
}, [statusData]);
return keycloak.hasResourceRole("postnet_editor", "postnet") && hasFinishedUpdate;
};
export const useUpdatePostamatId = () => {
return useMutation({
mutationFn: (params) => {
return api.put(
`/api/placement_points/update_postamat_id/?${params.toString()}`
);
},
});
};
export const getLastMLRun = async () => {
const { data } = await api.get(
`/api/placement_points/last_time_ml_run/`
);
return data;
};
export const startML = async () => {
const { data } = await api.get(
`/api/placement_points/start/`
);
return data;
};
export const getPostamatesAndPvzGroups = async () => {
const { data } = await api.get(
`/api/postamate_and_pvz_groups/`
);
return data;
};
export const usePostamatesAndPvzGroups = () => {
return useQuery(
['groups'],
async () => {
return await getPostamatesAndPvzGroups();
},
);
};
export const getOtherGroups = async () => {
const { data } = await api.get(
`/api/other_object_groups/`
);
return data;
};
export const useOtherGroups = () => {
return useQuery(
['other_groups'],
async () => {
return await getOtherGroups();
},
);
};
export const useLastMLRun = () => {
return useQuery(
['last_time'],
async () => {
return await getLastMLRun();
},
{
refetchInterval: 5000,
}
);
}
export const useGetPendingPointsRange = (dbTable) => {
const { isImportMode } = useMode();
const statusFilter = isImportMode ? '' : `?status[]=${STATUSES.pending}`;
return useQuery(
["prediction-max-min", dbTable],
async () => {
const { data, isInitialLoading, isFetching } = await api.get(
`/api/${dbTable}/filters/${statusFilter}`
);
return {data, isLoading: isInitialLoading || isFetching};
},
{
select: ({data, isLoading}) => {
const distToGroupsArr = data.dist_to_groups.map((groupRange) => {
return {
[`d${groupRange.group_id}`]: [Math.floor(groupRange.dist[0]), Math.min(Math.ceil(groupRange.dist[1]), 4000)],
}
});
const distToGroups = Object.assign({}, ...distToGroupsArr);
const rangesArr = RANGE_FILTERS_KEYS.map((key) => {
if ((/d[0-9]/.test(key))) return;
return {
[key]: [Math.floor(data[key][0]), Math.ceil(data[key][1])]
}
}).filter(item => !!item);
const ranges = Object.assign({}, ...rangesArr);
return {
fullRange: {
prediction: data.prediction_current,
...ranges,
...distToGroups
},
isLoading: isLoading
};
},
}
);
};
export const useGetPopupPoints = (features) => {
const pointsIds = features.map(f => f.properties.id);
const dbTable = useDbTableName();
const { data, isInitialLoading, isFetching } = useQuery(
["popup_data", features],
async () => {
const params = new URLSearchParams({
"location_ids[]": pointsIds,
});
const { data } = await api.get(
`/api/${dbTable}/?${params.toString()}`
);
return data.results;
},
{
refetchOnWindowFocus: false,
refetchOnMount: false
}
);
return { data, isLoading: isInitialLoading || isFetching };
};
export const deletePoint = async (id) => {
const formData = new FormData();
formData.append("ids", id);
await api.delete(
`/api/pre_placement_points/delete_points/`,
{ data: formData }
)
}