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.
110 lines
2.8 KiB
110 lines
2.8 KiB
import { AutoComplete, Input } from "antd";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { SearchOutlined } from "@ant-design/icons";
|
|
import { api } from "../api";
|
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
import { useMap } from "react-map-gl";
|
|
import parse from "wellknown";
|
|
import { usePopup } from "../stores/usePopup.js";
|
|
import { useClickedPointConfig } from "../stores/useClickedPointConfig.js";
|
|
|
|
function useDebounce(value, delay) {
|
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => setDebouncedValue(value), delay || 500);
|
|
return () => {
|
|
clearTimeout(timer);
|
|
};
|
|
}, [value, delay]);
|
|
|
|
return debouncedValue;
|
|
}
|
|
|
|
const renderLabel = (address) => <div>{address}</div>;
|
|
|
|
export const AddressSearch = ({ autoFocus = false }) => {
|
|
const { map } = useMap();
|
|
const [value, setValue] = useState("");
|
|
const debouncedValue = useDebounce(value);
|
|
const { setPopup } = usePopup();
|
|
const { setClickedPointConfig } = useClickedPointConfig();
|
|
const inputRef = useRef();
|
|
|
|
const { data } = useQuery(
|
|
["address", debouncedValue],
|
|
async () => {
|
|
const result = await api.get(
|
|
`/api/placement_points/search_address?page_size=100&address=${debouncedValue}`
|
|
);
|
|
|
|
return result.data;
|
|
},
|
|
{ enabled: !!debouncedValue }
|
|
);
|
|
|
|
const options = useMemo(() => {
|
|
if (!data) return [];
|
|
|
|
return data.results.map((item) => ({
|
|
label: renderLabel(item.address),
|
|
value: `${item.address}$${item.id}`,
|
|
item: item,
|
|
}));
|
|
}, [data]);
|
|
|
|
const handleChange = (value) => {
|
|
if (!value) {
|
|
setValue(value);
|
|
} else {
|
|
setValue(value.split("$")[0]);
|
|
}
|
|
};
|
|
|
|
const handleSelect = (_value, option) => {
|
|
const geometry = parse(option.item.geometry);
|
|
map.flyTo({
|
|
center: [geometry.coordinates[0], geometry.coordinates[1]],
|
|
zoom: 13,
|
|
essential: true,
|
|
});
|
|
|
|
const feature = {
|
|
properties: option.item,
|
|
};
|
|
|
|
setPopup({ features: [feature], coordinates: geometry.coordinates });
|
|
setClickedPointConfig(feature.properties.id);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (autoFocus && inputRef?.current) {
|
|
inputRef.current.focus();
|
|
}
|
|
}, [autoFocus]);
|
|
|
|
return (
|
|
<div>
|
|
<AutoComplete
|
|
options={options}
|
|
style={{
|
|
width: 300,
|
|
}}
|
|
value={value}
|
|
onChange={handleChange}
|
|
onSelect={handleSelect}
|
|
allowClear={true}
|
|
onClear={() => setValue("")}
|
|
autoFocus={autoFocus}
|
|
popupClassName={"overflow-visible"}
|
|
>
|
|
<Input
|
|
prefix={<SearchOutlined />}
|
|
placeholder="Введите адрес точки"
|
|
className="text-ellipsis"
|
|
ref={inputRef}
|
|
/>
|
|
</AutoComplete>
|
|
</div>
|
|
);
|
|
};
|