From db5e9d9fc454207e97ae6b0c07280cfdeda7ac5a Mon Sep 17 00:00:00 2001 From: itoshi Date: Sun, 25 May 2025 23:16:33 +0300 Subject: [PATCH] fix: Fix station create page --- .../modals/ArticleEditModal/index.tsx | 1 - .../modals/StationEditModal/index.tsx | 26 +- src/components/ui/MediaView.tsx | 180 ++++---- src/pages/route-preview/MapDataContext.tsx | 431 ++++++++++-------- src/pages/route/create.tsx | 8 - src/pages/station/create.tsx | 249 ++++++---- src/pages/station/edit.tsx | 68 ++- src/pages/vehicle/list.tsx | 18 +- 8 files changed, 565 insertions(+), 416 deletions(-) diff --git a/src/components/modals/ArticleEditModal/index.tsx b/src/components/modals/ArticleEditModal/index.tsx index 2e213e0..170035f 100644 --- a/src/components/modals/ArticleEditModal/index.tsx +++ b/src/components/modals/ArticleEditModal/index.tsx @@ -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( diff --git a/src/components/modals/StationEditModal/index.tsx b/src/components/modals/StationEditModal/index.tsx index 4a1c74c..aa295ff 100644 --- a/src/components/modals/StationEditModal/index.tsx +++ b/src/components/modals/StationEditModal/index.tsx @@ -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]); diff --git a/src/components/ui/MediaView.tsx b/src/components/ui/MediaView.tsx index 74bab3c..b717e09 100644 --- a/src/components/ui/MediaView.tsx +++ b/src/components/ui/MediaView.tsx @@ -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 ( - - {media?.media_type === 1 && ( - {media?.filename} - )} +export function MediaView({ media }: Readonly<{ media?: MediaData }>) { + const token = localStorage.getItem(TOKEN_KEY); + return ( + + {media?.media_type === 1 && ( + {media?.filename} + )} - {media?.media_type === 2 && ( - - ) -} \ No newline at end of file + {media?.media_type === 6 && ( + + )} + + ); +} diff --git a/src/pages/route-preview/MapDataContext.tsx b/src/pages/route-preview/MapDataContext.tsx index 78ed1c8..23aa2c3 100644 --- a/src/pages/route-preview/MapDataContext.tsx +++ b/src/pages/route-preview/MapDataContext.tsx @@ -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(); - const [originalStationData, setOriginalStationData] = useState(); - const [originalSightData, setOriginalSightData] = useState(); + const [originalRouteData, setOriginalRouteData] = useState(); + const [originalStationData, setOriginalStationData] = + useState(); + const [originalSightData, setOriginalSightData] = useState(); - const [routeData, setRouteData] = useState(); - const [stationData, setStationData] = useState(); - const [sightData, setSightData] = useState(); + const [routeData, setRouteData] = useState(); + const [stationData, setStationData] = useState(); + const [sightData, setSightData] = useState(); - const [routeChanges, setRouteChanges] = useState({} as RouteData); - const [stationChanges, setStationChanges] = useState([]); - const [sightChanges, setSightChanges] = useState([]); - + const [routeChanges, setRouteChanges] = useState({} as RouteData); + const [stationChanges, setStationChanges] = useState([]); + const [sightChanges, setSightChanges] = useState([]); - 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 ( - - {children} - - ); + return ( + {children} + ); } export const useMapData = () => { - const context = useContext(MapDataContext); - if (!context) { - throw new Error('useMapData must be used within a MapDataProvider'); - } - return context; -}; \ No newline at end of file + const context = useContext(MapDataContext); + if (!context) { + throw new Error("useMapData must be used within a MapDataProvider"); + } + return context; +}; diff --git a/src/pages/route/create.tsx b/src/pages/route/create.tsx index 7d6d190..2a95c98 100644 --- a/src/pages/route/create.tsx +++ b/src/pages/route/create.tsx @@ -277,14 +277,6 @@ export const RouteCreate = () => { )} /> - - {routeDirection ? "Прямой" : "Обратный"} - - { 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) => { + 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" /> - ( - field.onChange(e.target.checked)} - /> - } + + + el.value == false)} + onChange={(_, element) => { + if (element) { + setValue("direction", element.value); + setRouteDirection(element.value); + } + }} + renderInput={(params) => ( + )} /> - { + if (value === "") { + return 0; + } + return Number(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" /> { )} /> - + + { + 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" + /> - - - {/* Группа полей пересадок */} - - - Пересадки - - - {TRANSFER_FIELDS.map((field) => ( - - - - ))} - - + { + 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" + /> + + + {/* Группа полей пересадок */} + ); }; diff --git a/src/pages/station/edit.tsx b/src/pages/station/edit.tsx index cd9933d..2eaa4f7 100644 --- a/src/pages/station/edit.tsx +++ b/src/pages/station/edit.tsx @@ -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 ( { label={"Системное название *"} name="system_name" /> - ( - field.onChange(e.target.checked)} - /> - } + + + el.value == routeDirection)} + onChange={(_, element) => { + if (element) { + setValue("direction", element.value); + setRouteDirection(element.value); + } + }} + renderInput={(params) => ( + )} /> diff --git a/src/pages/vehicle/list.tsx b/src/pages/vehicle/list.tsx index b3e3722..9a7a11c 100644 --- a/src/pages/vehicle/list.tsx +++ b/src/pages/vehicle/list.tsx @@ -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(() => { row.id}