Files
WhiteNightsAdminPanel/src/pages/Station/StationEditPage/index.tsx
2025-11-20 20:17:52 +03:00

294 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Button,
Paper,
TextField,
Select,
MenuItem,
FormControl,
InputLabel,
Box,
} 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,
LoadingSpinner,
} 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 [isLoadingData, setIsLoadingData] = useState(true);
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) {
setIsLoadingData(false);
return;
}
setIsLoadingData(true);
try {
const stationId = Number(id);
await getEditStation(stationId);
await getCities("ru");
await getCities("en");
await getCities("zh");
} finally {
setIsLoadingData(false);
}
};
fetchAndSetStationData();
}, [id]);
if (isLoadingData) {
return (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
minHeight: "60vh",
}}
>
<LoadingSpinner message="Загрузка данных станции..." />
</Box>
);
}
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>
);
});