264 lines
7.4 KiB
TypeScript
264 lines
7.4 KiB
TypeScript
import {
|
||
Button,
|
||
Paper,
|
||
TextField,
|
||
Select,
|
||
MenuItem,
|
||
FormControl,
|
||
InputLabel,
|
||
} from "@mui/material";
|
||
import { observer } from "mobx-react-lite";
|
||
import { ArrowLeft, Save } from "lucide-react";
|
||
import { Loader2 } from "lucide-react";
|
||
import { useNavigate, useParams } from "react-router-dom";
|
||
import { toast } from "react-toastify";
|
||
import { stationsStore, languageStore, cityStore } from "@shared";
|
||
import { useEffect, useState } from "react";
|
||
import { LanguageSwitcher } from "@widgets";
|
||
import { LinkedSights } from "../LinkedSights";
|
||
import { SaveWithoutCityAgree } from "@widgets";
|
||
|
||
export const StationEditPage = observer(() => {
|
||
const navigate = useNavigate();
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const { language } = languageStore;
|
||
const { id } = useParams();
|
||
const {
|
||
editStationData,
|
||
getEditStation,
|
||
setEditCommonData,
|
||
editStation,
|
||
setLanguageEditStationData,
|
||
} = stationsStore;
|
||
const { cities, getCities } = cityStore;
|
||
const [coordinates, setCoordinates] = useState<string>("");
|
||
|
||
const [isSaveWarningOpen, setIsSaveWarningOpen] = useState(false);
|
||
|
||
useEffect(() => {
|
||
languageStore.setLanguage("ru");
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (
|
||
editStationData.common.latitude !== 0 ||
|
||
editStationData.common.longitude !== 0
|
||
) {
|
||
setCoordinates(
|
||
`${editStationData.common.latitude}, ${editStationData.common.longitude}`
|
||
);
|
||
}
|
||
}, [editStationData.common.latitude, editStationData.common.longitude]);
|
||
|
||
const executeEdit = async () => {
|
||
try {
|
||
setIsLoading(true);
|
||
await editStation(Number(id));
|
||
toast.success("Остановка успешно обновлена");
|
||
} catch (error) {
|
||
console.error("Error updating station:", error);
|
||
toast.error("Ошибка при обновлении станции");
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleEdit = async () => {
|
||
const isCityMissing = !editStationData.common.city_id;
|
||
|
||
const isNameMissing =
|
||
!editStationData.ru.name ||
|
||
!editStationData.en.name ||
|
||
!editStationData.zh.name;
|
||
|
||
if (isCityMissing || isNameMissing) {
|
||
setIsSaveWarningOpen(true);
|
||
return;
|
||
}
|
||
|
||
await executeEdit();
|
||
};
|
||
|
||
const handleConfirmEdit = async () => {
|
||
setIsSaveWarningOpen(false);
|
||
await executeEdit();
|
||
};
|
||
|
||
const handleCancelEdit = () => {
|
||
setIsSaveWarningOpen(false);
|
||
};
|
||
|
||
useEffect(() => {
|
||
const fetchAndSetStationData = async () => {
|
||
if (!id) return;
|
||
|
||
const stationId = Number(id);
|
||
await getEditStation(stationId);
|
||
await getCities("ru");
|
||
await getCities("en");
|
||
await getCities("zh");
|
||
};
|
||
|
||
fetchAndSetStationData();
|
||
}, [id]);
|
||
|
||
return (
|
||
<Paper className="w-full h-full p-3 flex flex-col gap-10">
|
||
<LanguageSwitcher />
|
||
|
||
<div className="flex items-center gap-4">
|
||
<button
|
||
className="flex items-center gap-2"
|
||
onClick={() => navigate(-1)}
|
||
>
|
||
<ArrowLeft size={20} />
|
||
Назад
|
||
</button>
|
||
</div>
|
||
|
||
<div className="flex flex-col gap-10 w-full items-end">
|
||
<div className="flex gap-10 items-center mb-5 max-w-[80%] self-start">
|
||
<h1 className="text-3xl break-words">{editStationData.ru.name}</h1>
|
||
</div>
|
||
<TextField
|
||
fullWidth
|
||
label="Название"
|
||
value={editStationData[language].name || ""}
|
||
required
|
||
onChange={(e) =>
|
||
setLanguageEditStationData(language, {
|
||
name: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
|
||
<FormControl fullWidth>
|
||
<InputLabel id="direction-label">Прямой/обратный маршрут</InputLabel>
|
||
<Select
|
||
labelId="direction-label"
|
||
value={editStationData.common.direction ? "Прямой" : "Обратный"}
|
||
label="Прямой/обратный маршрут"
|
||
onChange={(e) =>
|
||
setEditCommonData({
|
||
direction: e.target.value === "Прямой",
|
||
})
|
||
}
|
||
>
|
||
<MenuItem value="Прямой">Прямой</MenuItem>
|
||
<MenuItem value="Обратный">Обратный</MenuItem>
|
||
</Select>
|
||
</FormControl>
|
||
|
||
<TextField
|
||
fullWidth
|
||
label="Описание"
|
||
value={editStationData.common.description || ""}
|
||
onChange={(e) =>
|
||
setEditCommonData({
|
||
description: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
|
||
{/* <TextField
|
||
fullWidth
|
||
label="Адрес"
|
||
value={editStationData[language].address || ""}
|
||
onChange={(e) =>
|
||
setLanguageEditStationData(language, {
|
||
address: e.target.value,
|
||
})
|
||
}
|
||
/> */}
|
||
|
||
<TextField
|
||
fullWidth
|
||
label="Координаты"
|
||
value={coordinates}
|
||
onChange={(e) => {
|
||
const newValue = e.target.value;
|
||
setCoordinates(newValue);
|
||
|
||
const input = newValue.replace(/,/g, " ").trim();
|
||
const [latStr, lonStr] = input.split(/\s+/);
|
||
|
||
const lat = parseFloat(latStr);
|
||
const lon = parseFloat(lonStr);
|
||
|
||
const isValidLat = !isNaN(lat);
|
||
const isValidLon = !isNaN(lon);
|
||
|
||
if (isValidLat && isValidLon) {
|
||
setEditCommonData({
|
||
latitude: lat,
|
||
longitude: lon,
|
||
});
|
||
} else {
|
||
setEditCommonData({
|
||
latitude: 0,
|
||
longitude: 0,
|
||
});
|
||
}
|
||
}}
|
||
placeholder="Введите координаты в формате: широта долгота (можно использовать запятые или пробелы)"
|
||
/>
|
||
|
||
<FormControl fullWidth>
|
||
<InputLabel>Город</InputLabel>
|
||
<Select
|
||
value={editStationData.common.city_id || ""}
|
||
label="Город"
|
||
onChange={(e) => {
|
||
const selectedCity = cities["ru"].data.find(
|
||
(city) => city.id === e.target.value
|
||
);
|
||
setEditCommonData({
|
||
city_id: e.target.value as number,
|
||
city: selectedCity?.name || "",
|
||
});
|
||
}}
|
||
>
|
||
{cities["ru"].data.map((city) => (
|
||
<MenuItem key={city.id} value={city.id}>
|
||
{city.name}
|
||
</MenuItem>
|
||
))}
|
||
</Select>
|
||
</FormControl>
|
||
|
||
{id && (
|
||
<LinkedSights
|
||
parentId={Number(id)}
|
||
fields={[{ label: "Название", data: "name" }]}
|
||
type="edit"
|
||
/>
|
||
)}
|
||
|
||
<Button
|
||
variant="contained"
|
||
className="w-min flex gap-2 items-center"
|
||
startIcon={<Save size={20} />}
|
||
onClick={handleEdit}
|
||
disabled={isLoading}
|
||
>
|
||
{isLoading ? (
|
||
<Loader2 size={20} className="animate-spin" />
|
||
) : (
|
||
"Сохранить"
|
||
)}
|
||
</Button>
|
||
</div>
|
||
|
||
{/* ИНТЕГРИРОВАННОЕ ПРЕДУПРЕЖДАЮЩЕЕ ОКНО */}
|
||
{isSaveWarningOpen && (
|
||
<SaveWithoutCityAgree
|
||
blocker={{
|
||
proceed: handleConfirmEdit,
|
||
reset: handleCancelEdit,
|
||
}}
|
||
/>
|
||
)}
|
||
</Paper>
|
||
);
|
||
});
|