Latest version #12

Merged
Kerblif merged 46 commits from preview into master 2025-05-29 10:12:00 +00:00
8 changed files with 565 additions and 416 deletions
Showing only changes of commit db5e9d9fc4 - Show all commits

View File

@ -62,7 +62,6 @@ export const ArticleEditModal = observer(() => {
// Load existing media files when editing an article // Load existing media files when editing an article
const loadExistingMedia = async () => { const loadExistingMedia = async () => {
console.log("Called loadExistingMedia");
if (selectedArticleId) { if (selectedArticleId) {
try { try {
const response = await axiosInstance.get( const response = await axiosInstance.get(

View File

@ -50,8 +50,12 @@ const style = {
}; };
export const StationEditModal = observer(() => { export const StationEditModal = observer(() => {
const { stationModalOpen, setStationModalOpenAction, selectedStationId, selectedRouteId } = const {
stationStore; stationModalOpen,
setStationModalOpenAction,
selectedStationId,
selectedRouteId,
} = stationStore;
const { language } = languageStore; const { language } = languageStore;
useEffect(() => { useEffect(() => {
@ -63,10 +67,9 @@ export const StationEditModal = observer(() => {
const apiUrl = useApiUrl(); const apiUrl = useApiUrl();
const { data: stationQuery, isLoading: isStationLoading } = useCustom({ const { data: stationQuery, isLoading: isStationLoading } = useCustom({
url: `${apiUrl}/route/${selectedRouteId ?? 1}/station`, url: `${apiUrl}/route/${selectedRouteId ?? 1}/station`,
method: 'get' method: "get",
}); });
const { const {
register, register,
@ -84,7 +87,6 @@ export const StationEditModal = observer(() => {
id: "", id: "",
redirect: false, redirect: false,
onMutationSuccess: (data) => { onMutationSuccess: (data) => {
console.log(data);
setStationModalOpenAction(false); setStationModalOpenAction(false);
reset(); reset();
window.location.reload(); window.location.reload();
@ -99,14 +101,14 @@ export const StationEditModal = observer(() => {
useEffect(() => { useEffect(() => {
if (stationModalOpen) { if (stationModalOpen) {
const station = stationQuery?.data?.find((station: StationItem) => station.id === selectedStationId); const station = stationQuery?.data?.find(
if(!station) return; (station: StationItem) => station.id === selectedStationId
for(const key in station) { );
if (!station) return;
for (const key in station) {
setValue(key, station[key]); setValue(key, station[key]);
console.log(key, station[key]);
} }
setValue("station_id", station.id); setValue("station_id", station.id);
console.log(stationQuery);
} }
}, [stationModalOpen, stationQuery]); }, [stationModalOpen, stationQuery]);

View File

@ -4,94 +4,102 @@ import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
import { ModelViewer } from "./ModelViewer"; import { ModelViewer } from "./ModelViewer";
export interface MediaData { export interface MediaData {
id: string | number; id: string | number;
media_type: number; media_type: number;
filename?: string; filename?: string;
} }
export function MediaView({media} : Readonly<{media?: MediaData}>) { export function MediaView({ media }: Readonly<{ media?: MediaData }>) {
const token = localStorage.getItem(TOKEN_KEY); const token = localStorage.getItem(TOKEN_KEY);
return ( return (
<Box <Box
sx={{maxHeight: "300px", width: "100%", display: "flex", flexGrow: 1, justifyContent: "center"}} sx={{
> maxHeight: "300px",
{media?.media_type === 1 && ( width: "100%",
<img height: "100%",
src={`${import.meta.env.VITE_KRBL_MEDIA}${ maxWidth: "300px",
media?.id display: "flex",
}/download?token=${token}`} flexGrow: 1,
alt={media?.filename} justifyContent: "center",
style={{ }}
maxWidth: "100%", >
height: "auto", {media?.media_type === 1 && (
objectFit: "contain", <img
borderRadius: 8, src={`${import.meta.env.VITE_KRBL_MEDIA}${
}} media?.id
/> }/download?token=${token}`}
)} alt={media?.filename}
style={{
maxWidth: "100%",
height: "auto",
objectFit: "contain",
borderRadius: 8,
}}
/>
)}
{media?.media_type === 2 && ( {media?.media_type === 2 && (
<video <video
src={`${import.meta.env.VITE_KRBL_MEDIA}${ src={`${import.meta.env.VITE_KRBL_MEDIA}${
media?.id media?.id
}/download?token=${token}`} }/download?token=${token}`}
style={{ style={{
maxWidth: "100%", maxWidth: "100%",
height: "100%", height: "100%",
objectFit: "contain", objectFit: "contain",
borderRadius: 30, borderRadius: 30,
}} }}
controls controls
autoPlay autoPlay
muted muted
/> />
)} )}
{media?.media_type === 3 && ( {media?.media_type === 3 && (
<img <img
src={`${import.meta.env.VITE_KRBL_MEDIA}${ src={`${import.meta.env.VITE_KRBL_MEDIA}${
media?.id media?.id
}/download?token=${token}`} }/download?token=${token}`}
alt={media?.filename} alt={media?.filename}
style={{ style={{
maxWidth: "100%", maxWidth: "100%",
height: "100%", height: "100%",
objectFit: "contain", objectFit: "contain",
borderRadius: 8, borderRadius: 8,
}} }}
/> />
)} )}
{media?.media_type === 4 && ( {media?.media_type === 4 && (
<img <img
src={`${import.meta.env.VITE_KRBL_MEDIA}${ src={`${import.meta.env.VITE_KRBL_MEDIA}${
media?.id media?.id
}/download?token=${token}`} }/download?token=${token}`}
alt={media?.filename} alt={media?.filename}
style={{ style={{
maxWidth: "100%", maxWidth: "100%",
height: "100%", height: "100%",
objectFit: "contain", objectFit: "contain",
borderRadius: 8, borderRadius: 8,
}} }}
/> />
)} )}
{media?.media_type === 5 && ( {media?.media_type === 5 && (
<ReactPhotoSphereViewer <ReactPhotoSphereViewer
src={`${import.meta.env.VITE_KRBL_MEDIA}${ src={`${import.meta.env.VITE_KRBL_MEDIA}${
media?.id media?.id
}/download?token=${token}`} }/download?token=${token}`}
width={"100%"} width={"100%"}
height={"100%"} height={"100%"}
/> />
)} )}
{media?.media_type === 6 && ( {media?.media_type === 6 && (
<ModelViewer <ModelViewer
fileUrl={`${import.meta.env.VITE_KRBL_MEDIA}${ fileUrl={`${import.meta.env.VITE_KRBL_MEDIA}${
media?.id media?.id
}/download?token=${token}`} }/download?token=${token}`}
/> />
)} )}
</Box> </Box>
) );
} }

View File

@ -1,222 +1,271 @@
import { useCustom, useApiUrl } from "@refinedev/core"; import { useCustom, useApiUrl } from "@refinedev/core";
import { useParams } from "react-router"; import { useParams } from "react-router";
import { createContext, ReactNode, useContext, useEffect, useMemo, useState } from "react"; import {
import { RouteData, SightData, SightPatchData, StationData, StationPatchData } from "./types"; createContext,
ReactNode,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import {
RouteData,
SightData,
SightPatchData,
StationData,
StationPatchData,
} from "./types";
import { axiosInstance } from "../../providers/data"; import { axiosInstance } from "../../providers/data";
const MapDataContext = createContext<{ const MapDataContext = createContext<{
originalRouteData?: RouteData, originalRouteData?: RouteData;
originalStationData?: StationData[], originalStationData?: StationData[];
originalSightData?: SightData[], originalSightData?: SightData[];
routeData?: RouteData, routeData?: RouteData;
stationData?: StationData[], stationData?: StationData[];
sightData?: SightData[], sightData?: SightData[];
isRouteLoading: boolean, isRouteLoading: boolean;
isStationLoading: boolean, isStationLoading: boolean;
isSightLoading: boolean, isSightLoading: boolean;
setScaleRange: (min: number, max: number) => void, setScaleRange: (min: number, max: number) => void;
setMapRotation: (rotation: number) => void, setMapRotation: (rotation: number) => void;
setMapCenter: (x: number, y: number) => void, setMapCenter: (x: number, y: number) => void;
setStationOffset: (stationId: number, x: number, y: number) => void, setStationOffset: (stationId: number, x: number, y: number) => void;
setSightCoordinates: (sightId: number, latitude: number, longitude: number) => void, setSightCoordinates: (
saveChanges: () => void, sightId: number,
latitude: number,
longitude: number
) => void;
saveChanges: () => void;
}>({ }>({
originalRouteData: undefined, originalRouteData: undefined,
originalStationData: undefined, originalStationData: undefined,
originalSightData: undefined, originalSightData: undefined,
routeData: undefined, routeData: undefined,
stationData: undefined, stationData: undefined,
sightData: undefined, sightData: undefined,
isRouteLoading: true, isRouteLoading: true,
isStationLoading: true, isStationLoading: true,
isSightLoading: true, isSightLoading: true,
setScaleRange: () => {}, setScaleRange: () => {},
setMapRotation: () => {}, setMapRotation: () => {},
setMapCenter: () => {}, setMapCenter: () => {},
setStationOffset: () => {}, setStationOffset: () => {},
setSightCoordinates: () => {}, setSightCoordinates: () => {},
saveChanges: () => {}, saveChanges: () => {},
}); });
export function MapDataProvider({ children }: Readonly<{ children: ReactNode }>) { export function MapDataProvider({
const { id: routeId } = useParams<{ id: string }>(); children,
const apiUrl = useApiUrl(); }: Readonly<{ children: ReactNode }>) {
const { id: routeId } = useParams<{ id: string }>();
const apiUrl = useApiUrl();
const [originalRouteData, setOriginalRouteData] = useState<RouteData>(); const [originalRouteData, setOriginalRouteData] = useState<RouteData>();
const [originalStationData, setOriginalStationData] = useState<StationData[]>(); const [originalStationData, setOriginalStationData] =
const [originalSightData, setOriginalSightData] = useState<SightData[]>(); useState<StationData[]>();
const [originalSightData, setOriginalSightData] = useState<SightData[]>();
const [routeData, setRouteData] = useState<RouteData>(); const [routeData, setRouteData] = useState<RouteData>();
const [stationData, setStationData] = useState<StationData[]>(); const [stationData, setStationData] = useState<StationData[]>();
const [sightData, setSightData] = useState<SightData[]>(); const [sightData, setSightData] = useState<SightData[]>();
const [routeChanges, setRouteChanges] = useState<RouteData>({} as RouteData); const [routeChanges, setRouteChanges] = useState<RouteData>({} as RouteData);
const [stationChanges, setStationChanges] = useState<StationPatchData[]>([]); const [stationChanges, setStationChanges] = useState<StationPatchData[]>([]);
const [sightChanges, setSightChanges] = useState<SightPatchData[]>([]); const [sightChanges, setSightChanges] = useState<SightPatchData[]>([]);
const { data: routeQuery, isLoading: isRouteLoading } = useCustom({
url: `${apiUrl}/route/${routeId}`,
method: "get",
});
const { data: stationQuery, isLoading: isStationLoading } = useCustom({
url: `${apiUrl}/route/${routeId}/station`,
method: "get",
});
const { data: sightQuery, isLoading: isSightLoading } = useCustom({
url: `${apiUrl}/route/${routeId}/sight`,
method: "get",
});
useEffect(() => {
// if not undefined, set original data
if (routeQuery?.data) setOriginalRouteData(routeQuery.data as RouteData);
if (stationQuery?.data)
setOriginalStationData(stationQuery.data as StationData[]);
if (sightQuery?.data) setOriginalSightData(sightQuery.data as SightData[]);
console.log("queries", routeQuery, stationQuery, sightQuery);
}, [routeQuery, stationQuery, sightQuery]);
const { data: routeQuery, isLoading: isRouteLoading } = useCustom({ useEffect(() => {
url: `${apiUrl}/route/${routeId}`, // combine changes with original data
method: 'get', if (originalRouteData)
}); setRouteData({ ...originalRouteData, ...routeChanges });
const { data: stationQuery, isLoading: isStationLoading } = useCustom({ if (originalStationData) setStationData(originalStationData);
url: `${apiUrl}/route/${routeId}/station`, if (originalSightData) setSightData(originalSightData);
method: 'get' }, [
}); originalRouteData,
const { data: sightQuery, isLoading: isSightLoading } = useCustom({ originalStationData,
url: `${apiUrl}/route/${routeId}/sight`, originalSightData,
method: 'get', routeChanges,
}); stationChanges,
useEffect(() => { sightChanges,
// if not undefined, set original data ]);
if(routeQuery?.data) setOriginalRouteData(routeQuery.data as RouteData);
if(stationQuery?.data) setOriginalStationData(stationQuery.data as StationData[]);
if(sightQuery?.data) setOriginalSightData(sightQuery.data as SightData[]);
console.log("queries", routeQuery, stationQuery, sightQuery);
}, [routeQuery, stationQuery, sightQuery]);
useEffect(() => { function setScaleRange(min: number, max: number) {
// combine changes with original data setRouteChanges((prev) => {
if(originalRouteData) setRouteData({...originalRouteData, ...routeChanges}); return { ...prev, scale_min: min, scale_max: max };
if(originalStationData) setStationData(originalStationData); });
if(originalSightData) setSightData(originalSightData); }
}, [
originalRouteData, originalStationData, originalSightData,
routeChanges, stationChanges, sightChanges
]);
useEffect(() => { function setMapRotation(rotation: number) {
console.log("data", routeData, stationData, sightData); setRouteChanges((prev) => {
}, [routeData, stationData, sightData]); return { ...prev, rotate: rotation };
});
}
function setScaleRange(min: number, max: number) { function setMapCenter(x: number, y: number) {
setRouteChanges((prev) => { setRouteChanges((prev) => {
return {...prev, scale_min: min, scale_max: max}; return { ...prev, center_latitude: x, center_longitude: y };
}); });
} }
function setMapRotation(rotation: number) { async function saveChanges() {
setRouteChanges((prev) => { await axiosInstance.patch(`/route/${routeId}`, routeData);
return {...prev, rotate: rotation}; await saveStationChanges();
}); await saveSightChanges();
} }
function setMapCenter(x: number, y: number) { async function saveStationChanges() {
setRouteChanges((prev) => { for (const station of stationChanges) {
return {...prev, center_latitude: x, center_longitude: y} const response = await axiosInstance.patch(
}); `/route/${routeId}/station`,
} station
);
}
}
async function saveChanges() { async function saveSightChanges() {
await axiosInstance.patch(`/route/${routeId}`, routeData); console.log("sightChanges", sightChanges);
await saveStationChanges(); for (const sight of sightChanges) {
await saveSightChanges(); const response = await axiosInstance.patch(
} `/route/${routeId}/sight`,
sight
);
}
}
async function saveStationChanges() { function setStationOffset(stationId: number, x: number, y: number) {
for(const station of stationChanges) { setStationChanges((prev) => {
const response = await axiosInstance.patch(`/route/${routeId}/station`, station); let found = prev.find((station) => station.station_id === stationId);
console.log("response", response); if (found) {
} found.offset_x = x;
} found.offset_y = y;
async function saveSightChanges() { return prev.map((station) => {
console.log("sightChanges", sightChanges); if (station.station_id === stationId) {
for(const sight of sightChanges) { return found;
const response = await axiosInstance.patch(`/route/${routeId}/sight`, sight); }
console.log("response", response); return station;
} });
} } else {
const foundStation = stationData?.find(
(station) => station.id === stationId
);
if (foundStation) {
return [
...prev,
{
station_id: stationId,
offset_x: x,
offset_y: y,
transfers: foundStation.transfers,
},
];
}
return prev;
}
});
}
function setStationOffset(stationId: number, x: number, y: number) { function setSightCoordinates(
setStationChanges((prev) => { sightId: number,
let found = prev.find((station) => station.station_id === stationId); latitude: number,
if(found) { longitude: number
found.offset_x = x; ) {
found.offset_y = y; setSightChanges((prev) => {
let found = prev.find((sight) => sight.sight_id === sightId);
if (found) {
found.latitude = latitude;
found.longitude = longitude;
return prev.map((station) => { return prev.map((sight) => {
if(station.station_id === stationId) { if (sight.sight_id === sightId) {
return found; return found;
} }
return station; return sight;
}); });
} else { } else {
const foundStation = stationData?.find((station) => station.id === stationId); const foundSight = sightData?.find((sight) => sight.id === sightId);
if(foundStation) { if (foundSight) {
return [...prev, { return [
station_id: stationId, ...prev,
offset_x: x, offset_y: y, {
transfers: foundStation.transfers sight_id: sightId,
}]; latitude,
} longitude,
return prev; },
} ];
}); }
} return prev;
}
});
}
function setSightCoordinates(sightId: number, latitude: number, longitude: number) { useEffect(() => {
setSightChanges((prev) => { console.log("sightChanges", sightChanges);
let found = prev.find((sight) => sight.sight_id === sightId); }, [sightChanges]);
if(found) {
found.latitude = latitude;
found.longitude = longitude;
return prev.map((sight) => { const value = useMemo(
if(sight.sight_id === sightId) { () => ({
return found; originalRouteData: originalRouteData,
} originalStationData: originalStationData,
return sight; originalSightData: originalSightData,
}); routeData: routeData,
} else { stationData: stationData,
const foundSight = sightData?.find((sight) => sight.id === sightId); sightData: sightData,
if(foundSight) { isRouteLoading,
return [...prev, { isStationLoading,
sight_id: sightId, isSightLoading,
latitude, setScaleRange,
longitude setMapRotation,
}]; setMapCenter,
} saveChanges,
return prev; setStationOffset,
} setSightCoordinates,
}); }),
} [
originalRouteData,
originalStationData,
originalSightData,
routeData,
stationData,
sightData,
isRouteLoading,
isStationLoading,
isSightLoading,
]
);
useEffect(() => { return (
console.log("sightChanges", sightChanges); <MapDataContext.Provider value={value}>{children}</MapDataContext.Provider>
}, [sightChanges]); );
const value = useMemo(() => ({
originalRouteData: originalRouteData,
originalStationData: originalStationData,
originalSightData: originalSightData,
routeData: routeData,
stationData: stationData,
sightData: sightData,
isRouteLoading,
isStationLoading,
isSightLoading,
setScaleRange,
setMapRotation,
setMapCenter,
saveChanges,
setStationOffset,
setSightCoordinates
}), [originalRouteData, originalStationData, originalSightData, routeData, stationData, sightData, isRouteLoading, isStationLoading, isSightLoading]);
return (
<MapDataContext.Provider value={value}>
{children}
</MapDataContext.Provider>
);
} }
export const useMapData = () => { export const useMapData = () => {
const context = useContext(MapDataContext); const context = useContext(MapDataContext);
if (!context) { if (!context) {
throw new Error('useMapData must be used within a MapDataProvider'); throw new Error("useMapData must be used within a MapDataProvider");
} }
return context; return context;
}; };

View File

@ -277,14 +277,6 @@ export const RouteCreate = () => {
)} )}
/> />
<Typography
variant="caption"
color="textSecondary"
sx={{ mt: 0, mb: 1 }}
>
{routeDirection ? "Прямой" : "Обратный"}
</Typography>
<TextField <TextField
{...register("scale_min", { {...register("scale_min", {
// required: 'Это поле является обязательным', // required: 'Это поле является обязательным',

View File

@ -10,6 +10,7 @@ import {
} from "@mui/material"; } from "@mui/material";
import { Create, useAutocomplete } from "@refinedev/mui"; import { Create, useAutocomplete } from "@refinedev/mui";
import { useForm } from "@refinedev/react-hook-form"; import { useForm } from "@refinedev/react-hook-form";
import { useEffect, useState } from "react";
import { Controller } from "react-hook-form"; import { Controller } from "react-hook-form";
const TRANSFER_FIELDS = [ const TRANSFER_FIELDS = [
@ -29,14 +30,64 @@ export const StationCreate = () => {
saveButtonProps, saveButtonProps,
refineCore: { formLoading }, refineCore: { formLoading },
register, register,
setValue,
control, control,
getValues,
watch,
formState: { errors }, formState: { errors },
} = useForm({ } = useForm({
refineCoreProps: { refineCoreProps: {
resource: "station/", resource: "station",
}, },
}); });
const [coordinatesPreview, setCoordinatesPreview] = useState({
latitude: "",
longitude: "",
});
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const [lat, lon] = e.target.value.split(",").map((s) => s.trim());
setCoordinatesPreview({
latitude: lat,
longitude: lon,
});
setValue("latitude", lat);
setValue("longitude", lon);
};
const latitudeContent = watch("latitude");
const longitudeContent = watch("longitude");
useEffect(() => {
setCoordinatesPreview({
latitude: latitudeContent || "",
longitude: longitudeContent || "",
});
}, [latitudeContent, longitudeContent]);
useEffect(() => {
const latitude = getValues("latitude");
const longitude = getValues("longitude");
if (latitude && longitude) {
setCoordinatesPreview({
latitude: latitude,
longitude: longitude,
});
}
}, [getValues]);
const directions = [
{
label: "Прямой",
value: true,
},
{
label: "Обратный",
value: false,
},
];
const [routeDirection, setRouteDirection] = useState(false);
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({ const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
resource: "city", resource: "city",
onSearch: (value) => [ onSearch: (value) => [
@ -108,50 +159,68 @@ export const StationCreate = () => {
label={"Описание"} label={"Описание"}
name="description" name="description"
/> />
<Controller <input
name="direction" // boolean type="hidden"
control={control} {...register("direction", {
defaultValue={false} value: routeDirection,
render={({ field }: { field: any }) => ( })}
<FormControlLabel />
label="Прямой маршрут?"
control={ <Autocomplete
<Checkbox options={directions}
{...field} defaultValue={directions.find((el) => el.value == false)}
checked={field.value} onChange={(_, element) => {
onChange={(e) => field.onChange(e.target.checked)} if (element) {
/> setValue("direction", element.value);
} setRouteDirection(element.value);
}
}}
renderInput={(params) => (
<TextField
{...params}
label="Прямой/обратный маршрут"
margin="normal"
variant="outlined"
error={!!errors.arms}
helperText={(errors as any)?.arms?.message}
required
/> />
)} )}
/> />
<TextField <TextField
{...register("latitude", { value={`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
required: "Это поле является обязательным", onChange={handleCoordinatesChange}
valueAsNumber: true,
})}
error={!!(errors as any)?.latitude} error={!!(errors as any)?.latitude}
helperText={(errors as any)?.latitude?.message} helperText={(errors as any)?.latitude?.message}
margin="normal" margin="normal"
fullWidth fullWidth
InputLabelProps={{ shrink: true }} InputLabelProps={{ shrink: true }}
type="number" type="text"
label={"Широта *"} label={"Координаты *"}
name="latitude"
/> />
<TextField <input
{...register("longitude", { type="hidden"
required: "Это поле является обязательным", {...register("latitude", {
valueAsNumber: true, value: coordinatesPreview.latitude,
setValueAs: (value) => {
if (value === "") {
return 0;
}
return Number(value);
},
})}
/>
<input
type="hidden"
{...register("longitude", {
value: coordinatesPreview.longitude,
setValueAs: (value) => {
if (value === "") {
return 0;
}
return Number(value);
},
})} })}
error={!!(errors as any)?.longitude}
helperText={(errors as any)?.longitude?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Долгота *"}
name="longitude"
/> />
<Controller <Controller
@ -196,58 +265,70 @@ export const StationCreate = () => {
)} )}
/> />
<TextField <Box sx={{ visibility: "hidden" }}>
{...register("offset_x", { <TextField
// required: 'Это поле является обязательным', {...register("offset_x", {
})} // required: 'Это поле является обязательным',
error={!!(errors as any)?.offset_x} setValueAs: (value) => {
helperText={(errors as any)?.offset_x?.message} if (value === "") {
margin="normal" return 0;
fullWidth }
InputLabelProps={{ shrink: true }} },
type="number" })}
label={"Смещение (X)"} error={!!(errors as any)?.offset_x}
name="offset_x" helperText={(errors as any)?.offset_x?.message}
/> margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Смещение (X)"}
name="offset_x"
/>
<TextField <TextField
{...register("offset_y", { {...register("offset_y", {
// required: 'Это поле является обязательным', setValueAs: (value) => {
})} if (value === "") {
error={!!(errors as any)?.offset_y} return 0;
helperText={(errors as any)?.offset_y?.message} }
margin="normal" },
fullWidth // required: 'Это поле является обязательным',
InputLabelProps={{ shrink: true }} })}
type="number" error={!!(errors as any)?.offset_y}
label={"Смещение (Y)"} helperText={(errors as any)?.offset_y?.message}
name="offset_y" margin="normal"
/> fullWidth
InputLabelProps={{ shrink: true }}
{/* Группа полей пересадок */} type="number"
<Paper sx={{ p: 2, mt: 2 }}> label={"Смещение (Y)"}
<Typography variant="h6" gutterBottom> name="offset_y"
Пересадки />
</Typography> </Box>
<Grid container spacing={2}>
{TRANSFER_FIELDS.map((field) => (
<Grid item xs={12} sm={6} md={4} key={field.name}>
<TextField
{...register(`transfers.${field.name}`)}
error={!!(errors as any)?.transfers?.[field.name]}
helperText={(errors as any)?.transfers?.[field.name]?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label={field.label}
name={`transfers.${field.name}`}
/>
</Grid>
))}
</Grid>
</Paper>
</Box> </Box>
{/* Группа полей пересадок */}
<Paper hidden sx={{ p: 2, mt: 2 }}>
<Typography variant="h6" gutterBottom>
Пересадки
</Typography>
<Grid container spacing={2}>
{TRANSFER_FIELDS.map((field) => (
<Grid item xs={12} sm={6} md={4} key={field.name}>
<TextField
{...register(`transfers.${field.name}`)}
error={!!(errors as any)?.transfers?.[field.name]}
helperText={(errors as any)?.transfers?.[field.name]?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label={field.label}
name={`transfers.${field.name}`}
/>
</Grid>
))}
</Grid>
</Paper>
</Create> </Create>
); );
}; };

View File

@ -96,6 +96,26 @@ export const StationEdit = observer(() => {
}, },
}); });
const directions = [
{
label: "Прямой",
value: true,
},
{
label: "Обратный",
value: false,
},
];
const directionContent = watch("direction");
const [routeDirection, setRouteDirection] = useState(false);
useEffect(() => {
if (directionContent) {
setRouteDirection(directionContent);
}
}, [directionContent]);
useEffect(() => { useEffect(() => {
if (stationData[language as keyof typeof stationData]?.name) { if (stationData[language as keyof typeof stationData]?.name) {
setValue("name", stationData[language as keyof typeof stationData]?.name); setValue("name", stationData[language as keyof typeof stationData]?.name);
@ -172,17 +192,6 @@ export const StationEdit = observer(() => {
}, },
}); });
useEffect(() => {
const latitude = getValues("latitude");
const longitude = getValues("longitude");
if (latitude && longitude) {
setCoordinatesPreview({
latitude: latitude,
longitude: longitude,
});
}
}, [getValues]);
return ( return (
<Edit saveButtonProps={saveButtonProps}> <Edit saveButtonProps={saveButtonProps}>
<Box <Box
@ -217,20 +226,29 @@ export const StationEdit = observer(() => {
label={"Системное название *"} label={"Системное название *"}
name="system_name" name="system_name"
/> />
<Controller
name="direction" // boolean <input
control={control} type="hidden"
defaultValue={false} {...register("direction", { value: routeDirection })}
render={({ field }: { field: any }) => ( />
<FormControlLabel <Autocomplete
label="Прямой маршрут?" options={directions}
control={ value={directions.find((el) => el.value == routeDirection)}
<Checkbox onChange={(_, element) => {
{...field} if (element) {
checked={field.value} setValue("direction", element.value);
onChange={(e) => field.onChange(e.target.checked)} setRouteDirection(element.value);
/> }
} }}
renderInput={(params) => (
<TextField
{...params}
label="Прямой/обратный маршрут"
margin="normal"
variant="outlined"
error={!!errors.direction}
helperText={(errors as any)?.direction?.message}
required
/> />
)} )}
/> />

View File

@ -61,6 +61,7 @@ export const VehicleList = observer(() => {
type: "string", type: "string",
minWidth: 200, minWidth: 200,
display: "flex", display: "flex",
flex: 1,
align: "left", align: "left",
headerAlign: "left", headerAlign: "left",
renderCell: (params) => { renderCell: (params) => {
@ -70,14 +71,14 @@ export const VehicleList = observer(() => {
); );
}, },
}, },
{ // {
field: "city", // field: "city",
headerName: "Город", // headerName: "Город",
type: "string", // type: "string",
align: "left", // align: "left",
headerAlign: "left", // headerAlign: "left",
flex: 1, // flex: 1,
}, // },
{ {
field: "actions", field: "actions",
headerName: "Действия", headerName: "Действия",
@ -110,7 +111,6 @@ export const VehicleList = observer(() => {
<List> <List>
<CustomDataGrid <CustomDataGrid
{...dataGridProps} {...dataGridProps}
languageEnabled
columns={columns} columns={columns}
localeText={localeText} localeText={localeText}
getRowId={(row: any) => row.id} getRowId={(row: any) => row.id}