Compare commits
No commits in common. "190accc4a7064878bb0c467c08e69444ae0f5c9c" and "9701d3289dd1df47133b8a7612adb5b2269ffa8e" have entirely different histories.
190accc4a7
...
9701d3289d
4 changed files with 6 additions and 34 deletions
|
|
@ -42,7 +42,6 @@ const PRESET_ADDRESSES: { label: string; full: string; kind: string }[] = [
|
||||||
interface Props {
|
interface Props {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (val: string) => void;
|
onChange: (val: string) => void;
|
||||||
onPickCoords?: (coords: { lat: number; lon: number } | null) => void;
|
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
inputId?: string;
|
inputId?: string;
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +83,7 @@ function presetsToItems(): SuggestItem[] {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AddressInput({ value, onChange, onPickCoords, placeholder, inputId = "addr" }: Props) {
|
export function AddressInput({ value, onChange, placeholder, inputId = "addr" }: Props) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [items, setItems] = useState<SuggestItem[]>([]);
|
const [items, setItems] = useState<SuggestItem[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
@ -144,12 +143,6 @@ export function AddressInput({ value, onChange, onPickCoords, placeholder, input
|
||||||
function pick(item: SuggestItem) {
|
function pick(item: SuggestItem) {
|
||||||
lastPickedRef.current = item.full_address;
|
lastPickedRef.current = item.full_address;
|
||||||
onChange(item.full_address);
|
onChange(item.full_address);
|
||||||
const hasCoords =
|
|
||||||
Number.isFinite(item.lat) &&
|
|
||||||
Number.isFinite(item.lon) &&
|
|
||||||
item.lat !== 0 &&
|
|
||||||
item.lon !== 0;
|
|
||||||
onPickCoords?.(hasCoords ? { lat: item.lat, lon: item.lon } : null);
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setShowPresets(false);
|
setShowPresets(false);
|
||||||
setItems([]);
|
setItems([]);
|
||||||
|
|
@ -196,7 +189,6 @@ export function AddressInput({ value, onChange, onPickCoords, placeholder, input
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
lastPickedRef.current = ""; // юзер начал редактировать — снимаем guard
|
lastPickedRef.current = ""; // юзер начал редактировать — снимаем guard
|
||||||
onPickCoords?.(null); // ручное редактирование сбрасывает ранее выбранные coords
|
|
||||||
setShowPresets(false);
|
setShowPresets(false);
|
||||||
}}
|
}}
|
||||||
onFocus={() => {
|
onFocus={() => {
|
||||||
|
|
|
||||||
|
|
@ -73,10 +73,7 @@ function validate(f: FormState): string | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toPayload(
|
function toPayload(f: FormState): TradeInEstimateInput {
|
||||||
f: FormState,
|
|
||||||
coords: { lat: number; lon: number } | null,
|
|
||||||
): TradeInEstimateInput {
|
|
||||||
const out: TradeInEstimateInput = {
|
const out: TradeInEstimateInput = {
|
||||||
address: f.address.trim(),
|
address: f.address.trim(),
|
||||||
area_m2: Number(f.area_m2),
|
area_m2: Number(f.area_m2),
|
||||||
|
|
@ -85,10 +82,6 @@ function toPayload(
|
||||||
total_floors: f.total_floors !== "" ? Number(f.total_floors) : null,
|
total_floors: f.total_floors !== "" ? Number(f.total_floors) : null,
|
||||||
has_balcony: f.has_balcony,
|
has_balcony: f.has_balcony,
|
||||||
};
|
};
|
||||||
if (coords) {
|
|
||||||
out.lat = coords.lat;
|
|
||||||
out.lon = coords.lon;
|
|
||||||
}
|
|
||||||
if (f.year_built !== "") out.year_built = Number(f.year_built);
|
if (f.year_built !== "") out.year_built = Number(f.year_built);
|
||||||
const ht = asHouseType(f.house_type);
|
const ht = asHouseType(f.house_type);
|
||||||
if (ht) out.house_type = ht;
|
if (ht) out.house_type = ht;
|
||||||
|
|
@ -110,7 +103,6 @@ export function EstimateForm({
|
||||||
limit = null,
|
limit = null,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [form, setForm] = useState<FormState>(INITIAL);
|
const [form, setForm] = useState<FormState>(INITIAL);
|
||||||
const [coords, setCoords] = useState<{ lat: number; lon: number } | null>(null);
|
|
||||||
const [touched, setTouched] = useState(false);
|
const [touched, setTouched] = useState(false);
|
||||||
const [mapOpen, setMapOpen] = useState(false);
|
const [mapOpen, setMapOpen] = useState(false);
|
||||||
// CRM-блок свёрнут по умолчанию — экономит ~190px высоты, чтобы форма влезала
|
// CRM-блок свёрнут по умолчанию — экономит ~190px высоты, чтобы форма влезала
|
||||||
|
|
@ -132,7 +124,7 @@ export function EstimateForm({
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setTouched(true);
|
setTouched(true);
|
||||||
if (canSubmit) {
|
if (canSubmit) {
|
||||||
onSubmit(toPayload(form, coords));
|
onSubmit(toPayload(form));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,7 +154,6 @@ export function EstimateForm({
|
||||||
<AddressInput
|
<AddressInput
|
||||||
value={form.address}
|
value={form.address}
|
||||||
onChange={(val) => setForm((s) => ({ ...s, address: val }))}
|
onChange={(val) => setForm((s) => ({ ...s, address: val }))}
|
||||||
onPickCoords={setCoords}
|
|
||||||
placeholder="ул. Малышева, 30 · Куйбышева, 48…"
|
placeholder="ул. Малышева, 30 · Куйбышева, 48…"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -519,10 +510,7 @@ export function EstimateForm({
|
||||||
|
|
||||||
{mapOpen && (
|
{mapOpen && (
|
||||||
<MapPicker
|
<MapPicker
|
||||||
onPick={(addr, mapCoords) => {
|
onPick={(addr) => setForm((s) => ({ ...s, address: addr }))}
|
||||||
setForm((s) => ({ ...s, address: addr }));
|
|
||||||
setCoords(mapCoords ?? null);
|
|
||||||
}}
|
|
||||||
onClose={() => setMapOpen(false)}
|
onClose={() => setMapOpen(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ function loadLeaflet(): Promise<any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onPick: (address: string, coords?: { lat: number; lon: number }) => void;
|
onPick: (address: string) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,8 +99,6 @@ export function MapPicker({ onPick, onClose }: Props) {
|
||||||
// тонкий hint «Точка дома по Яндексу», чтобы user понимал почему marker
|
// тонкий hint «Точка дома по Яндексу», чтобы user понимал почему marker
|
||||||
// переехал на пару метров от его клика.
|
// переехал на пару метров от его клика.
|
||||||
const [snapped, setSnapped] = useState(false);
|
const [snapped, setSnapped] = useState(false);
|
||||||
// Координаты последнего выбора (snap-точка здания или raw клик).
|
|
||||||
const pickedCoordsRef = useRef<{ lat: number; lon: number } | null>(null);
|
|
||||||
// Portal-mount guard (SSR-safe): document доступен только после монтирования.
|
// Portal-mount guard (SSR-safe): document доступен только после монтирования.
|
||||||
// Рендерим оверлей в document.body, чтобы position:fixed/z-index:1000 не были
|
// Рендерим оверлей в document.body, чтобы position:fixed/z-index:1000 не были
|
||||||
// заперты в stacking-context формы (#771: полоски SourcesProgress наезжали).
|
// заперты в stacking-context формы (#771: полоски SourcesProgress наезжали).
|
||||||
|
|
@ -125,7 +123,6 @@ export function MapPicker({ onPick, onClose }: Props) {
|
||||||
map.on("click", (e: any) => {
|
map.on("click", (e: any) => {
|
||||||
const lat = e.latlng.lat as number;
|
const lat = e.latlng.lat as number;
|
||||||
const lon = e.latlng.lng as number;
|
const lon = e.latlng.lng as number;
|
||||||
pickedCoordsRef.current = { lat, lon }; // сохраняем raw click coords
|
|
||||||
if (marker) marker.setLatLng([lat, lon]);
|
if (marker) marker.setLatLng([lat, lon]);
|
||||||
else
|
else
|
||||||
marker = L.circleMarker([lat, lon], {
|
marker = L.circleMarker([lat, lon], {
|
||||||
|
|
@ -165,7 +162,6 @@ export function MapPicker({ onPick, onClose }: Props) {
|
||||||
animate: true,
|
animate: true,
|
||||||
duration: 0.3,
|
duration: 0.3,
|
||||||
});
|
});
|
||||||
pickedCoordsRef.current = { lat: d.snapped_lat, lon: d.snapped_lon };
|
|
||||||
setSnapped(true);
|
setSnapped(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -316,7 +312,7 @@ export function MapPicker({ onPick, onClose }: Props) {
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (address) {
|
if (address) {
|
||||||
onPick(address, pickedCoordsRef.current ?? undefined);
|
onPick(address);
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,6 @@ export interface TradeInEstimateInput {
|
||||||
has_mortgage?: boolean;
|
has_mortgage?: boolean;
|
||||||
client_name?: string;
|
client_name?: string;
|
||||||
client_phone?: string;
|
client_phone?: string;
|
||||||
// Координаты из автокомплита — позволяют бэкенду пропустить геокодинг
|
|
||||||
// для адресов, которые DaData/Yandex не резолвят по строке.
|
|
||||||
lat?: number | null;
|
|
||||||
lon?: number | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnalogLot {
|
export interface AnalogLot {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue