fix: Update language
usage with review coordinates
All checks were successful
release-tag / release-image (push) Successful in 2m16s
All checks were successful
release-tag / release-image (push) Successful in 2m16s
This commit is contained in:
parent
b34baf6d40
commit
9218743faf
@ -3,19 +3,63 @@ import { Create, useAutocomplete } from "@refinedev/mui";
|
|||||||
import { useForm } from "@refinedev/react-hook-form";
|
import { useForm } from "@refinedev/react-hook-form";
|
||||||
import { Controller } from "react-hook-form";
|
import { Controller } from "react-hook-form";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { languageStore, META_LANGUAGE } from "../../store/LanguageStore";
|
import { META_LANGUAGE } from "../../store/LanguageStore";
|
||||||
|
import { LanguageSwitch } from "@/components/LanguageSwitch";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { EVERY_LANGUAGE, Languages, languageStore } from "@stores";
|
||||||
|
|
||||||
export const CarrierCreate = observer(() => {
|
export const CarrierCreate = observer(() => {
|
||||||
const { language } = languageStore;
|
const { language, setLanguageAction } = languageStore;
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
refineCore: { formLoading },
|
refineCore: { formLoading },
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
|
setValue,
|
||||||
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm({
|
} = useForm({
|
||||||
refineCoreProps: META_LANGUAGE(language)
|
refineCoreProps: META_LANGUAGE(language),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [carrierData, setCarrierData] = useState({
|
||||||
|
full_name: EVERY_LANGUAGE(""),
|
||||||
|
short_name: EVERY_LANGUAGE(""),
|
||||||
|
slogan: EVERY_LANGUAGE(""),
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue("full_name", carrierData.full_name[language]);
|
||||||
|
setValue("short_name", carrierData.short_name[language]);
|
||||||
|
setValue("slogan", carrierData.slogan[language]);
|
||||||
|
}, [carrierData, language, setValue]);
|
||||||
|
|
||||||
|
function updateTranslations(update: boolean = true) {
|
||||||
|
const newCarrierData = {
|
||||||
|
...carrierData,
|
||||||
|
full_name: {
|
||||||
|
...carrierData.full_name,
|
||||||
|
[language]: watch("full_name") ?? "",
|
||||||
|
},
|
||||||
|
short_name: {
|
||||||
|
...carrierData.short_name,
|
||||||
|
[language]: watch("short_name") ?? "",
|
||||||
|
},
|
||||||
|
slogan: {
|
||||||
|
...carrierData.slogan,
|
||||||
|
[language]: watch("slogan") ?? "",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (update) setCarrierData(newCarrierData);
|
||||||
|
return newCarrierData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
|
updateTranslations();
|
||||||
|
setLanguageAction(lang);
|
||||||
|
};
|
||||||
|
|
||||||
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
||||||
resource: "city",
|
resource: "city",
|
||||||
onSearch: (value) => [
|
onSearch: (value) => [
|
||||||
@ -45,6 +89,7 @@ export const CarrierCreate = observer(() => {
|
|||||||
sx={{ display: "flex", flexDirection: "column" }}
|
sx={{ display: "flex", flexDirection: "column" }}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
>
|
>
|
||||||
|
<LanguageSwitch action={handleLanguageChange} />
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="city_id"
|
name="city_id"
|
||||||
@ -95,7 +140,7 @@ export const CarrierCreate = observer(() => {
|
|||||||
helperText={(errors as any)?.full_name?.message}
|
helperText={(errors as any)?.full_name?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{inputLabel: {shrink: true}}}
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
type="text"
|
type="text"
|
||||||
label={"Полное имя *"}
|
label={"Полное имя *"}
|
||||||
name="full_name"
|
name="full_name"
|
||||||
@ -109,16 +154,13 @@ export const CarrierCreate = observer(() => {
|
|||||||
helperText={(errors as any)?.short_name?.message}
|
helperText={(errors as any)?.short_name?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{inputLabel: {shrink: true}}}
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
type="text"
|
type="text"
|
||||||
label={"Короткое имя"}
|
label={"Короткое имя"}
|
||||||
name="short_name"
|
name="short_name"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Box component="form"
|
<Box component="form" sx={{ display: "flex" }} autoComplete="off">
|
||||||
sx={{ display: "flex" }}
|
|
||||||
autoComplete="off"
|
|
||||||
>
|
|
||||||
<TextField
|
<TextField
|
||||||
{...register("main_color", {
|
{...register("main_color", {
|
||||||
// required: 'Это поле является обязательным',
|
// required: 'Это поле является обязательным',
|
||||||
@ -127,7 +169,7 @@ export const CarrierCreate = observer(() => {
|
|||||||
helperText={(errors as any)?.main_color?.message}
|
helperText={(errors as any)?.main_color?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{inputLabel: {shrink: true}}}
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
type="color"
|
type="color"
|
||||||
label={"Основной цвет"}
|
label={"Основной цвет"}
|
||||||
name="main_color"
|
name="main_color"
|
||||||
@ -149,7 +191,7 @@ export const CarrierCreate = observer(() => {
|
|||||||
helperText={(errors as any)?.left_color?.message}
|
helperText={(errors as any)?.left_color?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{inputLabel: {shrink: true}}}
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
type="color"
|
type="color"
|
||||||
label={"Цвет левого виджета"}
|
label={"Цвет левого виджета"}
|
||||||
name="left_color"
|
name="left_color"
|
||||||
@ -172,7 +214,7 @@ export const CarrierCreate = observer(() => {
|
|||||||
helperText={(errors as any)?.right_color?.message}
|
helperText={(errors as any)?.right_color?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{inputLabel: {shrink: true}}}
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
type="color"
|
type="color"
|
||||||
label={"Цвет правого виджета"}
|
label={"Цвет правого виджета"}
|
||||||
name="right_color"
|
name="right_color"
|
||||||
@ -195,7 +237,7 @@ export const CarrierCreate = observer(() => {
|
|||||||
helperText={(errors as any)?.slogan?.message}
|
helperText={(errors as any)?.slogan?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
slotProps={{inputLabel: {shrink: true}}}
|
slotProps={{ inputLabel: { shrink: true } }}
|
||||||
type="text"
|
type="text"
|
||||||
label={"Слоган"}
|
label={"Слоган"}
|
||||||
name="slogan"
|
name="slogan"
|
||||||
|
@ -1,97 +1,303 @@
|
|||||||
import {Autocomplete, Box, TextField} from '@mui/material'
|
import { Autocomplete, Box, TextField } from "@mui/material";
|
||||||
import {Create, useAutocomplete} from '@refinedev/mui'
|
import { Create, useAutocomplete } from "@refinedev/mui";
|
||||||
import {useForm} from '@refinedev/react-hook-form'
|
import { useForm } from "@refinedev/react-hook-form";
|
||||||
import {Controller} from 'react-hook-form'
|
import { Controller } from "react-hook-form";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { EVERY_LANGUAGE, Languages, languageStore } from "@stores"; // Assuming these imports are correct and available
|
||||||
|
import { LanguageSwitch } from "@/components/LanguageSwitch"; // Assuming this import is correct and available
|
||||||
|
import { axiosInstance, axiosInstanceForGet } from "@/providers"; // Assuming these imports are correct and available
|
||||||
|
import { useNavigate } from "react-router";
|
||||||
|
import { useNotification } from "@refinedev/core";
|
||||||
|
|
||||||
export const CityCreate = () => {
|
export const CityCreate = () => {
|
||||||
|
const { language, setLanguageAction } = languageStore;
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const notification = useNotification();
|
||||||
|
// State to hold all language translations for the city name.
|
||||||
|
// Initialized with an object where each language key maps to an empty string.
|
||||||
|
const [allLanguageNames, setAllLanguageNames] = useState<
|
||||||
|
Record<Languages, string>
|
||||||
|
>(EVERY_LANGUAGE(""));
|
||||||
|
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
refineCore: {formLoading},
|
refineCore: { formLoading }, // Indicates if the form is currently loading data
|
||||||
register,
|
register, // Function to register input fields with react-hook-form
|
||||||
control,
|
control, // Object to pass to Controller for controlled components
|
||||||
formState: {errors},
|
setValue, // Function to programmatically set form values
|
||||||
} = useForm({})
|
watch, // Function to watch for changes in form values
|
||||||
|
handleSubmit, // Function to handle form submission, including validation
|
||||||
|
formState: { errors }, // Object containing form validation errors
|
||||||
|
} = useForm<{
|
||||||
|
name: string; // This field will hold the name for the *currently active* language
|
||||||
|
country_code: string; // The code for the selected country
|
||||||
|
arms: string; // The ID of the selected media for the city's arms (e.g., coat of arms)
|
||||||
|
}>({});
|
||||||
|
|
||||||
const {autocompleteProps: countryAutocompleteProps} = useAutocomplete({
|
// useEffect hook to synchronize the 'name' TextField with the 'allLanguageNames' state.
|
||||||
resource: 'country',
|
// Whenever the active 'language' or the 'allLanguageNames' state changes,
|
||||||
})
|
// the 'name' field in the form is updated to display the correct translation.
|
||||||
|
useEffect(() => {
|
||||||
|
setValue("name", allLanguageNames[language]);
|
||||||
|
}, [language, allLanguageNames, setValue]);
|
||||||
|
|
||||||
const {autocompleteProps: mediaAutocompleteProps} = useAutocomplete({
|
// Function to update the 'allLanguageNames' state with the current value from the 'name' TextField.
|
||||||
resource: 'media',
|
// This is crucial to ensure that changes made by the user are saved before
|
||||||
|
// switching languages or submitting the form.
|
||||||
|
const updateCurrentLanguageName = () => {
|
||||||
|
const currentNameValue = watch("name"); // Get the current value typed into the 'name' TextField
|
||||||
|
setAllLanguageNames((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[language]: currentNameValue || "", // Update the specific language entry in the state
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for language switch.
|
||||||
|
// It first saves the current input for the active language, then changes the language.
|
||||||
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
|
updateCurrentLanguageName(); // Save the current input before switching language
|
||||||
|
setLanguageAction(lang); // Update the global language state
|
||||||
|
};
|
||||||
|
|
||||||
|
// Autocomplete props for Country selection.
|
||||||
|
// 'resource' specifies the API endpoint, and it's assumed 'code' is the value
|
||||||
|
// to be stored and 'name' is the label to display.
|
||||||
|
const { autocompleteProps: countryAutocompleteProps } = useAutocomplete({
|
||||||
|
resource: "country",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Autocomplete props for Media selection (specifically for city's arms).
|
||||||
|
// 'resource' specifies the API endpoint, and 'onSearch' provides a custom
|
||||||
|
// search filter based on 'media_name'.
|
||||||
|
const { autocompleteProps: mediaAutocompleteProps } = useAutocomplete({
|
||||||
|
resource: "media",
|
||||||
onSearch: (value) => [
|
onSearch: (value) => [
|
||||||
{
|
{
|
||||||
field: 'media_name',
|
field: "media_name",
|
||||||
operator: 'contains',
|
operator: "contains",
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
|
|
||||||
|
// This function is called when the form is submitted and passes validation.
|
||||||
|
// It orchestrates the API calls for creating the city and updating its translations.
|
||||||
|
const onFinish = async (data: {
|
||||||
|
name: string;
|
||||||
|
country_code: string;
|
||||||
|
arms: string;
|
||||||
|
}) => {
|
||||||
|
// Ensure the very latest input for the current language is captured
|
||||||
|
// into 'allLanguageNames' before making API calls. This handles cases
|
||||||
|
// where the user might click 'Save' without blurring the 'name' field.
|
||||||
|
updateCurrentLanguageName();
|
||||||
|
|
||||||
|
// Create a final set of names including the latest value from the form
|
||||||
|
// for the current language.
|
||||||
|
const finalNames = {
|
||||||
|
...allLanguageNames,
|
||||||
|
[language]: data.name, // Ensure the absolute latest value from the form is included
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Validate that the Russian name is present, as it's used for the initial POST request.
|
||||||
|
if (!finalNames["ru"]) {
|
||||||
|
console.error("Russian name is required for initial city creation.");
|
||||||
|
// In a real application, you might want to display a user-friendly error message here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Submitting with names:", finalNames);
|
||||||
|
|
||||||
|
// 1. Create the city entry in Russian.
|
||||||
|
// This POST request typically returns the ID of the newly created resource.
|
||||||
|
const ruResponse = await axiosInstanceForGet("ru").post("/city", {
|
||||||
|
name: finalNames["ru"], // Russian name
|
||||||
|
country_code: data.country_code, // Country code from the form
|
||||||
|
arms: data.arms, // Arms ID from the form, included in initial creation
|
||||||
|
});
|
||||||
|
|
||||||
|
const id = ruResponse.data.id; // Extract the ID of the newly created city
|
||||||
|
|
||||||
|
// 2. Patch the city with the English name if available.
|
||||||
|
if (finalNames["en"]) {
|
||||||
|
await axiosInstanceForGet("en").patch(`/city/${id}`, {
|
||||||
|
name: finalNames["en"], // English name
|
||||||
|
country_code: data.country_code, // Country code from the form
|
||||||
|
arms: data.arms, // Arms ID from the form, included in initial creation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Patch the city with the Chinese name if available.
|
||||||
|
if (finalNames["zh"]) {
|
||||||
|
await axiosInstanceForGet("zh").patch(`/city/${id}`, {
|
||||||
|
name: finalNames["zh"], // Chinese name
|
||||||
|
country_code: data.country_code, // Country code from the form
|
||||||
|
arms: data.arms, // Arms ID from the form, included in initial creation
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("City created/updated successfully!");
|
||||||
|
if (notification && typeof notification.open === "function") {
|
||||||
|
notification.open({
|
||||||
|
message: "Город успешно создан",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.onbeforeunload = null;
|
||||||
|
navigate("/city");
|
||||||
|
|
||||||
|
// After successful creation/update, you might want to:
|
||||||
|
// - Navigate to a different page (e.g., city list).
|
||||||
|
// - Display a success notification to the user.
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating/updating city:", error);
|
||||||
|
// Display an error message to the user if the API calls fail.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
<Create
|
||||||
<Box component="form" sx={{display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
isLoading={formLoading} // Show loading indicator if form data is being fetched
|
||||||
|
// Pass the handleSubmit function to the save button's onClick.
|
||||||
|
// This ensures form validation runs before 'onFinish' is called.
|
||||||
|
saveButtonProps={{
|
||||||
|
...saveButtonProps,
|
||||||
|
onClick: handleSubmit(onFinish as any),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
component="form"
|
||||||
|
sx={{ display: "flex", flexDirection: "column" }}
|
||||||
|
autoComplete="off" // Disable browser autocomplete
|
||||||
|
>
|
||||||
|
{/* Language Switch component to change the active language */}
|
||||||
|
<LanguageSwitch action={handleLanguageChange} />
|
||||||
|
|
||||||
|
{/* Country Autocomplete field */}
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control} // Pass control from useForm
|
||||||
name="country_code"
|
name="country_code" // Field name in the form state
|
||||||
rules={{required: 'Это поле является обязательным'}}
|
rules={{ required: "Это поле является обязательным" }} // Validation rule
|
||||||
defaultValue={null}
|
defaultValue={null} // Initial value
|
||||||
render={({field}) => (
|
render={({ field }) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...countryAutocompleteProps}
|
{...countryAutocompleteProps} // Spread autocomplete props from useAutocomplete hook
|
||||||
value={countryAutocompleteProps.options.find((option) => option.code === field.value) || null}
|
value={
|
||||||
onChange={(_, value) => {
|
// Find the selected option based on the field's current value
|
||||||
field.onChange(value?.code || '')
|
countryAutocompleteProps.options.find(
|
||||||
|
(option: { code: string; name: string; id: string }) =>
|
||||||
|
option.code === field.value
|
||||||
|
) || null
|
||||||
|
}
|
||||||
|
onChange={(
|
||||||
|
_,
|
||||||
|
value: { code: string; name: string; id: string } | null
|
||||||
|
) => {
|
||||||
|
// Update the form field's value when an option is selected
|
||||||
|
field.onChange(value?.code || "");
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item: {
|
||||||
return item ? item.name : ''
|
code: string;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
}) => {
|
||||||
|
// Define how to display the label for each option
|
||||||
|
return item ? item.name : "";
|
||||||
}}
|
}}
|
||||||
isOptionEqualToValue={(option, value) => {
|
isOptionEqualToValue={(
|
||||||
return option.id === value?.id
|
option: { code: string; name: string; id: string },
|
||||||
|
value: { code: string; name: string; id: string }
|
||||||
|
) => {
|
||||||
|
// Define how to compare options for equality
|
||||||
|
return option.id === value?.id;
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите страну" margin="normal" variant="outlined" error={!!errors.country_code} helperText={(errors as any)?.country_code?.message} required />}
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Выберите страну"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
error={!!errors.country_code} // Show error state if validation fails
|
||||||
|
required // Mark as required in UI
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* City Name TextField for the current language */}
|
||||||
<TextField
|
<TextField
|
||||||
{...register('name', {
|
{...register("name", {
|
||||||
required: 'Это поле является обязательным',
|
required: "Это поле является обязательным", // Validation rule
|
||||||
|
onBlur: updateCurrentLanguageName, // Update translations when the field loses focus
|
||||||
})}
|
})}
|
||||||
error={!!(errors as any)?.name}
|
error={!!errors.name} // Show error state if validation fails
|
||||||
helperText={(errors as any)?.name?.message}
|
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
InputLabelProps={{shrink: true}}
|
InputLabelProps={{ shrink: true }}
|
||||||
type="text"
|
type="text"
|
||||||
label={'Название *'}
|
label={"Название *"}
|
||||||
name="name"
|
name="name" // HTML name attribute, matches register key
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Arms Autocomplete field */}
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control} // Pass control from useForm
|
||||||
name="arms"
|
name="arms" // Field name in the form state
|
||||||
defaultValue={null}
|
defaultValue={null} // Initial value
|
||||||
render={({field}) => (
|
render={({ field }) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps} // Spread autocomplete props from useAutocomplete hook
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={
|
||||||
onChange={(_, value) => {
|
// Find the selected option based on the field's current value
|
||||||
field.onChange(value?.id || '')
|
mediaAutocompleteProps.options.find(
|
||||||
|
(option: { id: string; media_name: string }) =>
|
||||||
|
option.id === field.value
|
||||||
|
) || null
|
||||||
|
}
|
||||||
|
onChange={(
|
||||||
|
_,
|
||||||
|
value: { id: string; media_name: string } | null
|
||||||
|
) => {
|
||||||
|
// Update the form field's value when an option is selected
|
||||||
|
field.onChange(value?.id || "");
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item: { id: string; media_name: string }) => {
|
||||||
return item ? item.media_name : ''
|
// Define how to display the label for each option
|
||||||
|
return item ? item.media_name : "";
|
||||||
}}
|
}}
|
||||||
isOptionEqualToValue={(option, value) => {
|
isOptionEqualToValue={(
|
||||||
return option.id === value?.id
|
option: { id: string; media_name: string },
|
||||||
|
value: { id: string; media_name: string }
|
||||||
|
) => {
|
||||||
|
// Define how to compare options for equality
|
||||||
|
return option.id === value?.id;
|
||||||
}}
|
}}
|
||||||
filterOptions={(options, {inputValue}) => {
|
filterOptions={(
|
||||||
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
options: { id: string; media_name: string }[],
|
||||||
|
{ inputValue }
|
||||||
|
) => {
|
||||||
|
// Custom filter for options based on input value
|
||||||
|
return options.filter((option) =>
|
||||||
|
option.media_name
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(inputValue.toLowerCase())
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите герб" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} />}
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Выберите герб"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
error={!!errors.arms} // Show error state if validation fails
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Create>
|
</Create>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
@ -100,7 +100,6 @@ export const MediaList = observer(() => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
localeText={localeText}
|
localeText={localeText}
|
||||||
getRowId={(row: any) => row.id}
|
getRowId={(row: any) => row.id}
|
||||||
languageEnabled
|
|
||||||
/>
|
/>
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
@ -114,10 +114,10 @@ export const StationLabel = observer(
|
|||||||
rotation={-rotation}
|
rotation={-rotation}
|
||||||
>
|
>
|
||||||
<pixiText
|
<pixiText
|
||||||
anchor={{ x: 0.5, y: 0.5 }}
|
anchor={{ x: 1, y: 0.5 }}
|
||||||
text={station.name}
|
text={station.name}
|
||||||
position={{
|
position={{
|
||||||
x: position.x / scale,
|
x: position.x / scale + 24,
|
||||||
y: position.y / scale,
|
y: position.y / scale,
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
@ -129,10 +129,10 @@ export const StationLabel = observer(
|
|||||||
|
|
||||||
{ruLabel && (
|
{ruLabel && (
|
||||||
<pixiText
|
<pixiText
|
||||||
anchor={{ x: 0.5, y: -1 }}
|
anchor={{ x: 1, y: -1 }}
|
||||||
text={ruLabel}
|
text={ruLabel}
|
||||||
position={{
|
position={{
|
||||||
x: position.x / scale,
|
x: position.x / scale + 24,
|
||||||
y: position.y / scale,
|
y: position.y / scale,
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
|
@ -153,7 +153,11 @@ export const RouteMap = observer(() => {
|
|||||||
<Station
|
<Station
|
||||||
station={obj}
|
station={obj}
|
||||||
key={obj.id}
|
key={obj.id}
|
||||||
ruLabel={language === "ru" ? null : stationData.ru[index].name}
|
ruLabel={
|
||||||
|
language === "ru"
|
||||||
|
? stationData.en[index].name
|
||||||
|
: stationData.ru[index].name
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|||||||
|
|
||||||
export const SightCreate = observer(() => {
|
export const SightCreate = observer(() => {
|
||||||
const { language, setLanguageAction } = languageStore;
|
const { language, setLanguageAction } = languageStore;
|
||||||
|
const [coordinates, setCoordinates] = useState("");
|
||||||
const [sightData, setSightData] = useState({
|
const [sightData, setSightData] = useState({
|
||||||
name: EVERY_LANGUAGE(""),
|
name: EVERY_LANGUAGE(""),
|
||||||
address: EVERY_LANGUAGE(""),
|
address: EVERY_LANGUAGE(""),
|
||||||
@ -79,10 +80,7 @@ export const SightCreate = observer(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [namePreview, setNamePreview] = useState("");
|
const [namePreview, setNamePreview] = useState("");
|
||||||
const [coordinatesPreview, setCoordinatesPreview] = useState({
|
const [coordinatesPreview, setCoordinatesPreview] = useState("");
|
||||||
latitude: "",
|
|
||||||
longitude: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const [creatingArticleHeading, setCreatingArticleHeading] =
|
const [creatingArticleHeading, setCreatingArticleHeading] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
@ -102,13 +100,19 @@ export const SightCreate = observer(() => {
|
|||||||
const [previewArticlePreview, setPreviewArticlePreview] = useState("");
|
const [previewArticlePreview, setPreviewArticlePreview] = useState("");
|
||||||
|
|
||||||
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const [lat, lon] = e.target.value.split(",").map((s) => s.trim());
|
setCoordinates(e.target.value);
|
||||||
setCoordinatesPreview({
|
if (e.target.value) {
|
||||||
latitude: lat,
|
const [lat, lon] = e.target.value.split(" ").map((s) => s.trim());
|
||||||
longitude: lon,
|
setCoordinatesPreview(
|
||||||
});
|
`${lat ? Number(lat) : 0}, ${lon ? Number(lon) : 0}`
|
||||||
setValue("latitude", lat);
|
);
|
||||||
setValue("longitude", lon);
|
setValue("latitude", lat ? Number(lat) : 0);
|
||||||
|
setValue("longitude", lon ? Number(lon) : 0);
|
||||||
|
} else {
|
||||||
|
setCoordinatesPreview("");
|
||||||
|
setValue("latitude", "");
|
||||||
|
setValue("longitude", "");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Автокомплиты
|
// Автокомплиты
|
||||||
@ -170,13 +174,6 @@ export const SightCreate = observer(() => {
|
|||||||
setNamePreview(nameContent ?? "");
|
setNamePreview(nameContent ?? "");
|
||||||
}, [nameContent]);
|
}, [nameContent]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCoordinatesPreview({
|
|
||||||
latitude: latitudeContent || "",
|
|
||||||
longitude: longitudeContent || "",
|
|
||||||
});
|
|
||||||
}, [latitudeContent, longitudeContent]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const selectedCity = cityAutocompleteProps.options.find(
|
const selectedCity = cityAutocompleteProps.options.find(
|
||||||
(option) => option.id === cityContent
|
(option) => option.id === cityContent
|
||||||
@ -276,7 +273,7 @@ export const SightCreate = observer(() => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
value={`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
|
value={coordinates}
|
||||||
onChange={handleCoordinatesChange}
|
onChange={handleCoordinatesChange}
|
||||||
error={!!(errors as any)?.latitude}
|
error={!!(errors as any)?.latitude}
|
||||||
helperText={(errors as any)?.latitude?.message}
|
helperText={(errors as any)?.latitude?.message}
|
||||||
@ -286,10 +283,11 @@ export const SightCreate = observer(() => {
|
|||||||
type="text"
|
type="text"
|
||||||
label={"Координаты *"}
|
label={"Координаты *"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("longitude", {
|
{...register("longitude", {
|
||||||
value: coordinatesPreview.longitude,
|
value: coordinates.split(" ")[1],
|
||||||
required: "Это поле является обязательным",
|
required: "Это поле является обязательным",
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
@ -297,7 +295,7 @@ export const SightCreate = observer(() => {
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("latitude", {
|
{...register("latitude", {
|
||||||
value: coordinatesPreview.latitude,
|
value: coordinates.split(" ")[0],
|
||||||
required: "Это поле является обязательным",
|
required: "Это поле является обязательным",
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
@ -668,21 +666,22 @@ export const SightCreate = observer(() => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{/* Координаты */}
|
{/* Координаты */}
|
||||||
<Typography variant="body1" sx={{ mb: 2 }}>
|
{coordinatesPreview && (
|
||||||
<Box component="span" sx={{ color: "text.secondary" }}>
|
<Typography variant="body1" sx={{ mb: 2 }}>
|
||||||
Координаты:{" "}
|
<Box component="span" sx={{ color: "text.secondary" }}>
|
||||||
</Box>
|
Координаты:{" "}
|
||||||
<Box
|
</Box>
|
||||||
component="span"
|
<Box
|
||||||
sx={{
|
component="span"
|
||||||
color: (theme) =>
|
sx={{
|
||||||
theme.palette.mode === "dark" ? "grey.300" : "grey.800",
|
color: (theme) =>
|
||||||
}}
|
theme.palette.mode === "dark" ? "grey.300" : "grey.800",
|
||||||
>
|
}}
|
||||||
{`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
|
>
|
||||||
</Box>
|
{coordinatesPreview}
|
||||||
</Typography>
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
{/* Обложка */}
|
{/* Обложка */}
|
||||||
{thumbnailPreview && (
|
{thumbnailPreview && (
|
||||||
<Box sx={{ mb: 2 }}>
|
<Box sx={{ mb: 2 }}>
|
||||||
|
@ -70,6 +70,7 @@ export const SightEdit = observer(() => {
|
|||||||
name: EVERY_LANGUAGE(""),
|
name: EVERY_LANGUAGE(""),
|
||||||
address: EVERY_LANGUAGE(""),
|
address: EVERY_LANGUAGE(""),
|
||||||
});
|
});
|
||||||
|
const [coordinates, setCoordinates] = useState("");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
@ -163,37 +164,13 @@ export const SightEdit = observer(() => {
|
|||||||
setValue("address", sightData.address[language]);
|
setValue("address", sightData.address[language]);
|
||||||
}, [language, sightData, setValue]);
|
}, [language, sightData, setValue]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const latitude = getValues("latitude");
|
|
||||||
const longitude = getValues("longitude");
|
|
||||||
if (latitude && longitude) {
|
|
||||||
setCoordinatesPreview({
|
|
||||||
latitude: latitude,
|
|
||||||
longitude: longitude,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [getValues]);
|
|
||||||
|
|
||||||
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 [creatingArticleHeading, setCreatingArticleHeading] =
|
const [creatingArticleHeading, setCreatingArticleHeading] =
|
||||||
useState<string>("");
|
useState<string>("");
|
||||||
const [creatingArticleBody, setCreatingArticleBody] = useState<string>("");
|
const [creatingArticleBody, setCreatingArticleBody] = useState<string>("");
|
||||||
|
|
||||||
const [coordinatesPreview, setCoordinatesPreview] = useState({
|
const [coordinatesPreview, setCoordinatesPreview] = useState("");
|
||||||
latitude: "",
|
|
||||||
longitude: "",
|
|
||||||
});
|
|
||||||
const [selectedArticleIndex, setSelectedArticleIndex] = useState(-1);
|
const [selectedArticleIndex, setSelectedArticleIndex] = useState(-1);
|
||||||
const [previewMediaFile, setPreviewMediaFile] = useState<MediaData>();
|
const [previewMediaFile, setPreviewMediaFile] = useState<MediaData>();
|
||||||
const [thumbnailPreview, setThumbnailPreview] = useState<string | null>(null);
|
const [thumbnailPreview, setThumbnailPreview] = useState<string | null>(null);
|
||||||
@ -243,12 +220,25 @@ export const SightEdit = observer(() => {
|
|||||||
const watermarkRDContent = watch("watermark_rd");
|
const watermarkRDContent = watch("watermark_rd");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCoordinatesPreview({
|
if (latitudeContent && longitudeContent) {
|
||||||
latitude: latitudeContent ?? "",
|
setCoordinates(`${latitudeContent} ${longitudeContent}`);
|
||||||
longitude: longitudeContent ?? "",
|
}
|
||||||
});
|
|
||||||
}, [latitudeContent, longitudeContent]);
|
}, [latitudeContent, longitudeContent]);
|
||||||
|
|
||||||
|
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setCoordinates(e.target.value);
|
||||||
|
if (e.target.value) {
|
||||||
|
const [lat, lon] = e.target.value.split(" ").map((s) => s.trim());
|
||||||
|
setCoordinatesPreview(`${lat ?? "0"}, ${lon ?? "0"}`);
|
||||||
|
setValue("latitude", lat ?? "");
|
||||||
|
setValue("longitude", lon ?? "");
|
||||||
|
} else {
|
||||||
|
setCoordinatesPreview("");
|
||||||
|
setValue("latitude", "");
|
||||||
|
setValue("longitude", "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (linkedArticles[selectedArticleIndex]?.id) {
|
if (linkedArticles[selectedArticleIndex]?.id) {
|
||||||
getMedia(linkedArticles[selectedArticleIndex].id).then((media) => {
|
getMedia(linkedArticles[selectedArticleIndex].id).then((media) => {
|
||||||
@ -505,7 +495,6 @@ export const SightEdit = observer(() => {
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("longitude", {
|
{...register("longitude", {
|
||||||
value: coordinatesPreview.longitude,
|
|
||||||
required: "Это поле является обязательным",
|
required: "Это поле является обязательным",
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
@ -513,7 +502,6 @@ export const SightEdit = observer(() => {
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("latitude", {
|
{...register("latitude", {
|
||||||
value: coordinatesPreview.latitude,
|
|
||||||
required: "Это поле является обязательным",
|
required: "Это поле является обязательным",
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
@ -1535,7 +1523,7 @@ export const SightEdit = observer(() => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
value={`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
|
value={coordinates}
|
||||||
onChange={handleCoordinatesChange}
|
onChange={handleCoordinatesChange}
|
||||||
error={!!(errors as any)?.latitude}
|
error={!!(errors as any)?.latitude}
|
||||||
helperText={(errors as any)?.latitude?.message}
|
helperText={(errors as any)?.latitude?.message}
|
||||||
@ -1687,7 +1675,7 @@ export const SightEdit = observer(() => {
|
|||||||
: "grey.800",
|
: "grey.800",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
|
{coordinatesPreview}
|
||||||
</Box>
|
</Box>
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -56,6 +56,7 @@ export const SightList = observer(() => {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
align: "left",
|
align: "left",
|
||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
|
flex: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "latitude",
|
field: "latitude",
|
||||||
|
@ -41,40 +41,19 @@ export const StationCreate = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [coordinatesPreview, setCoordinatesPreview] = useState({
|
const [coordinates, setCoordinates] = useState("");
|
||||||
latitude: "",
|
|
||||||
longitude: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const [lat, lon] = e.target.value.split(",").map((s) => s.trim());
|
setCoordinates(e.target.value);
|
||||||
setCoordinatesPreview({
|
const [lat, lon] = e.target.value
|
||||||
latitude: lat,
|
.replace(/,/g, "") // Remove all commas from the string
|
||||||
longitude: lon,
|
.split(" ")
|
||||||
});
|
.map((s) => s.trim());
|
||||||
|
console.log(lat, lon);
|
||||||
setValue("latitude", lat);
|
setValue("latitude", lat);
|
||||||
setValue("longitude", lon);
|
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 = [
|
const directions = [
|
||||||
{
|
{
|
||||||
label: "Прямой",
|
label: "Прямой",
|
||||||
@ -188,7 +167,7 @@ export const StationCreate = () => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
value={`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
|
value={coordinates}
|
||||||
onChange={handleCoordinatesChange}
|
onChange={handleCoordinatesChange}
|
||||||
error={!!(errors as any)?.latitude}
|
error={!!(errors as any)?.latitude}
|
||||||
helperText={(errors as any)?.latitude?.message}
|
helperText={(errors as any)?.latitude?.message}
|
||||||
@ -198,10 +177,11 @@ export const StationCreate = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
label={"Координаты *"}
|
label={"Координаты *"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("latitude", {
|
{...register("latitude", {
|
||||||
value: coordinatesPreview.latitude,
|
value: coordinates.split(",")[0],
|
||||||
setValueAs: (value) => {
|
setValueAs: (value) => {
|
||||||
if (value === "") {
|
if (value === "") {
|
||||||
return 0;
|
return 0;
|
||||||
@ -213,7 +193,7 @@ export const StationCreate = () => {
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("longitude", {
|
{...register("longitude", {
|
||||||
value: coordinatesPreview.longitude,
|
value: coordinates.split(",")[1],
|
||||||
setValueAs: (value) => {
|
setValueAs: (value) => {
|
||||||
if (value === "") {
|
if (value === "") {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -40,24 +40,24 @@ export const StationEdit = observer(() => {
|
|||||||
system_name: "",
|
system_name: "",
|
||||||
description: "",
|
description: "",
|
||||||
address: "",
|
address: "",
|
||||||
latitude: "",
|
latitude: 0,
|
||||||
longitude: "",
|
longitude: 0,
|
||||||
},
|
},
|
||||||
en: {
|
en: {
|
||||||
name: "",
|
name: "",
|
||||||
system_name: "",
|
system_name: "",
|
||||||
description: "",
|
description: "",
|
||||||
address: "",
|
address: "",
|
||||||
latitude: "",
|
latitude: 0,
|
||||||
longitude: "",
|
longitude: 0,
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
name: "",
|
name: "",
|
||||||
system_name: "",
|
system_name: "",
|
||||||
description: "",
|
description: "",
|
||||||
address: "",
|
address: "",
|
||||||
latitude: "",
|
latitude: 0,
|
||||||
longitude: "",
|
longitude: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -69,8 +69,8 @@ export const StationEdit = observer(() => {
|
|||||||
system_name: watch("system_name") ?? "",
|
system_name: watch("system_name") ?? "",
|
||||||
description: watch("description") ?? "",
|
description: watch("description") ?? "",
|
||||||
address: watch("address") ?? "",
|
address: watch("address") ?? "",
|
||||||
latitude: watch("latitude") ?? "",
|
latitude: Number(watch("latitude")) || 0,
|
||||||
longitude: watch("longitude") ?? "",
|
longitude: Number(watch("longitude")) || 0,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@ -120,7 +120,7 @@ export const StationEdit = observer(() => {
|
|||||||
if (stationData[language as keyof typeof stationData]?.name) {
|
if (stationData[language as keyof typeof stationData]?.name) {
|
||||||
setValue("name", stationData[language as keyof typeof stationData]?.name);
|
setValue("name", stationData[language as keyof typeof stationData]?.name);
|
||||||
}
|
}
|
||||||
if (stationData[language as keyof typeof stationData]?.address) {
|
if (stationData[language as keyof typeof stationData]?.system_name) {
|
||||||
setValue(
|
setValue(
|
||||||
"system_name",
|
"system_name",
|
||||||
stationData[language as keyof typeof stationData]?.system_name || ""
|
stationData[language as keyof typeof stationData]?.system_name || ""
|
||||||
@ -132,16 +132,20 @@ export const StationEdit = observer(() => {
|
|||||||
stationData[language as keyof typeof stationData]?.description || ""
|
stationData[language as keyof typeof stationData]?.description || ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (stationData[language as keyof typeof stationData]?.latitude) {
|
if (
|
||||||
|
stationData[language as keyof typeof stationData]?.latitude !== undefined
|
||||||
|
) {
|
||||||
setValue(
|
setValue(
|
||||||
"latitude",
|
"latitude",
|
||||||
stationData[language as keyof typeof stationData]?.latitude || ""
|
stationData[language as keyof typeof stationData]?.latitude || 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (stationData[language as keyof typeof stationData]?.longitude) {
|
if (
|
||||||
|
stationData[language as keyof typeof stationData]?.longitude !== undefined
|
||||||
|
) {
|
||||||
setValue(
|
setValue(
|
||||||
"longitude",
|
"longitude",
|
||||||
stationData[language as keyof typeof stationData]?.longitude || ""
|
stationData[language as keyof typeof stationData]?.longitude || 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, [language, stationData, setValue]);
|
}, [language, stationData, setValue]);
|
||||||
@ -150,28 +154,36 @@ export const StationEdit = observer(() => {
|
|||||||
setLanguageAction("ru");
|
setLanguageAction("ru");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { id: stationId } = useParams<{ id: string }>();
|
const [coordinates, setCoordinates] = useState("");
|
||||||
|
|
||||||
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const { id: stationId } = useParams<{ id: string }>();
|
||||||
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 latitudeContent = watch("latitude");
|
||||||
const longitudeContent = watch("longitude");
|
const longitudeContent = watch("longitude");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCoordinatesPreview({
|
if (latitudeContent && longitudeContent) {
|
||||||
latitude: latitudeContent || "",
|
setCoordinates(`${latitudeContent} ${longitudeContent}`);
|
||||||
longitude: longitudeContent || "",
|
}
|
||||||
});
|
|
||||||
}, [latitudeContent, longitudeContent]);
|
}, [latitudeContent, longitudeContent]);
|
||||||
|
|
||||||
|
const handleCoordinatesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setCoordinates(e.target.value);
|
||||||
|
if (e.target.value) {
|
||||||
|
const [lat, lon] = e.target.value
|
||||||
|
.replace(/,/g, "") // Remove all commas from the string
|
||||||
|
.split(" ")
|
||||||
|
.map((s) => s.trim());
|
||||||
|
setCoordinates(`${lat ?? 0} ${lon ?? 0}`);
|
||||||
|
setValue("latitude", lat ?? 0);
|
||||||
|
setValue("longitude", lon ?? 0);
|
||||||
|
} else {
|
||||||
|
setCoordinates("");
|
||||||
|
setValue("latitude", "");
|
||||||
|
setValue("longitude", "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
||||||
resource: "city",
|
resource: "city",
|
||||||
onSearch: (value) => [
|
onSearch: (value) => [
|
||||||
@ -282,7 +294,7 @@ export const StationEdit = observer(() => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
value={`${coordinatesPreview.latitude}, ${coordinatesPreview.longitude}`}
|
value={coordinates}
|
||||||
onChange={handleCoordinatesChange}
|
onChange={handleCoordinatesChange}
|
||||||
error={!!(errors as any)?.latitude}
|
error={!!(errors as any)?.latitude}
|
||||||
helperText={(errors as any)?.latitude?.message}
|
helperText={(errors as any)?.latitude?.message}
|
||||||
@ -295,12 +307,28 @@ export const StationEdit = observer(() => {
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("latitude", {
|
{...register("latitude", {
|
||||||
value: coordinatesPreview.latitude,
|
valueAsNumber: true,
|
||||||
|
value: Number(coordinates.split(" ")[0]),
|
||||||
|
setValueAs: (value) => {
|
||||||
|
if (value === "") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Number(value);
|
||||||
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
{...register("longitude", { value: coordinatesPreview.longitude })}
|
{...register("longitude", {
|
||||||
|
valueAsNumber: true,
|
||||||
|
value: Number(coordinates.split(" ")[1]),
|
||||||
|
setValueAs: (value) => {
|
||||||
|
if (value === "") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Number(value);
|
||||||
|
},
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
|
@ -104,6 +104,7 @@ export const VehicleList = observer(() => {
|
|||||||
type: "string",
|
type: "string",
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
flex: 1,
|
||||||
align: "left",
|
align: "left",
|
||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
renderCell: (params) => {
|
renderCell: (params) => {
|
||||||
@ -116,6 +117,7 @@ export const VehicleList = observer(() => {
|
|||||||
headerName: "Город",
|
headerName: "Город",
|
||||||
type: "string",
|
type: "string",
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
|
flex: 1,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
align: "left",
|
align: "left",
|
||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
|
Loading…
Reference in New Issue
Block a user