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
const loadExistingMedia = async () => {
console.log("Called loadExistingMedia");
if (selectedArticleId) {
try {
const response = await axiosInstance.get(

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@ import {
} from "@mui/material";
import { Create, useAutocomplete } from "@refinedev/mui";
import { useForm } from "@refinedev/react-hook-form";
import { useEffect, useState } from "react";
import { Controller } from "react-hook-form";
const TRANSFER_FIELDS = [
@ -29,14 +30,64 @@ export const StationCreate = () => {
saveButtonProps,
refineCore: { formLoading },
register,
setValue,
control,
getValues,
watch,
formState: { errors },
} = useForm({
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({
resource: "city",
onSearch: (value) => [
@ -108,50 +159,68 @@ export const StationCreate = () => {
label={"Описание"}
name="description"
/>
<Controller
name="direction" // boolean
control={control}
defaultValue={false}
render={({ field }: { field: any }) => (
<FormControlLabel
label="Прямой маршрут?"
control={
<Checkbox
{...field}
checked={field.value}
onChange={(e) => field.onChange(e.target.checked)}
/>
}
<input
type="hidden"
{...register("direction", {
value: routeDirection,
})}
/>
<Autocomplete
options={directions}
defaultValue={directions.find((el) => el.value == false)}
onChange={(_, element) => {
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
{...register("latitude", {
required: "Это поле является обязательным",
valueAsNumber: true,
})}
value={`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
onChange={handleCoordinatesChange}
error={!!(errors as any)?.latitude}
helperText={(errors as any)?.latitude?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Широта *"}
name="latitude"
type="text"
label={"Координаты *"}
/>
<TextField
{...register("longitude", {
required: "Это поле является обязательным",
valueAsNumber: true,
<input
type="hidden"
{...register("latitude", {
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
@ -196,58 +265,70 @@ export const StationCreate = () => {
)}
/>
<TextField
{...register("offset_x", {
// required: 'Это поле является обязательным',
})}
error={!!(errors as any)?.offset_x}
helperText={(errors as any)?.offset_x?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Смещение (X)"}
name="offset_x"
/>
<Box sx={{ visibility: "hidden" }}>
<TextField
{...register("offset_x", {
// required: 'Это поле является обязательным',
setValueAs: (value) => {
if (value === "") {
return 0;
}
},
})}
error={!!(errors as any)?.offset_x}
helperText={(errors as any)?.offset_x?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Смещение (X)"}
name="offset_x"
/>
<TextField
{...register("offset_y", {
// required: 'Это поле является обязательным',
})}
error={!!(errors as any)?.offset_y}
helperText={(errors as any)?.offset_y?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Смещение (Y)"}
name="offset_y"
/>
{/* Группа полей пересадок */}
<Paper 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>
<TextField
{...register("offset_y", {
setValueAs: (value) => {
if (value === "") {
return 0;
}
},
// required: 'Это поле является обязательным',
})}
error={!!(errors as any)?.offset_y}
helperText={(errors as any)?.offset_y?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="number"
label={"Смещение (Y)"}
name="offset_y"
/>
</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>
);
};

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(() => {
if (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 (
<Edit saveButtonProps={saveButtonProps}>
<Box
@ -217,20 +226,29 @@ export const StationEdit = observer(() => {
label={"Системное название *"}
name="system_name"
/>
<Controller
name="direction" // boolean
control={control}
defaultValue={false}
render={({ field }: { field: any }) => (
<FormControlLabel
label="Прямой маршрут?"
control={
<Checkbox
{...field}
checked={field.value}
onChange={(e) => field.onChange(e.target.checked)}
/>
}
<input
type="hidden"
{...register("direction", { value: routeDirection })}
/>
<Autocomplete
options={directions}
value={directions.find((el) => el.value == routeDirection)}
onChange={(_, element) => {
if (element) {
setValue("direction", element.value);
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",
minWidth: 200,
display: "flex",
flex: 1,
align: "left",
headerAlign: "left",
renderCell: (params) => {
@ -70,14 +71,14 @@ export const VehicleList = observer(() => {
);
},
},
{
field: "city",
headerName: "Город",
type: "string",
align: "left",
headerAlign: "left",
flex: 1,
},
// {
// field: "city",
// headerName: "Город",
// type: "string",
// align: "left",
// headerAlign: "left",
// flex: 1,
// },
{
field: "actions",
headerName: "Действия",
@ -110,7 +111,6 @@ export const VehicleList = observer(() => {
<List>
<CustomDataGrid
{...dataGridProps}
languageEnabled
columns={columns}
localeText={localeText}
getRowId={(row: any) => row.id}