Compare commits
2 Commits
d758dbffa6
...
193f53c029
| Author | SHA1 | Date | |
|---|---|---|---|
| 193f53c029 | |||
| 4bda233b63 |
14
.env
14
.env
@@ -1,8 +1,8 @@
|
|||||||
# VITE_API_URL='https://wn.st.unprism.ru'
|
VITE_API_URL='https://wn.st.unprism.ru'
|
||||||
# VITE_REACT_APP ='https://wn.st.unprism.ru/'
|
VITE_REACT_APP ='https://wn.st.unprism.ru/'
|
||||||
# VITE_KRBL_MEDIA='https://wn.st.unprism.ru/media/'
|
VITE_KRBL_MEDIA='https://wn.st.unprism.ru/media/'
|
||||||
# VITE_NEED_AUTH='true'
|
|
||||||
VITE_API_URL='https://wn.krbl.ru'
|
|
||||||
VITE_REACT_APP ='https://wn.krbl.ru/'
|
|
||||||
VITE_KRBL_MEDIA='https://wn.krbl.ru/media/'
|
|
||||||
VITE_NEED_AUTH='true'
|
VITE_NEED_AUTH='true'
|
||||||
|
# VITE_API_URL='https://wn.krbl.ru'
|
||||||
|
# VITE_REACT_APP ='https://wn.krbl.ru/'
|
||||||
|
# VITE_KRBL_MEDIA='https://wn.krbl.ru/media/'
|
||||||
|
# VITE_NEED_AUTH='true'
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const SightFrame = observer(({ media, sight_id, sight_name }) => {
|
|||||||
|
|
||||||
const textWrapperRef = useRef(null);
|
const textWrapperRef = useRef(null);
|
||||||
|
|
||||||
// Автозакрытие fullscreen 3D при бездействии (45 сек)
|
// Автозакрытие fullscreen 3D при бездействии (60 сек)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isFullscreen3D) {
|
if (!isFullscreen3D) {
|
||||||
if (idleTimerRef.current) {
|
if (idleTimerRef.current) {
|
||||||
@@ -61,7 +61,7 @@ const SightFrame = observer(({ media, sight_id, sight_name }) => {
|
|||||||
|
|
||||||
const checkIdle = () => {
|
const checkIdle = () => {
|
||||||
idleSeconds += 1;
|
idleSeconds += 1;
|
||||||
if (idleSeconds >= 45) {
|
if (idleSeconds >= 60) {
|
||||||
setIsFullscreen3D(false);
|
setIsFullscreen3D(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -264,15 +264,20 @@ const SideMenu = observer(({ onMenuToggle }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isMenuOpenRef = useRef(isMenuOpen);
|
||||||
|
const handleMenuToggleRef = useRef(handleMenuToggle);
|
||||||
|
useEffect(() => { isMenuOpenRef.current = isMenuOpen; }, [isMenuOpen]);
|
||||||
|
useEffect(() => { handleMenuToggleRef.current = handleMenuToggle; });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Автоматическое закрытие сайд-меню после 45 секунд бездействия
|
// Автоматическое закрытие сайд-меню после 60 секунд бездействия
|
||||||
let idleSeconds = 0;
|
let idleSeconds = 0;
|
||||||
|
|
||||||
const checkIdle = () => {
|
const checkIdle = () => {
|
||||||
idleSeconds += 1;
|
idleSeconds += 1;
|
||||||
|
|
||||||
if (idleSeconds >= 45 && isMenuOpen) {
|
if (idleSeconds >= 60 && isMenuOpenRef.current) {
|
||||||
handleMenuToggle(false);
|
handleMenuToggleRef.current(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,7 +306,7 @@ const SideMenu = observer(({ onMenuToggle }) => {
|
|||||||
window.removeEventListener(event, resetIdle);
|
window.removeEventListener(event, resetIdle);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}, [isMenuOpen, handleMenuToggle]);
|
}, []);
|
||||||
|
|
||||||
// Закрываем и открываем список достопримечательностей при изменении сортировки
|
// Закрываем и открываем список достопримечательностей при изменении сортировки
|
||||||
const prevSortingByRef = useRef(sortingBy);
|
const prevSortingByRef = useRef(sortingBy);
|
||||||
|
|||||||
@@ -26,15 +26,17 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.3) inset,
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(255, 255, 255, 0.3) inset,
|
||||||
/* Внутренняя рамка */ 4px 4px 12px 0 rgba(255, 255, 255, 0.12) inset; /* Ваш существующий внутренний shadow */
|
/* Внутренняя рамка */ 4px 4px 12px 0 rgba(255, 255, 255, 0.12) inset; /* Ваш существующий внутренний shadow */
|
||||||
padding: 1px; /* Чтобы контент не прилипал к рамке */
|
padding: 1px; /* Чтобы контент не прилипал к рамке */
|
||||||
background: linear-gradient(
|
background:
|
||||||
|
linear-gradient(
|
||||||
to bottom right,
|
to bottom right,
|
||||||
rgba(255, 255, 255, 0.2) 0%,
|
rgba(255, 255, 255, 0.2) 0%,
|
||||||
rgba(255, 255, 255, 0) 100%
|
rgba(255, 255, 255, 0) 100%
|
||||||
),
|
),
|
||||||
rgba(var(--carrier-main-rgb, 0, 111, 58), 0.4);
|
rgba(179, 165, 152, 0.4);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
z-index: 10000001;
|
z-index: 10000001;
|
||||||
@@ -50,7 +52,8 @@
|
|||||||
height: 96px;
|
height: 96px;
|
||||||
background-color: #fcd500;
|
background-color: #fcd500;
|
||||||
color: black;
|
color: black;
|
||||||
border-radius: 10px;
|
border-top-left-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const ArticleListPage = observer(() => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
fetchArticles();
|
fetchArticles();
|
||||||
}, [language]);
|
}, [language, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
|
import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
|
||||||
import { ruRU } from "@mui/x-data-grid/locales";
|
import { ruRU } from "@mui/x-data-grid/locales";
|
||||||
import { authStore, carrierStore, cityStore, languageStore, SearchInput } from "@shared";
|
import { authStore, carrierStore, cityStore, languageStore, selectedCityStore, SearchInput } from "@shared";
|
||||||
import { useEffect, useState, useMemo } from "react";
|
import { useEffect, useState, useMemo } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Pencil, Trash2, Minus } from "lucide-react";
|
import { Pencil, Trash2, Minus } from "lucide-react";
|
||||||
@@ -39,7 +39,7 @@ export const CarrierListPage = observer(() => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [language]);
|
}, [language, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
@@ -169,6 +169,11 @@ export const CarrierListPage = observer(() => {
|
|||||||
checkboxSelection={canWriteCarriers}
|
checkboxSelection={canWriteCarriers}
|
||||||
disableRowSelectionExcludeModel
|
disableRowSelectionExcludeModel
|
||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
|
onRowDoubleClick={(params) => {
|
||||||
|
if (canWriteCarriers) {
|
||||||
|
navigate(`/carrier/${params.id}/edit`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
paginationModel={paginationModel}
|
paginationModel={paginationModel}
|
||||||
onPaginationModelChange={setPaginationModel}
|
onPaginationModelChange={setPaginationModel}
|
||||||
|
|||||||
@@ -172,6 +172,11 @@ export const CityListPage = observer(() => {
|
|||||||
checkboxSelection={canWriteCities}
|
checkboxSelection={canWriteCities}
|
||||||
disableRowSelectionExcludeModel
|
disableRowSelectionExcludeModel
|
||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
|
onRowDoubleClick={(params) => {
|
||||||
|
if (canWriteCities) {
|
||||||
|
navigate(`/city/${params.id}/edit`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
paginationModel={paginationModel}
|
paginationModel={paginationModel}
|
||||||
onPaginationModelChange={setPaginationModel}
|
onPaginationModelChange={setPaginationModel}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
} from "@widgets";
|
} from "@widgets";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { runInAction } from "mobx";
|
||||||
|
|
||||||
function a11yProps(index: number) {
|
function a11yProps(index: number) {
|
||||||
return {
|
return {
|
||||||
@@ -36,6 +37,16 @@ export const CreateSightPage = observer(() => {
|
|||||||
return () => selectedCityStore.setIsLocked(false);
|
return () => selectedCityStore.setIsLocked(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { selectedCityId, selectedCity } = selectedCityStore;
|
||||||
|
if (selectedCityId && selectedCity && !createSightStore.sight.city_id) {
|
||||||
|
runInAction(() => {
|
||||||
|
createSightStore.sight.city_id = selectedCityId;
|
||||||
|
createSightStore.sight.city = selectedCity.name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleChange = (_: React.SyntheticEvent, newValue: number) => {
|
const handleChange = (_: React.SyntheticEvent, newValue: number) => {
|
||||||
setValue(newValue);
|
setValue(newValue);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const RouteListPage = observer(() => {
|
|||||||
loadCounts(routeIds);
|
loadCounts(routeIds);
|
||||||
};
|
};
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [language]);
|
}, [language, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchCarrierData() {
|
async function fetchCarrierData() {
|
||||||
if (routeData?.carrier_id) {
|
if (routeData?.carrier_id) {
|
||||||
const carrier = (await authInstance.get(`/carrier/${routeData.carrier_id}`)).data;
|
const carrier = (
|
||||||
|
await authInstance.get(`/carrier/${routeData.carrier_id}`)
|
||||||
|
).data;
|
||||||
setCarrierLogo(carrier.logo);
|
setCarrierLogo(carrier.logo);
|
||||||
setCarrierSlogan(carrier.slogan ?? null);
|
setCarrierSlogan(carrier.slogan ?? null);
|
||||||
setCarrierShortName(carrier.short_name ?? null);
|
setCarrierShortName(carrier.short_name ?? null);
|
||||||
@@ -45,6 +47,7 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
width: 288,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
}}
|
}}
|
||||||
@@ -165,7 +168,11 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
{carrierLogo && !isMediaIdEmpty(carrierLogo) && (
|
{carrierLogo && !isMediaIdEmpty(carrierLogo) && (
|
||||||
<div style={{ width: 170 }}>
|
<div style={{ width: 170 }}>
|
||||||
<MediaViewer
|
<MediaViewer
|
||||||
media={{ id: carrierLogo, media_type: 1, filename: "carrier_logo" }}
|
media={{
|
||||||
|
id: carrierLogo,
|
||||||
|
media_type: 1,
|
||||||
|
filename: "carrier_logo",
|
||||||
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -190,7 +197,12 @@ export const LeftSidebar = observer(({ open, onToggle }: LeftSidebarProps) => {
|
|||||||
<img
|
<img
|
||||||
src="/side-menu-photo.png"
|
src="/side-menu-photo.png"
|
||||||
alt=""
|
alt=""
|
||||||
style={{ width: "100%", marginTop: 32, display: "block", pointerEvents: "none" }}
|
style={{
|
||||||
|
width: "288px",
|
||||||
|
marginTop: 32,
|
||||||
|
display: "block",
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -448,6 +448,22 @@ const StationLabel = observer(
|
|||||||
anchor={dynamicAnchor}
|
anchor={dynamicAnchor}
|
||||||
zIndex={isHovered || isControlHovered ? 1000 : 0}
|
zIndex={isHovered || isControlHovered ? 1000 : 0}
|
||||||
>
|
>
|
||||||
|
{ruLabelWidth > 0 && (
|
||||||
|
<pixiGraphics
|
||||||
|
draw={(g: Graphics) => {
|
||||||
|
g.clear();
|
||||||
|
const hasSecondLabel = !!(station.name && language !== "ru" && ruLabel);
|
||||||
|
const pad = 10 / scale;
|
||||||
|
const w = ruLabelWidth + pad * 2;
|
||||||
|
const top = -compensatedRuFontSize / 2 - pad;
|
||||||
|
const bottom = hasSecondLabel
|
||||||
|
? compensatedRuFontSize * 1.1 + compensatedNameFontSize / 2 + pad
|
||||||
|
: compensatedRuFontSize / 2 + pad;
|
||||||
|
g.rect(-w / 2, top, w, bottom - top);
|
||||||
|
g.fill({ color: 0x000000, alpha: 0.001 });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{ruLabel && (
|
{ruLabel && (
|
||||||
<pixiText
|
<pixiText
|
||||||
ref={ruLabelRef}
|
ref={ruLabelRef}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const RoutePreview = () => {
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: isLeftSidebarOpen ? 300 : 0,
|
width: isLeftSidebarOpen ? 288 : 0,
|
||||||
transition: "width 0.3s ease",
|
transition: "width 0.3s ease",
|
||||||
overflow: "visible",
|
overflow: "visible",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
@@ -145,14 +145,14 @@ export const RouteMap = observer(() => {
|
|||||||
) {
|
) {
|
||||||
const coordinates = coordinatesToLocal(
|
const coordinates = coordinatesToLocal(
|
||||||
originalRouteData?.center_latitude,
|
originalRouteData?.center_latitude,
|
||||||
originalRouteData?.center_longitude
|
originalRouteData?.center_longitude,
|
||||||
);
|
);
|
||||||
|
|
||||||
setTransform(
|
setTransform(
|
||||||
coordinates.x,
|
coordinates.x,
|
||||||
coordinates.y,
|
coordinates.y,
|
||||||
originalRouteData?.rotate,
|
originalRouteData?.rotate,
|
||||||
originalRouteData?.scale_min
|
originalRouteData?.scale_min,
|
||||||
);
|
);
|
||||||
setIsSetup(true);
|
setIsSetup(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,17 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.3) inset,
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(255, 255, 255, 0.3) inset,
|
||||||
/* Внутренняя рамка */ 4px 4px 12px 0 rgba(255, 255, 255, 0.12) inset; /* Ваш существующий внутренний shadow */
|
/* Внутренняя рамка */ 4px 4px 12px 0 rgba(255, 255, 255, 0.12) inset; /* Ваш существующий внутренний shadow */
|
||||||
padding: 1px; /* Чтобы контент не прилипал к рамке */
|
padding: 1px; /* Чтобы контент не прилипал к рамке */
|
||||||
background: linear-gradient(
|
background:
|
||||||
|
linear-gradient(
|
||||||
to bottom right,
|
to bottom right,
|
||||||
rgba(255, 255, 255, 0.2) 0%,
|
rgba(255, 255, 255, 0.2) 0%,
|
||||||
rgba(255, 255, 255, 0) 100%
|
rgba(255, 255, 255, 0) 100%
|
||||||
),
|
),
|
||||||
rgba(var(--carrier-main-rgb, 0, 111, 58), 0.4);
|
rgba(179, 165, 152, 0.4);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
z-index: 10000001;
|
z-index: 10000001;
|
||||||
@@ -50,7 +52,8 @@
|
|||||||
height: 96px;
|
height: 96px;
|
||||||
background-color: #fcd500;
|
background-color: #fcd500;
|
||||||
color: black;
|
color: black;
|
||||||
border-radius: 10px;
|
border-top-left-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -2405,12 +2405,6 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
resizingStationIconId === station.id;
|
resizingStationIconId === station.id;
|
||||||
|
|
||||||
const secondaryLineHeight = 1.2;
|
const secondaryLineHeight = 1.2;
|
||||||
const secondaryHeight = showSecondary
|
|
||||||
? secondaryFontSize * secondaryLineHeight
|
|
||||||
: 0;
|
|
||||||
const menuPaddingTop = showSecondary
|
|
||||||
? Math.max(0, secondaryHeight - secondaryMarginTop) + 3
|
|
||||||
: 3;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={station.id}>
|
<div key={station.id}>
|
||||||
@@ -2440,22 +2434,25 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
color: "#fff",
|
color: "#fff",
|
||||||
fontFamily: "Roboto, sans-serif",
|
fontFamily: "Roboto, sans-serif",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
pointerEvents: "auto",
|
pointerEvents: "none",
|
||||||
cursor: "grab",
|
cursor: "grab",
|
||||||
userSelect: "none",
|
userSelect: "none",
|
||||||
touchAction: "none",
|
touchAction: "none",
|
||||||
|
lineHeight: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
pointerEvents: "auto",
|
display: "inline-block",
|
||||||
|
pointerEvents: "none",
|
||||||
transformOrigin: "left center",
|
transformOrigin: "left center",
|
||||||
transform: `rotate(${rotationCss})`,
|
transform: `rotate(${rotationCss})`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
pointerEvents: "auto",
|
display: "inline-block",
|
||||||
|
pointerEvents: "none",
|
||||||
transformOrigin: "left center",
|
transformOrigin: "left center",
|
||||||
transform: `rotate(${counterRotationCss})`,
|
transform: `rotate(${counterRotationCss})`,
|
||||||
}}
|
}}
|
||||||
@@ -2549,34 +2546,36 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
) : null}
|
) : null}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
position: "relative",
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: primaryFontSize,
|
fontSize: primaryFontSize,
|
||||||
|
lineHeight: 1,
|
||||||
textShadow: "0 0 4px rgba(0,0,0,0.6)",
|
textShadow: "0 0 4px rgba(0,0,0,0.6)",
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{station.name}
|
{station.name}
|
||||||
|
{showSecondary ? (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "100%",
|
||||||
|
marginTop: -1 * secondaryMarginTop,
|
||||||
|
fontWeight: 400,
|
||||||
|
fontSize: secondaryFontSize,
|
||||||
|
lineHeight: secondaryLineHeight,
|
||||||
|
color: "#CBCBCB",
|
||||||
|
textShadow: "0 0 3px rgba(0,0,0,0.4)",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
...secondaryPositionStyle,
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{secondaryStation?.name}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{showSecondary ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
top: "100%",
|
|
||||||
marginTop: -1 * secondaryMarginTop,
|
|
||||||
fontWeight: 400,
|
|
||||||
fontSize: secondaryFontSize,
|
|
||||||
lineHeight: secondaryLineHeight,
|
|
||||||
color: "#CBCBCB",
|
|
||||||
textShadow: "0 0 3px rgba(0,0,0,0.4)",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
...secondaryPositionStyle,
|
|
||||||
pointerEvents: "none",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{secondaryStation?.name}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2587,9 +2586,9 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
top: "100%",
|
top: "100%",
|
||||||
left: "50%",
|
left: "50%",
|
||||||
transform: "translateX(-50%)",
|
transform: "translateX(-50%)",
|
||||||
paddingTop: menuPaddingTop,
|
paddingTop: "8px",
|
||||||
pointerEvents: "auto",
|
pointerEvents: "auto",
|
||||||
zIndex: 10,
|
zIndex: 1000000,
|
||||||
cursor: "default",
|
cursor: "default",
|
||||||
}}
|
}}
|
||||||
onPointerDown={(e) => e.stopPropagation()}
|
onPointerDown={(e) => e.stopPropagation()}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export const SightListPage = observer(() => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
fetchSights();
|
fetchSights();
|
||||||
}, [language]);
|
}, [language, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const StationListPage = observer(() => {
|
|||||||
loadSightCounts(stationIds);
|
loadSightCounts(stationIds);
|
||||||
};
|
};
|
||||||
fetchStations();
|
fetchStations();
|
||||||
}, [language]);
|
}, [language, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import {
|
|||||||
VEHICLE_TYPES,
|
VEHICLE_TYPES,
|
||||||
carrierStore,
|
carrierStore,
|
||||||
languageStore,
|
languageStore,
|
||||||
|
cityStore,
|
||||||
|
selectedCityStore,
|
||||||
} from "@shared";
|
} from "@shared";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { ArrowLeft, Save } from "lucide-react";
|
import { ArrowLeft, Save } from "lucide-react";
|
||||||
@@ -26,11 +28,13 @@ export const VehicleCreatePage = observer(() => {
|
|||||||
const [type, setType] = useState("");
|
const [type, setType] = useState("");
|
||||||
const [carrierId, setCarrierId] = useState<number | null>(null);
|
const [carrierId, setCarrierId] = useState<number | null>(null);
|
||||||
const [model, setModel] = useState("");
|
const [model, setModel] = useState("");
|
||||||
|
const [cityId, setCityId] = useState<number | null>(selectedCityStore.selectedCityId);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { language } = languageStore;
|
const { language } = languageStore;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
carrierStore.getCarriers(language);
|
carrierStore.getCarriers(language);
|
||||||
|
cityStore.getCities("ru");
|
||||||
}, [language]);
|
}, [language]);
|
||||||
|
|
||||||
const handleCreate = async () => {
|
const handleCreate = async () => {
|
||||||
@@ -43,6 +47,7 @@ export const VehicleCreatePage = observer(() => {
|
|||||||
?.full_name as string,
|
?.full_name as string,
|
||||||
carrierId!,
|
carrierId!,
|
||||||
model || undefined,
|
model || undefined,
|
||||||
|
cityId ?? undefined,
|
||||||
);
|
);
|
||||||
toast.success("Транспорт успешно создан");
|
toast.success("Транспорт успешно создан");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -73,12 +78,11 @@ export const VehicleCreatePage = observer(() => {
|
|||||||
onChange={(e) => setTailNumber(e.target.value)}
|
onChange={(e) => setTailNumber(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth required>
|
||||||
<InputLabel>Тип</InputLabel>
|
<InputLabel>Тип</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={type}
|
value={type}
|
||||||
label="Тип"
|
label="Тип"
|
||||||
required
|
|
||||||
onChange={(e) => setType(e.target.value)}
|
onChange={(e) => setType(e.target.value)}
|
||||||
>
|
>
|
||||||
{VEHICLE_TYPES.map((type) => (
|
{VEHICLE_TYPES.map((type) => (
|
||||||
@@ -89,12 +93,11 @@ export const VehicleCreatePage = observer(() => {
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth required>
|
||||||
<InputLabel>Перевозчик</InputLabel>
|
<InputLabel>Перевозчик</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={carrierId || ""}
|
value={carrierId || ""}
|
||||||
label="Перевозчик"
|
label="Перевозчик"
|
||||||
required
|
|
||||||
onChange={(e) => setCarrierId(e.target.value as number)}
|
onChange={(e) => setCarrierId(e.target.value as number)}
|
||||||
>
|
>
|
||||||
{carrierStore.carriers[language].data?.map((carrier) => (
|
{carrierStore.carriers[language].data?.map((carrier) => (
|
||||||
@@ -113,12 +116,27 @@ export const VehicleCreatePage = observer(() => {
|
|||||||
placeholder="Произвольное название модели"
|
placeholder="Произвольное название модели"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormControl fullWidth required>
|
||||||
|
<InputLabel>Город</InputLabel>
|
||||||
|
<Select
|
||||||
|
value={cityId ?? ""}
|
||||||
|
label="Город"
|
||||||
|
onChange={(e) => setCityId(e.target.value ? Number(e.target.value) : null)}
|
||||||
|
>
|
||||||
|
{cityStore.cities.ru.data.map((city) => (
|
||||||
|
<MenuItem key={city.id} value={city.id}>
|
||||||
|
{city.name}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
className="w-min flex gap-2 items-center"
|
className="w-min flex gap-2 items-center"
|
||||||
startIcon={<Save size={20} />}
|
startIcon={<Save size={20} />}
|
||||||
onClick={handleCreate}
|
onClick={handleCreate}
|
||||||
disabled={isLoading || !tailNumber || !type || !carrierId}
|
disabled={isLoading || !tailNumber || !type || !carrierId || !cityId}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Loader2 size={20} className="animate-spin" />
|
<Loader2 size={20} className="animate-spin" />
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import {
|
|||||||
VEHICLE_TYPES,
|
VEHICLE_TYPES,
|
||||||
vehicleStore,
|
vehicleStore,
|
||||||
LoadingSpinner,
|
LoadingSpinner,
|
||||||
|
cityStore,
|
||||||
|
selectedCityStore,
|
||||||
} from "@shared";
|
} from "@shared";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ export const VehicleEditPage = observer(() => {
|
|||||||
try {
|
try {
|
||||||
await getVehicle(Number(id));
|
await getVehicle(Number(id));
|
||||||
await getCarriers(language);
|
await getCarriers(language);
|
||||||
|
await cityStore.getCities("ru");
|
||||||
|
|
||||||
setEditVehicleData({
|
setEditVehicleData({
|
||||||
tail_number: vehicle[Number(id)]?.vehicle.tail_number ?? "",
|
tail_number: vehicle[Number(id)]?.vehicle.tail_number ?? "",
|
||||||
@@ -63,6 +66,7 @@ export const VehicleEditPage = observer(() => {
|
|||||||
model: vehicle[Number(id)]?.vehicle.model ?? "",
|
model: vehicle[Number(id)]?.vehicle.model ?? "",
|
||||||
snapshot_update_blocked:
|
snapshot_update_blocked:
|
||||||
vehicle[Number(id)]?.vehicle.snapshot_update_blocked ?? false,
|
vehicle[Number(id)]?.vehicle.snapshot_update_blocked ?? false,
|
||||||
|
city_id: vehicle[Number(id)]?.vehicle.city_id ?? selectedCityStore.selectedCityId ?? undefined,
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingData(false);
|
setIsLoadingData(false);
|
||||||
@@ -125,12 +129,11 @@ export const VehicleEditPage = observer(() => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth required>
|
||||||
<InputLabel>Тип</InputLabel>
|
<InputLabel>Тип</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={editVehicleData.type}
|
value={editVehicleData.type}
|
||||||
label="Тип"
|
label="Тип"
|
||||||
required
|
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setEditVehicleData({ ...editVehicleData, type: e.target.value })
|
setEditVehicleData({ ...editVehicleData, type: e.target.value })
|
||||||
}
|
}
|
||||||
@@ -143,12 +146,11 @@ export const VehicleEditPage = observer(() => {
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth required>
|
||||||
<InputLabel>Перевозчик</InputLabel>
|
<InputLabel>Перевозчик</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={editVehicleData.carrier_id}
|
value={editVehicleData.carrier_id}
|
||||||
label="Перевозчик"
|
label="Перевозчик"
|
||||||
required
|
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setEditVehicleData({
|
setEditVehicleData({
|
||||||
...editVehicleData,
|
...editVehicleData,
|
||||||
@@ -177,6 +179,26 @@ export const VehicleEditPage = observer(() => {
|
|||||||
placeholder="Произвольное название модели"
|
placeholder="Произвольное название модели"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormControl fullWidth required>
|
||||||
|
<InputLabel>Город</InputLabel>
|
||||||
|
<Select
|
||||||
|
value={editVehicleData.city_id ?? ""}
|
||||||
|
label="Город"
|
||||||
|
onChange={(e) =>
|
||||||
|
setEditVehicleData({
|
||||||
|
...editVehicleData,
|
||||||
|
city_id: e.target.value ? Number(e.target.value) : undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{cityStore.cities.ru.data.map((city) => (
|
||||||
|
<MenuItem key={city.id} value={city.id}>
|
||||||
|
{city.name}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@@ -202,7 +224,8 @@ export const VehicleEditPage = observer(() => {
|
|||||||
isLoading ||
|
isLoading ||
|
||||||
!editVehicleData.tail_number ||
|
!editVehicleData.tail_number ||
|
||||||
!editVehicleData.type ||
|
!editVehicleData.type ||
|
||||||
!editVehicleData.carrier_id
|
!editVehicleData.carrier_id ||
|
||||||
|
!editVehicleData.city_id
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
|
import { DataGrid, GridColDef, GridRenderCellParams } from "@mui/x-data-grid";
|
||||||
import { ruRU } from "@mui/x-data-grid/locales";
|
import { ruRU } from "@mui/x-data-grid/locales";
|
||||||
import { authStore, carrierStore, languageStore, vehicleStore, SearchInput } from "@shared";
|
import { authStore, carrierStore, languageStore, vehicleStore, SearchInput, selectedCityStore, cityStore } from "@shared";
|
||||||
import { useEffect, useState, useMemo } from "react";
|
import { useEffect, useState, useMemo } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Eye, Pencil, Trash2, Minus } from "lucide-react";
|
import { Eye, Pencil, Trash2, Minus } from "lucide-react";
|
||||||
@@ -11,7 +11,7 @@ import { Box, CircularProgress } from "@mui/material";
|
|||||||
|
|
||||||
export const VehicleListPage = observer(() => {
|
export const VehicleListPage = observer(() => {
|
||||||
const { vehicles, getVehicles, deleteVehicle } = vehicleStore;
|
const { vehicles, getVehicles, deleteVehicle } = vehicleStore;
|
||||||
const { carriers, getCarriers } = carrierStore;
|
const { getCarriers } = carrierStore;
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||||
const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false);
|
const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false);
|
||||||
@@ -31,10 +31,11 @@ export const VehicleListPage = observer(() => {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await getVehicles();
|
await getVehicles();
|
||||||
await getCarriers(language);
|
await getCarriers(language);
|
||||||
|
await cityStore.getCities("ru");
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [language]);
|
}, [language, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
const columns: GridColDef[] = [
|
const columns: GridColDef[] = [
|
||||||
{
|
{
|
||||||
@@ -137,9 +138,13 @@ export const VehicleListPage = observer(() => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const { selectedCityId } = selectedCityStore;
|
||||||
|
|
||||||
const rows = useMemo(() => {
|
const rows = useMemo(() => {
|
||||||
|
if (!selectedCityId) return [];
|
||||||
const query = searchQuery.trim().toLowerCase();
|
const query = searchQuery.trim().toLowerCase();
|
||||||
return (vehicles.data ?? [])
|
return (vehicles.data ?? [])
|
||||||
|
.filter((vehicle) => vehicle.vehicle.city_id === selectedCityId)
|
||||||
.filter(
|
.filter(
|
||||||
(vehicle) =>
|
(vehicle) =>
|
||||||
!query ||
|
!query ||
|
||||||
@@ -151,11 +156,9 @@ export const VehicleListPage = observer(() => {
|
|||||||
tail_number: vehicle.vehicle.tail_number,
|
tail_number: vehicle.vehicle.tail_number,
|
||||||
type: vehicle.vehicle.type,
|
type: vehicle.vehicle.type,
|
||||||
carrier: vehicle.vehicle.carrier,
|
carrier: vehicle.vehicle.carrier,
|
||||||
city: carriers[language].data?.find(
|
city: cityStore.cities.ru.data.find((c) => c.id === vehicle.vehicle.city_id)?.name,
|
||||||
(carrier) => carrier.id === vehicle.vehicle.carrier_id
|
|
||||||
)?.city,
|
|
||||||
}));
|
}));
|
||||||
}, [vehicles.data, carriers[language].data, searchQuery]);
|
}, [vehicles.data, selectedCityId, searchQuery]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -166,6 +169,7 @@ export const VehicleListPage = observer(() => {
|
|||||||
<CreateButton
|
<CreateButton
|
||||||
label="Создать транспортное средство"
|
label="Создать транспортное средство"
|
||||||
path="/vehicle/create"
|
path="/vehicle/create"
|
||||||
|
disabled={!selectedCityId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -223,6 +227,8 @@ export const VehicleListPage = observer(() => {
|
|||||||
<Box sx={{ mt: 5, textAlign: "center", color: "text.secondary" }}>
|
<Box sx={{ mt: 5, textAlign: "center", color: "text.secondary" }}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<CircularProgress size={20} />
|
<CircularProgress size={20} />
|
||||||
|
) : !selectedCityId ? (
|
||||||
|
"Выберите город"
|
||||||
) : (
|
) : (
|
||||||
"Нет транспортных средств"
|
"Нет транспортных средств"
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { City } from "../CityStore";
|
|||||||
class SelectedCityStore {
|
class SelectedCityStore {
|
||||||
selectedCity: City | null = null;
|
selectedCity: City | null = null;
|
||||||
isLocked: boolean = false;
|
isLocked: boolean = false;
|
||||||
|
cityVersion: number = 0;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
@@ -25,6 +26,7 @@ class SelectedCityStore {
|
|||||||
setSelectedCity = (city: City | null) => {
|
setSelectedCity = (city: City | null) => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.selectedCity = city;
|
this.selectedCity = city;
|
||||||
|
this.cityVersion += 1;
|
||||||
if (city) {
|
if (city) {
|
||||||
localStorage.setItem("selectedCity", JSON.stringify(city));
|
localStorage.setItem("selectedCity", JSON.stringify(city));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class VehicleStore {
|
|||||||
carrier: string,
|
carrier: string,
|
||||||
carrierId: number,
|
carrierId: number,
|
||||||
model?: string,
|
model?: string,
|
||||||
|
cityId?: number,
|
||||||
) => {
|
) => {
|
||||||
const payload: Record<string, unknown> = {
|
const payload: Record<string, unknown> = {
|
||||||
tail_number: tailNumber.trim(),
|
tail_number: tailNumber.trim(),
|
||||||
@@ -129,6 +130,7 @@ class VehicleStore {
|
|||||||
};
|
};
|
||||||
// TODO: когда будет бекенд — добавить model в payload и в ответ
|
// TODO: когда будет бекенд — добавить model в payload и в ответ
|
||||||
if (model != null && model !== "") payload.model = model;
|
if (model != null && model !== "") payload.model = model;
|
||||||
|
if (cityId != null) payload.city_id = cityId;
|
||||||
const response = await languageInstance("ru").post("/vehicle", payload);
|
const response = await languageInstance("ru").post("/vehicle", payload);
|
||||||
const normalizedVehicle = this.normalizeVehicleItem(response.data);
|
const normalizedVehicle = this.normalizeVehicleItem(response.data);
|
||||||
|
|
||||||
@@ -147,6 +149,7 @@ class VehicleStore {
|
|||||||
carrier_id: number;
|
carrier_id: number;
|
||||||
model: string;
|
model: string;
|
||||||
snapshot_update_blocked: boolean;
|
snapshot_update_blocked: boolean;
|
||||||
|
city_id?: number;
|
||||||
} = {
|
} = {
|
||||||
tail_number: "",
|
tail_number: "",
|
||||||
type: 0,
|
type: 0,
|
||||||
@@ -154,6 +157,7 @@ class VehicleStore {
|
|||||||
carrier_id: 0,
|
carrier_id: 0,
|
||||||
model: "",
|
model: "",
|
||||||
snapshot_update_blocked: false,
|
snapshot_update_blocked: false,
|
||||||
|
city_id: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
setEditVehicleData = (data: {
|
setEditVehicleData = (data: {
|
||||||
@@ -163,6 +167,7 @@ class VehicleStore {
|
|||||||
carrier_id: number;
|
carrier_id: number;
|
||||||
model?: string;
|
model?: string;
|
||||||
snapshot_update_blocked?: boolean;
|
snapshot_update_blocked?: boolean;
|
||||||
|
city_id?: number;
|
||||||
}) => {
|
}) => {
|
||||||
this.editVehicleData = {
|
this.editVehicleData = {
|
||||||
...this.editVehicleData,
|
...this.editVehicleData,
|
||||||
@@ -179,6 +184,7 @@ class VehicleStore {
|
|||||||
carrier_id: number;
|
carrier_id: number;
|
||||||
model?: string;
|
model?: string;
|
||||||
snapshot_update_blocked?: boolean;
|
snapshot_update_blocked?: boolean;
|
||||||
|
city_id?: number;
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const payload: Record<string, unknown> = {
|
const payload: Record<string, unknown> = {
|
||||||
@@ -190,6 +196,7 @@ class VehicleStore {
|
|||||||
if (data.model != null && data.model !== "") payload.model = data.model;
|
if (data.model != null && data.model !== "") payload.model = data.model;
|
||||||
if (data.snapshot_update_blocked != null)
|
if (data.snapshot_update_blocked != null)
|
||||||
payload.snapshot_update_blocked = data.snapshot_update_blocked;
|
payload.snapshot_update_blocked = data.snapshot_update_blocked;
|
||||||
|
if (data.city_id != null) payload.city_id = data.city_id;
|
||||||
const response = await languageInstance("ru").patch(
|
const response = await languageInstance("ru").patch(
|
||||||
`/vehicle/${id}`,
|
`/vehicle/${id}`,
|
||||||
payload,
|
payload,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { authStore, cityStore, selectedCityStore, type City } from "@shared";
|
import { authStore, cityStore, selectedCityStore, snapshotStore, type City } from "@shared";
|
||||||
import { MapPin } from "lucide-react";
|
import { MapPin } from "lucide-react";
|
||||||
|
|
||||||
export const CitySelector: React.FC = observer(() => {
|
export const CitySelector: React.FC = observer(() => {
|
||||||
@@ -46,12 +46,14 @@ export const CitySelector: React.FC = observer(() => {
|
|||||||
const handleCityChange = (event: SelectChangeEvent<string>) => {
|
const handleCityChange = (event: SelectChangeEvent<string>) => {
|
||||||
const cityId = event.target.value;
|
const cityId = event.target.value;
|
||||||
if (cityId === "") {
|
if (cityId === "") {
|
||||||
|
snapshotStore.clearStoreCache();
|
||||||
setSelectedCity(null);
|
setSelectedCity(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const city = currentCities.find((c) => c.id === Number(cityId));
|
const city = currentCities.find((c) => c.id === Number(cityId));
|
||||||
if (city) {
|
if (city) {
|
||||||
|
snapshotStore.clearStoreCache();
|
||||||
setSelectedCity(city);
|
setSelectedCity(city);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
vehicleStore,
|
vehicleStore,
|
||||||
routeStore,
|
routeStore,
|
||||||
Vehicle,
|
Vehicle,
|
||||||
carrierStore,
|
|
||||||
selectedCityStore,
|
selectedCityStore,
|
||||||
menuStore,
|
menuStore,
|
||||||
VEHICLE_TYPES,
|
VEHICLE_TYPES,
|
||||||
@@ -184,31 +183,14 @@ export const DevicesTable = observer(() => {
|
|||||||
pageSize: 50,
|
pageSize: 50,
|
||||||
});
|
});
|
||||||
|
|
||||||
const filterVehiclesBySelectedCity = (vehiclesList: Vehicle[]): Vehicle[] => {
|
const { selectedCityId } = selectedCityStore;
|
||||||
const selectedCityId = selectedCityStore.selectedCityId;
|
|
||||||
|
|
||||||
if (!selectedCityId) {
|
const filteredVehicles = useMemo((): Vehicle[] => {
|
||||||
return vehiclesList;
|
if (!selectedCityId) return [];
|
||||||
}
|
return (vehicles.data as Vehicle[]).filter(
|
||||||
|
(vehicle) => vehicle.vehicle.city_id === selectedCityId,
|
||||||
const carriersInSelectedCityIds = new Set(
|
|
||||||
carrierStore.carriers.ru.data
|
|
||||||
.filter((carrier) => carrier.city_id === selectedCityId)
|
|
||||||
.map((carrier) => carrier.id),
|
|
||||||
);
|
);
|
||||||
|
}, [selectedCityId, vehicles.data]);
|
||||||
if (carriersInSelectedCityIds.size === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return vehiclesList.filter((vehicle) =>
|
|
||||||
carriersInSelectedCityIds.has(vehicle.vehicle.carrier_id),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const filteredVehicles = filterVehiclesBySelectedCity(
|
|
||||||
vehicles.data as Vehicle[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const rows = useMemo(
|
const rows = useMemo(
|
||||||
() => transformToRows(filteredVehicles),
|
() => transformToRows(filteredVehicles),
|
||||||
@@ -748,13 +730,8 @@ export const DevicesTable = observer(() => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
};
|
};
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [getDevices, getSnapshots, getVehicles, getRoutes, isMaintenanceOnly]);
|
}, [getDevices, getSnapshots, getVehicles, getRoutes, isMaintenanceOnly, selectedCityStore.cityVersion]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isMaintenanceOnly) {
|
|
||||||
carrierStore.getCarriers("ru");
|
|
||||||
}
|
|
||||||
}, [isMaintenanceOnly]);
|
|
||||||
|
|
||||||
const handleOpenSendSnapshotModal = () => {
|
const handleOpenSendSnapshotModal = () => {
|
||||||
if (!canWriteDevices) {
|
if (!canWriteDevices) {
|
||||||
@@ -888,6 +865,8 @@ export const DevicesTable = observer(() => {
|
|||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<CircularProgress size={20} />
|
<CircularProgress size={20} />
|
||||||
|
) : !selectedCityId ? (
|
||||||
|
"Выберите город"
|
||||||
) : (
|
) : (
|
||||||
"Нет устройств для отображения"
|
"Нет устройств для отображения"
|
||||||
)}
|
)}
|
||||||
@@ -928,13 +907,17 @@ export const DevicesTable = observer(() => {
|
|||||||
{!isCollapsed && (
|
{!isCollapsed && (
|
||||||
<Box sx={{ p: 0 }}>
|
<Box sx={{ p: 0 }}>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
rows={groupRows}
|
rows={groupRows}
|
||||||
columns={visibleColumns}
|
columns={visibleColumns}
|
||||||
checkboxSelection={canWriteDevices}
|
checkboxSelection={canWriteDevices}
|
||||||
disableRowSelectionExcludeModel
|
disableRowSelectionExcludeModel
|
||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
loading={isLoading}
|
onRowDoubleClick={(params) => {
|
||||||
paginationModel={paginationModel}
|
if (canWriteDevices) {
|
||||||
|
navigate(`/vehicle/${params.row.vehicle_id}/edit`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
loading={isLoading} paginationModel={paginationModel}
|
||||||
onPaginationModelChange={setPaginationModel}
|
onPaginationModelChange={setPaginationModel}
|
||||||
pageSizeOptions={[50]}
|
pageSizeOptions={[50]}
|
||||||
onRowSelectionModelChange={
|
onRowSelectionModelChange={
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user