Latest version #12
| @@ -162,9 +162,7 @@ export const CreateSightArticle = ({ | ||||
|  | ||||
|       // Получаем существующие статьи для определения порядкового номера | ||||
|       const existingItemsResponse = await axiosInstance.get( | ||||
|         `${ | ||||
|           import.meta.env.VITE_KRBL_API | ||||
|         }/${parentResource}/${parentId}/${childResource}` | ||||
|         `${import.meta.env.VITE_KRBL_API}/${parentResource}/${parentId}/${childResource}` | ||||
|       ); | ||||
|       const existingItems = existingItemsResponse.data ?? []; | ||||
|       const nextPageNum = existingItems.length + 1; | ||||
| @@ -172,14 +170,26 @@ export const CreateSightArticle = ({ | ||||
|       if (!left) { | ||||
|         // Привязываем статью к достопримечательности если она не левая | ||||
|         await axiosInstance.post( | ||||
|           `${ | ||||
|             import.meta.env.VITE_KRBL_API | ||||
|           }/${parentResource}/${parentId}/${childResource}/`, | ||||
|           `${import.meta.env.VITE_KRBL_API}/${parentResource}/${parentId}/${childResource}/`, | ||||
|           { | ||||
|             [`${childResource}_id`]: itemId, | ||||
|             page_num: nextPageNum, | ||||
|           } | ||||
|         ); | ||||
|       } else { | ||||
|         const response = await axiosInstance.get( | ||||
|           `${import.meta.env.VITE_KRBL_API}/${parentResource}/${parentId}/` | ||||
|         ); | ||||
|         const data = response.data; | ||||
|         if(data) { | ||||
|           await axiosInstance.patch( | ||||
|             `${import.meta.env.VITE_KRBL_API}/${parentResource}/${parentId}/`, | ||||
|             { | ||||
|               ...data, | ||||
|               left_article: itemId | ||||
|             } | ||||
|           ); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Загружаем все медиа файлы и получаем их ID | ||||
| @@ -220,7 +230,7 @@ export const CreateSightArticle = ({ | ||||
|   }; | ||||
|  | ||||
|   return ( | ||||
|     <Box component="form" onSubmit={handleSubmitItem(handleCreate)}> | ||||
|     <Box> | ||||
|       <TextField | ||||
|         {...registerItem("heading", { | ||||
|           required: "Это поле является обязательным", | ||||
| @@ -335,7 +345,7 @@ export const CreateSightArticle = ({ | ||||
|       </Box> | ||||
|  | ||||
|       <Box sx={{ mt: 2, display: "flex", gap: 2 }}> | ||||
|         <Button variant="contained" color="primary" type="submit"> | ||||
|         <Button variant="contained" color="primary" onClick={handleSubmitItem(handleCreate)}> | ||||
|           Создать | ||||
|         </Button> | ||||
|         <Button | ||||
|   | ||||
| @@ -69,6 +69,7 @@ type LinkedItemsProps<T> = { | ||||
|   dontRecurse?: boolean; | ||||
|   disableCreation?: boolean; | ||||
|   updatedLinkedItems?: T[]; | ||||
|   refresh?: number; | ||||
| }; | ||||
|  | ||||
| const reorder = (list: any[], startIndex: number, endIndex: number) => { | ||||
| @@ -126,7 +127,8 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any } | ||||
|   type, | ||||
|   onUpdate, | ||||
|   disableCreation = false, | ||||
|   updatedLinkedItems | ||||
|   updatedLinkedItems, | ||||
|   refresh | ||||
| }: LinkedItemsProps<T>) => { | ||||
|   const { language } = languageStore; | ||||
|   const { setArticleModalOpenAction, setArticleIdAction } = articleStore; | ||||
| @@ -207,7 +209,7 @@ export const LinkedItemsContents = <T extends { id: number; [key: string]: any } | ||||
|           setLinkedItems([]); | ||||
|         }); | ||||
|     } | ||||
|   }, [parentId, parentResource, childResource, language]); | ||||
|   }, [parentId, parentResource, childResource, language, refresh]); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     if (type === "edit") { | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import "easymde/dist/easymde.min.css"; | ||||
| import { memo, useMemo, useEffect, useCallback, useState } from "react"; | ||||
| import { MarkdownEditor } from "../../MarkdownEditor"; | ||||
| import { Edit } from "@refinedev/mui"; | ||||
| import { languageStore } from "../../../store/LanguageStore"; | ||||
| import { EVERY_LANGUAGE, languageStore } from "../../../store/LanguageStore"; | ||||
| import { LanguageSwitch } from "../../LanguageSwitch/index"; | ||||
| import { useDropzone } from "react-dropzone"; | ||||
| import { | ||||
| @@ -24,7 +24,7 @@ type MediaFile = { | ||||
|   file: File; | ||||
|   preview: string; | ||||
|   uploading: boolean; | ||||
|   mediaId?: number; | ||||
|   media_id?: number; | ||||
| }; | ||||
|  | ||||
| const style = { | ||||
| @@ -42,26 +42,18 @@ const style = { | ||||
| }; | ||||
|  | ||||
| export const ArticleEditModal = observer(() => { | ||||
|   const { language } = languageStore; | ||||
|   const [articleData, setArticleData] = useState({ | ||||
|     ru: { | ||||
|       heading: "", | ||||
|       body: "", | ||||
|     }, | ||||
|     en: { | ||||
|       heading: "", | ||||
|       body: "", | ||||
|     }, | ||||
|     zh: { | ||||
|       heading: "", | ||||
|       body: "", | ||||
|     }, | ||||
|     heading: EVERY_LANGUAGE(language), | ||||
|     body: EVERY_LANGUAGE(language), | ||||
|   }); | ||||
|   const { articleModalOpen, setArticleModalOpenAction, selectedArticleId } = | ||||
|     articleStore; | ||||
|   const { language } = languageStore; | ||||
|  | ||||
|   const [mediaFiles, setMediaFiles] = useState<MediaFile[]>([]); | ||||
|  | ||||
|   const [refresh, setRefresh] = useState(0); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     return () => { | ||||
|       setArticleModalOpenAction(false); | ||||
| @@ -103,6 +95,7 @@ export const ArticleEditModal = observer(() => { | ||||
|         ); | ||||
|  | ||||
|         setMediaFiles(mediaFiles); | ||||
|         setRefresh(refresh+1); | ||||
|       } catch (error) { | ||||
|         console.error("Error loading existing media:", error); | ||||
|       } | ||||
| @@ -131,7 +124,8 @@ export const ArticleEditModal = observer(() => { | ||||
|       onMutationSuccess: async () => { | ||||
|         try { | ||||
|           // Upload new media files | ||||
|           const newMediaFiles = mediaFiles.filter((file) => !file.mediaId); | ||||
|           const newMediaFiles = mediaFiles.filter((file) => !file.media_id); | ||||
|           const existingMediaAmount = mediaFiles.filter((file) => file.media_id).length; | ||||
|           const mediaIds = await Promise.all( | ||||
|             newMediaFiles.map(async (mediaFile) => { | ||||
|               return await uploadMedia(mediaFile); | ||||
| @@ -147,7 +141,7 @@ export const ArticleEditModal = observer(() => { | ||||
|                 }/article/${selectedArticleId}/media/`, | ||||
|                 { | ||||
|                   media_id: mediaId, | ||||
|                   media_order: index + 1, | ||||
|                   media_order: index + existingMediaAmount + 1, | ||||
|                 } | ||||
|               ) | ||||
|             ) | ||||
| @@ -169,27 +163,25 @@ export const ArticleEditModal = observer(() => { | ||||
|   }); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     if (articleData[language as keyof typeof articleData]?.heading) { | ||||
|       setValue( | ||||
|         "heading", | ||||
|         articleData[language as keyof typeof articleData]?.heading || "" | ||||
|       ); | ||||
|     if (articleData.heading[language]) { | ||||
|       setValue("heading", articleData.heading[language]) | ||||
|     } | ||||
|     if (articleData[language as keyof typeof articleData]?.body) { | ||||
|       setValue( | ||||
|         "body", | ||||
|         articleData[language as keyof typeof articleData]?.body || "" | ||||
|       ); | ||||
|     if (articleData.body[language]) { | ||||
|       setValue("body", articleData.body[language]) | ||||
|     } | ||||
|   }, [language, articleData, setValue]); | ||||
|  | ||||
|   const handleLanguageChange = () => { | ||||
|     setArticleData((prevData) => ({ | ||||
|       ...prevData, | ||||
|       [language]: { | ||||
|         heading: watch("heading") || "", | ||||
|         body: watch("body") || "", | ||||
|       heading: { | ||||
|         ...prevData.heading, | ||||
|         [language]: watch("heading") ?? "" | ||||
|       }, | ||||
|       body: { | ||||
|         ...prevData.body, | ||||
|         [language]: watch("body") ?? "" | ||||
|       } | ||||
|     })); | ||||
|   }; | ||||
|  | ||||
| @@ -240,10 +232,10 @@ export const ArticleEditModal = observer(() => { | ||||
|     const mediaFile = mediaFiles[index]; | ||||
|  | ||||
|     // If it's an existing media file (has mediaId), delete it from the server | ||||
|     if (mediaFile.mediaId) { | ||||
|     if (mediaFile.media_id) { | ||||
|       try { | ||||
|         await axiosInstance.delete( | ||||
|           `${import.meta.env.VITE_KRBL_API}/media/${mediaFile.mediaId}` | ||||
|           `${import.meta.env.VITE_KRBL_API}/media/${mediaFile.media_id}` | ||||
|         ); | ||||
|       } catch (error) { | ||||
|         console.error("Error deleting media:", error); | ||||
|   | ||||
| @@ -13,7 +13,7 @@ export function MediaView({media} : Readonly<{media?: MediaData}>) { | ||||
| 	const token = localStorage.getItem(TOKEN_KEY); | ||||
| 	return ( | ||||
| 		<Box | ||||
| 			sx={{maxHeight: "300px", width: "100%", display: "flex", justifyContent: "center"}}		 | ||||
| 			sx={{maxHeight: "300px", width: "100%", display: "flex", flexGrow: 1, justifyContent: "center"}}		 | ||||
| 		> | ||||
| 			{media?.media_type === 1 && ( | ||||
| 			<img | ||||
|   | ||||
| @@ -23,8 +23,6 @@ export const ArticleEdit = observer(() => { | ||||
|     body: EVERY_LANGUAGE("") | ||||
|   }); | ||||
|   const { id: articleId } = useParams<{ id: string }>(); | ||||
|   const [preview, setPreview] = useState(""); | ||||
|   const [headingPreview, setHeadingPreview] = useState(""); | ||||
|   const simpleMDEOptions = useMemo( | ||||
|     () => ({ | ||||
|       placeholder: "Введите контент в формате Markdown...", | ||||
| @@ -42,6 +40,7 @@ export const ArticleEdit = observer(() => { | ||||
|     watch, | ||||
|     formState: { errors }, | ||||
|     setValue, | ||||
|     getValues, | ||||
|   } = useForm<{ heading: string; body: string }>({ | ||||
|     refineCoreProps: META_LANGUAGE(language) | ||||
|   }); | ||||
| @@ -50,15 +49,21 @@ export const ArticleEdit = observer(() => { | ||||
|   const headingContent = watch("heading"); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     setValue("heading", articleData.heading[language] ?? ""); | ||||
|     setHeadingPreview(articleData.heading[language] ?? ""); | ||||
|     setValue("body", articleData.body[language] ?? ""); | ||||
|     setPreview(articleData.body[language] ?? ""); | ||||
|   }, [language, articleData, setValue]); | ||||
|     console.log(articleData) | ||||
|   }, [articleData]) | ||||
|  | ||||
|   useEffect(() => { | ||||
|     console.log("Trying to udpate") | ||||
|     //setHeadingPreview(articleData.heading[language] ?? ""); | ||||
|     //setPreview(articleData.body[language] ?? ""); | ||||
|     if(articleData.heading[language]) | ||||
|       setValue("heading", articleData.heading[language]); | ||||
|     if(articleData.body[language]) | ||||
|       setValue("body", articleData.body[language]); | ||||
|   }, [language]); | ||||
|  | ||||
|   function updateTranslations(update: boolean = true) { | ||||
|     const newArticleData = { | ||||
|       ...articleData, | ||||
|       heading: { | ||||
|         ...articleData.heading, | ||||
|         [language]: watch("heading") ?? "", | ||||
| @@ -75,25 +80,16 @@ export const ArticleEdit = observer(() => { | ||||
|   const handleLanguageChange = (lang: Languages) => { | ||||
|     updateTranslations(); | ||||
|     setLanguageAction(lang); | ||||
|     console.log("Setting preview to", articleData.body[lang] ?? "") | ||||
|   }; | ||||
|  | ||||
|   const handleFormSubmit = handleSubmit((values: FieldValues) => { | ||||
|     const newTranslations = updateTranslations(false); | ||||
|     console.log(newTranslations); | ||||
|     return onFinish({ | ||||
|       translations: newTranslations | ||||
|       translations: updateTranslations(false) | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     setPreview(bodyContent ?? ""); | ||||
|   }, [bodyContent]); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     setHeadingPreview(headingContent ?? ""); | ||||
|   }, [headingContent]); | ||||
|  | ||||
|   const { data: mediaData } = useList<MediaItem>({ | ||||
|   const { data: mediaData, refetch } = useList<MediaItem>({ | ||||
|     resource: `article/${articleId}/media`, | ||||
|   }); | ||||
|  | ||||
| @@ -156,6 +152,7 @@ export const ArticleEdit = observer(() => { | ||||
|                 childResource="media" | ||||
|                 fields={mediaFields} | ||||
|                 title="медиа" | ||||
|                 onUpdate={refetch} | ||||
|               /> | ||||
|             )} | ||||
|           </Box> | ||||
| @@ -191,7 +188,7 @@ export const ArticleEdit = observer(() => { | ||||
|               mb: 3, | ||||
|             }} | ||||
|           > | ||||
|             {headingPreview} | ||||
|             {headingContent} | ||||
|           </Typography> | ||||
|  | ||||
|           {/* Markdown контент */} | ||||
| @@ -235,7 +232,7 @@ export const ArticleEdit = observer(() => { | ||||
|               }, | ||||
|             }} | ||||
|           > | ||||
|             <ReactMarkdown>{preview}</ReactMarkdown> | ||||
|             <ReactMarkdown>{bodyContent}</ReactMarkdown> | ||||
|           </Box> | ||||
|  | ||||
|           {/* Привязанные медиа */} | ||||
| @@ -256,8 +253,10 @@ export const ArticleEdit = observer(() => { | ||||
|                   <Box | ||||
|                     key={media.id} | ||||
|                     sx={{ | ||||
|                       width: 120, | ||||
|                       height: 120, | ||||
|                       display: "flex", | ||||
|                       width: "45%", | ||||
|                       height: "45%", | ||||
|                       aspectRatio: "1/1", | ||||
|                       borderRadius: 1, | ||||
|                       overflow: "hidden", | ||||
|                       border: "1px solid", | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import { Create, useAutocomplete } from "@refinedev/mui"; | ||||
| import { useForm } from "@refinedev/react-hook-form"; | ||||
| import { Controller } from "react-hook-form"; | ||||
| import { observer } from "mobx-react-lite"; | ||||
| import { languageStore } from "../../store/LanguageStore"; | ||||
| import { languageStore, META_LANGUAGE } from "../../store/LanguageStore"; | ||||
| export const CarrierCreate = observer(() => { | ||||
|   const { language } = languageStore; | ||||
|   const { | ||||
| @@ -13,13 +13,7 @@ export const CarrierCreate = observer(() => { | ||||
|     control, | ||||
|     formState: { errors }, | ||||
|   } = useForm({ | ||||
|     refineCoreProps: { | ||||
|       meta: { | ||||
|         headers: { | ||||
|           "Accept-Language": language, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     refineCoreProps: META_LANGUAGE(language) | ||||
|   }); | ||||
|  | ||||
|   const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({ | ||||
|   | ||||
| @@ -39,7 +39,7 @@ export const CarrierEdit = observer(() => { | ||||
|         value, | ||||
|       }, | ||||
|     ], | ||||
|     ...META_LANGUAGE(language) | ||||
|     ...META_LANGUAGE("ru") | ||||
|   }); | ||||
|  | ||||
|  | ||||
| @@ -233,7 +233,8 @@ export const CarrierEdit = observer(() => { | ||||
|                 return options.filter((option) => | ||||
|                   option.media_name | ||||
|                     .toLowerCase() | ||||
|                     .includes(inputValue.toLowerCase()) | ||||
|                     .includes(inputValue.toLowerCase()) && | ||||
|                   option.media_type == 3 | ||||
|                 ); | ||||
|               }} | ||||
|               renderInput={(params) => ( | ||||
|   | ||||
| @@ -34,6 +34,23 @@ export const RouteCreate = () => { | ||||
|     ], | ||||
|   }); | ||||
|  | ||||
|   const { autocompleteProps: governorAppealAutocompleteProps } = useAutocomplete({ | ||||
|     resource: "article", | ||||
|  | ||||
|     onSearch: (value) => [ | ||||
|       { | ||||
|         field: "heading", | ||||
|         operator: "contains", | ||||
|         value, | ||||
|       }, | ||||
|       { | ||||
|         field: "media_type", | ||||
|         operator: "contains", | ||||
|         value, | ||||
|       }, | ||||
|     ] | ||||
|   }); | ||||
|  | ||||
|   return ( | ||||
|     <Create isLoading={formLoading} saveButtonProps={saveButtonProps}> | ||||
|       <Box | ||||
| @@ -94,7 +111,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.route_number?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="text" | ||||
|           label={"Номер маршрута *"} | ||||
|           name="route_number" | ||||
| @@ -174,7 +191,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.path?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="text" | ||||
|           label={"Координаты маршрута *"} | ||||
|           name="path" | ||||
| @@ -192,26 +209,54 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.route_sys_number?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="number" | ||||
|           label={"Системный номер маршрута *"} | ||||
|           name="route_sys_number" | ||||
|         /> | ||||
|  | ||||
|         <TextField | ||||
|           {...register("governor_appeal", { | ||||
|             // required: 'Это поле является обязательным', | ||||
|             setValueAs: (value) => Number(value), | ||||
|           })} | ||||
|           error={!!(errors as any)?.governor_appeal} | ||||
|           helperText={(errors as any)?.governor_appeal?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           type="number" | ||||
|           label={"Обращение губернатора"} | ||||
|         <Controller | ||||
|           control={control} | ||||
|           name="governor_appeal" | ||||
|         /> | ||||
|           defaultValue={null} | ||||
|           render={({ field }) => ( | ||||
|             <Autocomplete | ||||
|               {...governorAppealAutocompleteProps} | ||||
|               value={ | ||||
|                 governorAppealAutocompleteProps.options.find( | ||||
|                   (option) => option.id === field.value | ||||
|                 ) ?? null | ||||
|               } | ||||
|               onChange={(_, value) => { | ||||
|                 field.onChange(value?.id ?? ""); | ||||
|               }} | ||||
|               getOptionLabel={(item) => { | ||||
|                 return item ? item.heading : ""; | ||||
|               }} | ||||
|               isOptionEqualToValue={(option, value) => { | ||||
|                 return option.id === value?.id; | ||||
|               }} | ||||
|               filterOptions={(options, { inputValue }) => { | ||||
|                 return options.filter((option) => | ||||
|                   option.heading | ||||
|                     .toLowerCase() | ||||
|                     .includes(inputValue.toLowerCase()) | ||||
|                 ); | ||||
|               }} | ||||
|               renderInput={(params) => ( | ||||
|                 <TextField | ||||
|                   {...params} | ||||
|                   label="Обращение губернатора" | ||||
|                   margin="normal" | ||||
|                   variant="outlined" | ||||
|                   error={!!errors.arms} | ||||
|                   helperText={(errors as any)?.arms?.message} | ||||
|                   required | ||||
|                 /> | ||||
|               )} | ||||
|             /> | ||||
|           )} | ||||
|           /> | ||||
|  | ||||
|         <TextField | ||||
|           {...register("scale_min", { | ||||
| @@ -222,7 +267,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.scale_min?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="number" | ||||
|           label={"Масштаб (мин)"} | ||||
|           name="scale_min" | ||||
| @@ -237,7 +282,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.scale_max?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="number" | ||||
|           label={"Масштаб (макс)"} | ||||
|           name="scale_max" | ||||
| @@ -252,7 +297,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.rotate?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="number" | ||||
|           label={"Поворот"} | ||||
|           name="rotate" | ||||
| @@ -267,7 +312,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.center_latitude?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="number" | ||||
|           label={"Центр. широта"} | ||||
|           name="center_latitude" | ||||
| @@ -282,7 +327,7 @@ export const RouteCreate = () => { | ||||
|           helperText={(errors as any)?.center_longitude?.message} | ||||
|           margin="normal" | ||||
|           fullWidth | ||||
|           InputLabelProps={{ shrink: true }} | ||||
|           slotProps={{inputLabel: {shrink: true}}} | ||||
|           type="number" | ||||
|           label={"Центр. долгота"} | ||||
|           name="center_longitude" | ||||
|   | ||||
| @@ -19,8 +19,12 @@ import { | ||||
|   vehicleFields, | ||||
| } from "./types"; | ||||
| import { useEffect } from "react"; | ||||
| import { META_LANGUAGE, languageStore } from "@stores"; | ||||
| import { observer } from "mobx-react-lite"; | ||||
| import { LanguageSelector } from "@ui"; | ||||
|  | ||||
| export const RouteEdit = () => { | ||||
| export const RouteEdit = observer(() => { | ||||
|   const { language } = languageStore; | ||||
|   const { | ||||
|     saveButtonProps, | ||||
|     register, | ||||
| @@ -29,7 +33,9 @@ export const RouteEdit = () => { | ||||
|     refineCore: { queryResult }, | ||||
|     setValue, | ||||
|     watch, | ||||
|   } = useForm({}); | ||||
|   } = useForm({ | ||||
|     refineCoreProps: META_LANGUAGE(language) | ||||
|   }); | ||||
|   const navigate = useNavigate(); | ||||
|  | ||||
|   const { id: routeId } = useParams<{ id: string }>(); | ||||
| @@ -53,6 +59,7 @@ export const RouteEdit = () => { | ||||
|         value, | ||||
|       }, | ||||
|     ], | ||||
|     ...META_LANGUAGE(language) | ||||
|   }); | ||||
|  | ||||
|   const { autocompleteProps: governorAppealAutocompleteProps } = useAutocomplete({ | ||||
| @@ -69,7 +76,8 @@ export const RouteEdit = () => { | ||||
|         operator: "contains", | ||||
|         value, | ||||
|       }, | ||||
|     ] | ||||
|     ], | ||||
|     ...META_LANGUAGE(language) | ||||
|   }); | ||||
|  | ||||
|   return ( | ||||
| @@ -82,6 +90,7 @@ export const RouteEdit = () => { | ||||
|           sx={{ display: "flex", flexDirection: "column"}} | ||||
|           autoComplete="off" | ||||
|         > | ||||
|           <LanguageSelector /> | ||||
|           <Controller | ||||
|             control={control} | ||||
|             name="carrier_id" | ||||
| @@ -393,4 +402,4 @@ export const RouteEdit = () => { | ||||
|       </Box> | ||||
|     </Edit> | ||||
|   ); | ||||
| }; | ||||
| }); | ||||
|   | ||||
| @@ -13,11 +13,15 @@ import MapIcon from '@mui/icons-material/Map'; | ||||
|  | ||||
| import { localeText } from "../../locales/ru/localeText"; | ||||
| import { useLink } from "@refinedev/core"; | ||||
| import { observer } from "mobx-react-lite"; | ||||
| import { languageStore, META_LANGUAGE } from "@stores"; | ||||
|  | ||||
| export const RouteList = () => { | ||||
| export const RouteList = observer(() => { | ||||
|   const Link = useLink(); | ||||
|   const { language } = languageStore;  | ||||
|   const { dataGridProps } = useDataGrid({ | ||||
|     resource: "route/", | ||||
|     meta: META_LANGUAGE(language) | ||||
|   }); | ||||
|  | ||||
|   const columns = React.useMemo<GridColDef[]>( | ||||
| @@ -177,7 +181,8 @@ export const RouteList = () => { | ||||
|         columns={columns} | ||||
|         localeText={localeText} | ||||
|         getRowId={(row: any) => row.id} | ||||
|         languageEnabled | ||||
|       /> | ||||
|     </List> | ||||
|   ); | ||||
| }; | ||||
| }); | ||||
|   | ||||
| @@ -11,8 +11,9 @@ import { | ||||
|   vehicleFields, | ||||
| } from "./types"; | ||||
| import { useNavigate, useParams } from "react-router"; | ||||
| import { observer } from "mobx-react-lite"; | ||||
|  | ||||
| export const RouteShow = () => { | ||||
| export const RouteShow = observer(() => { | ||||
|   const { query } = useShow({}); | ||||
|   const { data, isLoading } = query; | ||||
|   const record = data?.data; | ||||
| @@ -115,4 +116,4 @@ export const RouteShow = () => { | ||||
|       </Stack> | ||||
|     </Show> | ||||
|   ); | ||||
| }; | ||||
| }); | ||||
|   | ||||
| @@ -76,6 +76,7 @@ export const SightEdit = observer(() => { | ||||
|     formState: { errors }, | ||||
|   } = useForm({ | ||||
|     refineCoreProps: META_LANGUAGE(language), | ||||
|     warnWhenUnsavedChanges: false | ||||
|   }); | ||||
|  | ||||
|   const getMedia = async (id?: string | number) => { | ||||
| @@ -119,6 +120,7 @@ export const SightEdit = observer(() => { | ||||
|   }>(); | ||||
|  | ||||
|   const [tabValue, setTabValue] = useState(0); | ||||
|  | ||||
|   const { autocompleteProps: mediaAutocompleteProps } = useAutocomplete({ | ||||
|     resource: "media", | ||||
|     onSearch: (value) => [ | ||||
| @@ -144,7 +146,8 @@ export const SightEdit = observer(() => { | ||||
|         operator: "contains", | ||||
|         value, | ||||
|       }, | ||||
|     ] | ||||
|     ], | ||||
|  | ||||
|   }); | ||||
|  | ||||
|   useEffect(() => { | ||||
| @@ -216,13 +219,6 @@ export const SightEdit = observer(() => { | ||||
|   const watermarkLUContent = watch("watermark_lu"); | ||||
|   const watermarkRDContent = watch("watermark_rd"); | ||||
|  | ||||
|  | ||||
|   // useEffect(() => { | ||||
|   //   return () => { | ||||
|   //     setLanguageAction("ru"); | ||||
|   //   }; | ||||
|   // }, []); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     setCoordinatesPreview({ | ||||
|       latitude: latitudeContent ?? "", | ||||
| @@ -290,7 +286,7 @@ export const SightEdit = observer(() => { | ||||
|         media, | ||||
|       }); | ||||
|     }); | ||||
|   }, [leftArticleId]); | ||||
|   }, [leftArticleId, articleAutocompleteProps.loading]); | ||||
|  | ||||
|   function updateTranslations(update: boolean = true) { | ||||
|     const newSightData = { | ||||
| @@ -621,18 +617,48 @@ export const SightEdit = observer(() => { | ||||
|                     Редактировать выбранную левую статью | ||||
|                   </Button> | ||||
|                 ) : ( | ||||
|                   <Link to="/article/create"> | ||||
|                     <Button | ||||
|                       variant="outlined" | ||||
|                       size="large" | ||||
|                   <> | ||||
|                     <Typography | ||||
|                       variant="h6" | ||||
|                       gutterBottom | ||||
|                       px={2} | ||||
|                       py={.5} | ||||
|                        | ||||
|                       sx={{ | ||||
|                         width: "100%", | ||||
|                         color: "text.primary" | ||||
|                       }} | ||||
|                       color="secondary" | ||||
|                     > | ||||
|                       Создать новую статью | ||||
|                     </Button> | ||||
|                   </Link> | ||||
|                     Создать и прикрепить новую статью: | ||||
|                     </Typography> | ||||
|                     <CreateSightArticle | ||||
|                       language={language} | ||||
|                       parentId={sightId!} | ||||
|                       parentResource="sight" | ||||
|                       childResource="article" | ||||
|                       title="статью" | ||||
|                       left | ||||
|                       setHeadingParent={(heading) => { | ||||
|                         //console.log("Updating", heading) | ||||
|                         setCreatingArticleHeading(heading); | ||||
|                       }} | ||||
|                       setBodyParent={(body) => { | ||||
|                         setCreatingArticleBody(body); | ||||
|                       }} | ||||
|                     /> | ||||
|                   </> | ||||
|                    | ||||
|                   // <Link to="/article/create"> | ||||
|                   //   <Button | ||||
|                   //     variant="outlined" | ||||
|                   //     size="large" | ||||
|                   //     sx={{ | ||||
|                   //       width: "100%", | ||||
|                   //     }} | ||||
|                   //     color="secondary" | ||||
|                   //   > | ||||
|                   //     Создать новую статью | ||||
|                   //   </Button> | ||||
|                   // </Link> | ||||
|                 )} | ||||
|               </Box> | ||||
|             </Box> | ||||
| @@ -678,7 +704,7 @@ export const SightEdit = observer(() => { | ||||
|                   mb: 3, | ||||
|                 }} | ||||
|               > | ||||
|                 {leftArticleData?.heading} | ||||
|                 {leftArticleId ? leftArticleData?.heading : creatingArticleHeading} | ||||
|               </Typography> | ||||
|  | ||||
|               {/* Адрес */} | ||||
| @@ -706,7 +732,7 @@ export const SightEdit = observer(() => { | ||||
|                       theme.palette.mode === "dark" ? "grey.300" : "grey.800", | ||||
|                   }} | ||||
|                 > | ||||
|                   {leftArticleData?.body} | ||||
|                   {leftArticleId ? leftArticleData?.body : creatingArticleBody} | ||||
|                 </Box> | ||||
|               </Typography> | ||||
|             </Paper> | ||||
| @@ -807,7 +833,7 @@ export const SightEdit = observer(() => { | ||||
|                     }} | ||||
|                     onClick={() => setArticleAdditionMode("creating")} | ||||
|                   > | ||||
|                     Создать новую статью | ||||
|                     Создать и привязать новую статью | ||||
|                   </Box> | ||||
|                 </Box> | ||||
|               </Box> | ||||
| @@ -870,7 +896,7 @@ export const SightEdit = observer(() => { | ||||
|                   parentResource="sight" | ||||
|                   childResource="article" | ||||
|                   title="статью" | ||||
|                   left | ||||
|                   //left | ||||
|                   setHeadingParent={(heading) => { | ||||
|                     console.log("Updating", heading) | ||||
|                     setCreatingArticleHeading(heading); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user