feat: Redesign route direction
with media_order
input
This commit is contained in:
parent
7c363f1730
commit
8a443882b5
@ -106,17 +106,19 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>(
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
|
||||
{!props.dontRecurse &&
|
||||
{!props.dontRecurse && (
|
||||
<>
|
||||
<ArticleEditModal />
|
||||
<StationEditModal />
|
||||
</>
|
||||
}
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const LinkedItemsContents = <T extends { id: number; [key: string]: any }>({
|
||||
export const LinkedItemsContents = <
|
||||
T extends { id: number; [key: string]: any }
|
||||
>({
|
||||
parentId,
|
||||
parentResource,
|
||||
childResource,
|
||||
@ -128,7 +130,7 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any }
|
||||
onUpdate,
|
||||
disableCreation = false,
|
||||
updatedLinkedItems,
|
||||
refresh
|
||||
refresh,
|
||||
}: LinkedItemsProps<T>) => {
|
||||
const { language } = languageStore;
|
||||
const { setArticleModalOpenAction, setArticleIdAction } = articleStore;
|
||||
@ -358,11 +360,17 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any }
|
||||
: "default",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (childResource === "article" && type==="edit") {
|
||||
if (
|
||||
childResource === "article" &&
|
||||
type === "edit"
|
||||
) {
|
||||
setArticleModalOpenAction(true);
|
||||
setArticleIdAction(item.id);
|
||||
}
|
||||
if (childResource === "station" && type==="edit") {
|
||||
if (
|
||||
childResource === "station" &&
|
||||
type === "edit"
|
||||
) {
|
||||
setStationModalOpenAction(true);
|
||||
setStationIdAction(item.id);
|
||||
setRouteIdAction(Number(parentId));
|
||||
@ -434,25 +442,15 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any }
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
value={
|
||||
availableItems?.find(
|
||||
(item) => item.id === selectedItemId
|
||||
) || null
|
||||
}
|
||||
onChange={(_, newValue) =>
|
||||
setSelectedItemId(newValue?.id || null)
|
||||
availableItems?.find((item) => item.id === selectedItemId) || null
|
||||
}
|
||||
onChange={(_, newValue) => setSelectedItemId(newValue?.id || null)}
|
||||
options={availableItems}
|
||||
getOptionLabel={(item) => String(item[fields[0].data])}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label={`Выберите ${title}`}
|
||||
fullWidth
|
||||
/>
|
||||
<TextField {...params} label={`Выберите ${title}`} fullWidth />
|
||||
)}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.id === value?.id
|
||||
}
|
||||
isOptionEqualToValue={(option, value) => option.id === value?.id}
|
||||
filterOptions={(options, { inputValue }) => {
|
||||
const searchWords = inputValue
|
||||
.toLowerCase()
|
||||
@ -495,17 +493,32 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any }
|
||||
{childResource === "media" && (
|
||||
<FormControl fullWidth>
|
||||
<TextField
|
||||
type="number"
|
||||
type="text"
|
||||
label="Порядок отображения медиа"
|
||||
value={mediaOrder}
|
||||
onChange={(e) => {
|
||||
const newValue = Number(e.target.value);
|
||||
const rawValue = e.target.value;
|
||||
const numericValue = Number(rawValue);
|
||||
const maxValue = linkedItems.length + 1;
|
||||
const value = Math.max(1, Math.min(newValue, maxValue));
|
||||
setMediaOrder(value);
|
||||
|
||||
if (isNaN(numericValue)) {
|
||||
return;
|
||||
} else {
|
||||
let newValue = numericValue;
|
||||
|
||||
if (newValue < 10 && newValue > 0) {
|
||||
setMediaOrder(numericValue);
|
||||
}
|
||||
|
||||
if (newValue > maxValue) {
|
||||
newValue = maxValue;
|
||||
}
|
||||
|
||||
setMediaOrder(newValue);
|
||||
}
|
||||
}}
|
||||
fullWidth
|
||||
slotProps={{inputLabel: {shrink: true}}}
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
@ -513,7 +526,9 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any }
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={linkItem}
|
||||
disabled={!selectedItemId}
|
||||
disabled={
|
||||
!selectedItemId || (childResource == "media" && mediaOrder == 0)
|
||||
}
|
||||
sx={{ alignSelf: "flex-start" }}
|
||||
>
|
||||
Добавить
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from "@mui/material";
|
||||
import { Create, useAutocomplete } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { useState } from "react";
|
||||
import { Controller } from "react-hook-form";
|
||||
|
||||
export const RouteCreate = () => {
|
||||
@ -16,6 +17,7 @@ export const RouteCreate = () => {
|
||||
refineCore: { formLoading },
|
||||
register,
|
||||
control,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm({
|
||||
refineCoreProps: {
|
||||
@ -23,6 +25,16 @@ export const RouteCreate = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const directions = [
|
||||
{
|
||||
label: "Прямой",
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
label: "Обратный",
|
||||
value: false,
|
||||
},
|
||||
];
|
||||
const { autocompleteProps: carrierAutocompleteProps } = useAutocomplete({
|
||||
resource: "carrier",
|
||||
onSearch: (value) => [
|
||||
@ -34,7 +46,8 @@ export const RouteCreate = () => {
|
||||
],
|
||||
});
|
||||
|
||||
const { autocompleteProps: governorAppealAutocompleteProps } = useAutocomplete({
|
||||
const { autocompleteProps: governorAppealAutocompleteProps } =
|
||||
useAutocomplete({
|
||||
resource: "article",
|
||||
|
||||
onSearch: (value) => [
|
||||
@ -48,9 +61,11 @@ export const RouteCreate = () => {
|
||||
operator: "contains",
|
||||
value,
|
||||
},
|
||||
]
|
||||
],
|
||||
});
|
||||
|
||||
const [routeDirection, setRouteDirection] = useState(false);
|
||||
|
||||
return (
|
||||
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
||||
<Box
|
||||
@ -117,31 +132,6 @@ export const RouteCreate = () => {
|
||||
name="route_number"
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="route_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)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="textSecondary"
|
||||
sx={{ mt: 0, mb: 1 }}
|
||||
>
|
||||
(Прямой / Обратный)
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
{...register("path", {
|
||||
required: "Это поле является обязательным",
|
||||
@ -211,7 +201,7 @@ export const RouteCreate = () => {
|
||||
fullWidth
|
||||
slotProps={{ inputLabel: { shrink: true } }}
|
||||
type="number"
|
||||
label={"Системный номер маршрута *"}
|
||||
label={"Номер маршрута в Говорящем Городе *"}
|
||||
name="route_sys_number"
|
||||
/>
|
||||
|
||||
@ -258,6 +248,43 @@ export const RouteCreate = () => {
|
||||
)}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
{...register("route_direction", {
|
||||
value: routeDirection,
|
||||
})}
|
||||
/>
|
||||
|
||||
<Autocomplete
|
||||
options={directions}
|
||||
defaultValue={directions.find((el) => el.value == false)}
|
||||
onChange={(_, element) => {
|
||||
if (element) {
|
||||
setValue("route_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
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="textSecondary"
|
||||
sx={{ mt: 0, mb: 1 }}
|
||||
>
|
||||
{routeDirection ? "Прямой" : "Обратный"}
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
{...register("scale_min", {
|
||||
// required: 'Это поле является обязательным',
|
||||
|
@ -18,7 +18,7 @@ import {
|
||||
stationFields,
|
||||
vehicleFields,
|
||||
} from "./types";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { META_LANGUAGE, languageStore } from "@stores";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { LanguageSelector } from "@ui";
|
||||
@ -32,11 +32,25 @@ export const RouteEdit = observer(() => {
|
||||
formState: { errors },
|
||||
refineCore: { queryResult },
|
||||
setValue,
|
||||
getValues,
|
||||
watch,
|
||||
} = useForm({
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
refineCoreProps: META_LANGUAGE(language),
|
||||
});
|
||||
const routeDirectionFromServer = watch("route_direction");
|
||||
|
||||
const [routeDirection, setRouteDirection] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const directions = [
|
||||
{
|
||||
label: "Прямой",
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
label: "Обратный",
|
||||
value: false,
|
||||
},
|
||||
];
|
||||
|
||||
const { id: routeId } = useParams<{ id: string }>();
|
||||
|
||||
@ -59,10 +73,11 @@ export const RouteEdit = observer(() => {
|
||||
value,
|
||||
},
|
||||
],
|
||||
...META_LANGUAGE(language)
|
||||
...META_LANGUAGE(language),
|
||||
});
|
||||
|
||||
const { autocompleteProps: governorAppealAutocompleteProps } = useAutocomplete({
|
||||
const { autocompleteProps: governorAppealAutocompleteProps } =
|
||||
useAutocomplete({
|
||||
resource: "article",
|
||||
|
||||
onSearch: (value) => [
|
||||
@ -77,14 +92,18 @@ export const RouteEdit = observer(() => {
|
||||
value,
|
||||
},
|
||||
],
|
||||
...META_LANGUAGE(language)
|
||||
...META_LANGUAGE(language),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (routeDirectionFromServer) {
|
||||
setRouteDirection(routeDirectionFromServer);
|
||||
}
|
||||
}, [routeDirectionFromServer]);
|
||||
|
||||
return (
|
||||
<Edit saveButtonProps={saveButtonProps}>
|
||||
<Box
|
||||
sx={{display: "flex", flexDirection: "column", gap:1}}
|
||||
>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
|
||||
<Box
|
||||
component="form"
|
||||
sx={{ display: "flex", flexDirection: "column" }}
|
||||
@ -149,32 +168,31 @@ export const RouteEdit = observer(() => {
|
||||
label={"Номер маршрута"}
|
||||
name="route_number"
|
||||
/>
|
||||
<Controller
|
||||
name="route_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("route_direction")} />
|
||||
|
||||
<Autocomplete
|
||||
options={directions}
|
||||
value={directions.find((el) => el.value == routeDirection)}
|
||||
onChange={(_, element) => {
|
||||
if (element) {
|
||||
setValue("route_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
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="textSecondary"
|
||||
sx={{ mt: 0, mb: 1 }}
|
||||
>
|
||||
(Прямой / Обратный)
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
{...register("path", {
|
||||
required: "Это поле является обязательным",
|
||||
@ -198,7 +216,8 @@ export const RouteEdit = observer(() => {
|
||||
return "Введите хотя бы одну пару координат";
|
||||
if (
|
||||
!value.every(
|
||||
(point: unknown) => Array.isArray(point) && point.length === 2
|
||||
(point: unknown) =>
|
||||
Array.isArray(point) && point.length === 2
|
||||
)
|
||||
) {
|
||||
return "Каждая строка должна содержать две координаты";
|
||||
@ -243,7 +262,7 @@ export const RouteEdit = observer(() => {
|
||||
fullWidth
|
||||
slotProps={{ inputLabel: { shrink: true } }}
|
||||
type="number"
|
||||
label={"Системный номер маршрута *"}
|
||||
label={"Номер маршрута в Говорящем Городе *"}
|
||||
name="route_sys_number"
|
||||
/>
|
||||
|
||||
@ -364,7 +383,6 @@ export const RouteEdit = observer(() => {
|
||||
label={"Центр. долгота"}
|
||||
name="center_longitude"
|
||||
/>
|
||||
|
||||
</Box>
|
||||
|
||||
{routeId && (
|
||||
@ -390,7 +408,7 @@ export const RouteEdit = observer(() => {
|
||||
</>
|
||||
)}
|
||||
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-start' }}>
|
||||
<Box sx={{ display: "flex", justifyContent: "flex-start" }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
} from "@refinedev/mui";
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import MapIcon from '@mui/icons-material/Map';
|
||||
import MapIcon from "@mui/icons-material/Map";
|
||||
|
||||
import { localeText } from "../../locales/ru/localeText";
|
||||
import { useLink } from "@refinedev/core";
|
||||
@ -21,7 +21,7 @@ export const RouteList = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const { dataGridProps } = useDataGrid({
|
||||
resource: "route/",
|
||||
meta: META_LANGUAGE(language)
|
||||
meta: META_LANGUAGE(language),
|
||||
});
|
||||
|
||||
const columns = React.useMemo<GridColDef[]>(
|
||||
@ -64,7 +64,7 @@ export const RouteList = observer(() => {
|
||||
},
|
||||
{
|
||||
field: "route_sys_number",
|
||||
headerName: "Системный номер маршрута",
|
||||
headerName: "Номер маршрута в Говорящем Городе",
|
||||
type: "string",
|
||||
minWidth: 120,
|
||||
display: "flex",
|
||||
|
Loading…
Reference in New Issue
Block a user