feat: Rewrite route edit and create page for new field
				
					
				
			This commit is contained in:
		| @@ -13,7 +13,7 @@ import { | ||||
|   DialogContent, | ||||
|   DialogActions, | ||||
| } from "@mui/material"; | ||||
| import { MediaViewer } from "@widgets"; | ||||
| import { MediaViewer, VideoPreviewCard } from "@widgets"; | ||||
| import { observer } from "mobx-react-lite"; | ||||
| import { ArrowLeft, Loader2, Save, Plus } from "lucide-react"; | ||||
| import { useEffect, useState, useMemo } from "react"; | ||||
| @@ -24,9 +24,10 @@ import { articlesStore } from "../../../shared/store/ArticlesStore"; | ||||
| import { Route, routeStore } from "../../../shared/store/RouteStore"; | ||||
| import { | ||||
|   languageStore, | ||||
|   SelectArticleModal, | ||||
|   ArticleSelectOrCreateDialog, | ||||
|   SelectMediaDialog, | ||||
|   selectedCityStore, | ||||
|   UploadMediaDialog, | ||||
| } from "@shared"; | ||||
|  | ||||
| export const RouteCreatePage = observer(() => { | ||||
| @@ -39,6 +40,7 @@ export const RouteCreatePage = observer(() => { | ||||
|   const [direction, setDirection] = useState("backward"); | ||||
|   const [scaleMin, setScaleMin] = useState(""); | ||||
|   const [scaleMax, setScaleMax] = useState(""); | ||||
|   const [routeName, setRouteName] = useState(""); | ||||
|   const [turn, setTurn] = useState(""); | ||||
|   const [centerLat, setCenterLat] = useState(""); | ||||
|   const [centerLng, setCenterLng] = useState(""); | ||||
| @@ -48,6 +50,8 @@ export const RouteCreatePage = observer(() => { | ||||
|     useState(false); | ||||
|   const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false); | ||||
|   const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false); | ||||
|   const [isUploadVideoDialogOpen, setIsUploadVideoDialogOpen] = useState(false); | ||||
|   const [fileToUpload, setFileToUpload] = useState<File | null>(null); | ||||
|   const { language } = languageStore; | ||||
|  | ||||
|   useEffect(() => { | ||||
| @@ -110,6 +114,8 @@ export const RouteCreatePage = observer(() => { | ||||
|   const handleArticleSelect = (articleId: number) => { | ||||
|     setGovernorAppeal(articleId.toString()); | ||||
|     setIsSelectArticleDialogOpen(false); | ||||
|     // Обновляем список статей после создания новой | ||||
|     articlesStore.getArticleList(); | ||||
|   }; | ||||
|  | ||||
|   const handleVideoSelect = (media: { | ||||
| @@ -122,6 +128,26 @@ export const RouteCreatePage = observer(() => { | ||||
|     setIsSelectVideoDialogOpen(false); | ||||
|   }; | ||||
|  | ||||
|   const handleVideoFileSelect = (file?: File) => { | ||||
|     if (file) { | ||||
|       setFileToUpload(file); | ||||
|       setIsUploadVideoDialogOpen(true); | ||||
|     } else { | ||||
|       setIsSelectVideoDialogOpen(true); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const handleVideoUpload = (media: { | ||||
|     id: string; | ||||
|     filename: string; | ||||
|     media_name?: string; | ||||
|     media_type: number; | ||||
|   }) => { | ||||
|     setVideoPreview(media.id); | ||||
|     setIsUploadVideoDialogOpen(false); | ||||
|     setFileToUpload(null); | ||||
|   }; | ||||
|  | ||||
|   const handleVideoPreviewClick = () => { | ||||
|     setIsVideoPreviewOpen(true); | ||||
|   }; | ||||
| @@ -167,6 +193,7 @@ export const RouteCreatePage = observer(() => { | ||||
|         route_number: routeNumber, | ||||
|         route_sys_number: govRouteNumber, | ||||
|         governor_appeal, | ||||
|         route_name: routeName, | ||||
|         route_direction, | ||||
|         scale_min, | ||||
|         scale_max, | ||||
| @@ -208,6 +235,13 @@ export const RouteCreatePage = observer(() => { | ||||
|  | ||||
|       <div className="flex flex-col gap-10 w-full items-end"> | ||||
|         <Box className="flex flex-col gap-6 w-full"> | ||||
|           <TextField | ||||
|             className="w-full" | ||||
|             label="Название маршрута" | ||||
|             required | ||||
|             value={routeName} | ||||
|             onChange={(e) => setRouteName(e.target.value)} | ||||
|           /> | ||||
|           <FormControl fullWidth required> | ||||
|             <InputLabel>Выберите перевозчика</InputLabel> | ||||
|             <Select | ||||
| @@ -279,6 +313,7 @@ export const RouteCreatePage = observer(() => { | ||||
|               }, | ||||
|             }} | ||||
|           /> | ||||
|  | ||||
|           <TextField | ||||
|             className="w-full" | ||||
|             label="Номер маршрута в Говорящем Городе" | ||||
| @@ -287,99 +322,43 @@ export const RouteCreatePage = observer(() => { | ||||
|             onChange={(e) => setGovRouteNumber(e.target.value)} | ||||
|           /> | ||||
|  | ||||
|           {/* Заменяем Select на кнопку для выбора статьи */} | ||||
|           <Box className="flex flex-col gap-2"> | ||||
|             <label className="text-sm font-medium text-gray-700"> | ||||
|               Обращение к пассажирам | ||||
|             </label> | ||||
|             <Box className="flex gap-2"> | ||||
|               <TextField | ||||
|                 className="flex-1" | ||||
|                 value={selectedArticle?.heading || "Статья не выбрана"} | ||||
|                 placeholder="Выберите статью" | ||||
|                 disabled | ||||
|                 sx={{ | ||||
|                   "& .MuiInputBase-input": { | ||||
|                     color: selectedArticle ? "inherit" : "#999", | ||||
|                   }, | ||||
|                 }} | ||||
|               /> | ||||
|               <Button | ||||
|                 variant="outlined" | ||||
|                 onClick={() => setIsSelectArticleDialogOpen(true)} | ||||
|                 startIcon={<Plus size={16} />} | ||||
|                 sx={{ minWidth: "auto", px: 2 }} | ||||
|               > | ||||
|                 Выбрать | ||||
|               </Button> | ||||
|             </Box> | ||||
|           <Typography variant="subtitle1" sx={{ fontWeight: 600 }}> | ||||
|             Обращение к пассажирам | ||||
|           </Typography> | ||||
|           <Box className="flex gap-2"> | ||||
|             <TextField | ||||
|               className="flex-1" | ||||
|               value={selectedArticle?.heading || "Статья не выбрана"} | ||||
|               placeholder="Выберите статью" | ||||
|               disabled | ||||
|               fullWidth | ||||
|               sx={{ | ||||
|                 "& .MuiInputBase-input": { | ||||
|                   color: selectedArticle ? "inherit" : "#999", | ||||
|                 }, | ||||
|               }} | ||||
|             /> | ||||
|             <Button | ||||
|               variant="outlined" | ||||
|               onClick={() => setIsSelectArticleDialogOpen(true)} | ||||
|               startIcon={<Plus size={16} />} | ||||
|               sx={{ minWidth: "auto", px: 2 }} | ||||
|             > | ||||
|               Выбрать | ||||
|             </Button> | ||||
|           </Box> | ||||
|  | ||||
|           {/* Селектор видеозаставки */} | ||||
|           <Box className="flex flex-col gap-2"> | ||||
|             <label className="text-sm font-medium text-gray-700"> | ||||
|               Видеозаставка | ||||
|             </label> | ||||
|             <Box className="flex gap-2"> | ||||
|               <Box | ||||
|                 className="flex-1" | ||||
|                 onClick={handleVideoPreviewClick} | ||||
|                 sx={{ | ||||
|                   cursor: | ||||
|                     videoPreview && videoPreview !== "" ? "pointer" : "default", | ||||
|                 }} | ||||
|               > | ||||
|                 <Box | ||||
|                   className="w-full h-[50px] border border-gray-400 rounded-sm flex items-center justify-between px-4" | ||||
|                   sx={{ | ||||
|                     "& .MuiInputBase-input": { | ||||
|                       color: | ||||
|                         videoPreview && videoPreview !== "" | ||||
|                           ? "inherit" | ||||
|                           : "#999", | ||||
|                       cursor: | ||||
|                         videoPreview && videoPreview !== "" | ||||
|                           ? "pointer" | ||||
|                           : "default", | ||||
|                     }, | ||||
|                   }} | ||||
|                 > | ||||
|                   <Typography variant="body1" className="text-sm"> | ||||
|                     {videoPreview && videoPreview !== "" | ||||
|                       ? "Видео выбрано" | ||||
|                       : "Видео не выбрано"} | ||||
|                   </Typography> | ||||
|                   {videoPreview && videoPreview !== "" && ( | ||||
|                     <Box | ||||
|                       onClick={(e) => { | ||||
|                         e.stopPropagation(); | ||||
|                         setVideoPreview(""); | ||||
|                       }} | ||||
|                       sx={{ | ||||
|                         cursor: "pointer", | ||||
|                         color: "#999", | ||||
|                         "&:hover": { | ||||
|                           color: "#666", | ||||
|                         }, | ||||
|                       }} | ||||
|                     > | ||||
|                       <Typography variant="body1" className="text-lg font-bold"> | ||||
|                         × | ||||
|                       </Typography> | ||||
|                     </Box> | ||||
|                   )} | ||||
|                 </Box> | ||||
|               </Box> | ||||
|               <Button | ||||
|                 variant="outlined" | ||||
|                 onClick={() => setIsSelectVideoDialogOpen(true)} | ||||
|                 startIcon={<Plus size={16} />} | ||||
|                 sx={{ minWidth: "auto", px: 2 }} | ||||
|               > | ||||
|                 Выбрать | ||||
|               </Button> | ||||
|             </Box> | ||||
|           </Box> | ||||
|           {/* Видео-превью как на странице редактирования */} | ||||
|           <VideoPreviewCard | ||||
|             title="Видеозаставка" | ||||
|             videoId={videoPreview} | ||||
|             onVideoClick={handleVideoPreviewClick} | ||||
|             onDeleteVideoClick={() => { | ||||
|               setVideoPreview(""); | ||||
|             }} | ||||
|             onSelectVideoClick={handleVideoFileSelect} | ||||
|             className="w-full" | ||||
|           /> | ||||
|  | ||||
|           <FormControl fullWidth required> | ||||
|             <InputLabel>Прямой/обратный маршрут</InputLabel> | ||||
| @@ -404,6 +383,7 @@ export const RouteCreatePage = observer(() => { | ||||
|             value={scaleMax} | ||||
|             onChange={(e) => setScaleMax(e.target.value)} | ||||
|           /> | ||||
|  | ||||
|           <TextField | ||||
|             className="w-full" | ||||
|             label="Поворот" | ||||
| @@ -441,8 +421,8 @@ export const RouteCreatePage = observer(() => { | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       {/* Модальное окно выбора статьи */} | ||||
|       <SelectArticleModal | ||||
|       {/* Модальное окно выбора или создания статьи */} | ||||
|       <ArticleSelectOrCreateDialog | ||||
|         open={isSelectArticleDialogOpen} | ||||
|         onClose={() => setIsSelectArticleDialogOpen(false)} | ||||
|         onSelectArticle={handleArticleSelect} | ||||
| @@ -483,6 +463,20 @@ export const RouteCreatePage = observer(() => { | ||||
|           </DialogActions> | ||||
|         </Dialog> | ||||
|       )} | ||||
|  | ||||
|       {/* Модальное окно загрузки видео */} | ||||
|       <UploadMediaDialog | ||||
|         open={isUploadVideoDialogOpen} | ||||
|         onClose={() => { | ||||
|           setIsUploadVideoDialogOpen(false); | ||||
|           setFileToUpload(null); | ||||
|         }} | ||||
|         hardcodeType="video_preview" | ||||
|         contextObjectName={routeName || "Маршрут"} | ||||
|         contextType="sight" | ||||
|         initialFile={fileToUpload || undefined} | ||||
|         afterUpload={handleVideoUpload} | ||||
|       /> | ||||
|     </Paper> | ||||
|   ); | ||||
| }); | ||||
|   | ||||
| @@ -13,7 +13,7 @@ import { | ||||
|   DialogContent, | ||||
|   DialogActions, | ||||
| } from "@mui/material"; | ||||
| import { MediaViewer } from "@widgets"; | ||||
| import { MediaViewer, VideoPreviewCard } from "@widgets"; | ||||
| import { observer } from "mobx-react-lite"; | ||||
| import { ArrowLeft, Copy, Save, Plus } from "lucide-react"; | ||||
| import { useEffect, useState } from "react"; | ||||
| @@ -24,8 +24,9 @@ import { articlesStore } from "../../../shared/store/ArticlesStore"; | ||||
| import { | ||||
|   routeStore, | ||||
|   languageStore, | ||||
|   SelectArticleModal, | ||||
|   ArticleSelectOrCreateDialog, | ||||
|   SelectMediaDialog, | ||||
|   UploadMediaDialog, | ||||
| } from "@shared"; | ||||
| import { toast } from "react-toastify"; | ||||
| import { stationsStore } from "@shared"; | ||||
| @@ -40,6 +41,8 @@ export const RouteEditPage = observer(() => { | ||||
|     useState(false); | ||||
|   const [isSelectVideoDialogOpen, setIsSelectVideoDialogOpen] = useState(false); | ||||
|   const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false); | ||||
|   const [isUploadVideoDialogOpen, setIsUploadVideoDialogOpen] = useState(false); | ||||
|   const [fileToUpload, setFileToUpload] = useState<File | null>(null); | ||||
|   const { language } = languageStore; | ||||
|   const [coordinates, setCoordinates] = useState<string>(""); | ||||
|  | ||||
| @@ -125,6 +128,8 @@ export const RouteEditPage = observer(() => { | ||||
|       governor_appeal: articleId, | ||||
|     }); | ||||
|     setIsSelectArticleDialogOpen(false); | ||||
|     // Обновляем список статей после создания новой | ||||
|     articlesStore.getArticleList(); | ||||
|   }; | ||||
|  | ||||
|   const handleVideoSelect = (media: { | ||||
| @@ -139,6 +144,28 @@ export const RouteEditPage = observer(() => { | ||||
|     setIsSelectVideoDialogOpen(false); | ||||
|   }; | ||||
|  | ||||
|   const handleVideoFileSelect = (file?: File) => { | ||||
|     if (file) { | ||||
|       setFileToUpload(file); | ||||
|       setIsUploadVideoDialogOpen(true); | ||||
|     } else { | ||||
|       setIsSelectVideoDialogOpen(true); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const handleVideoUpload = (media: { | ||||
|     id: string; | ||||
|     filename: string; | ||||
|     media_name?: string; | ||||
|     media_type: number; | ||||
|   }) => { | ||||
|     routeStore.setEditRouteData({ | ||||
|       video_preview: media.id, | ||||
|     }); | ||||
|     setIsUploadVideoDialogOpen(false); | ||||
|     setFileToUpload(null); | ||||
|   }; | ||||
|  | ||||
|   const handleVideoPreviewClick = () => { | ||||
|     if (editRouteData.video_preview && editRouteData.video_preview !== "") { | ||||
|       setIsVideoPreviewOpen(true); | ||||
| @@ -164,6 +191,17 @@ export const RouteEditPage = observer(() => { | ||||
|  | ||||
|       <div className="flex flex-col gap-10 w-full items-end"> | ||||
|         <Box className="flex flex-col gap-6 w-full"> | ||||
|           <TextField | ||||
|             className="w-full" | ||||
|             label="Название маршрута" | ||||
|             required | ||||
|             value={editRouteData.route_name || ""} | ||||
|             onChange={(e) => | ||||
|               routeStore.setEditRouteData({ | ||||
|                 route_name: e.target.value, | ||||
|               }) | ||||
|             } | ||||
|           /> | ||||
|           <FormControl fullWidth required> | ||||
|             <InputLabel>Выберите перевозчика</InputLabel> | ||||
|             <Select | ||||
| @@ -279,110 +317,6 @@ export const RouteEditPage = observer(() => { | ||||
|             } | ||||
|           /> | ||||
|  | ||||
|           {/* Заменяем Select на кнопку для выбора статьи */} | ||||
|           <Box className="flex flex-col gap-2"> | ||||
|             <label className="text-sm font-medium text-gray-700"> | ||||
|               Обращение к пассажирам | ||||
|             </label> | ||||
|             <Box className="flex gap-2"> | ||||
|               <TextField | ||||
|                 className="flex-1" | ||||
|                 value={selectedArticle?.heading || "Статья не выбрана"} | ||||
|                 placeholder="Выберите статью" | ||||
|                 disabled | ||||
|                 sx={{ | ||||
|                   "& .MuiInputBase-input": { | ||||
|                     color: selectedArticle ? "inherit" : "#999", | ||||
|                   }, | ||||
|                 }} | ||||
|               /> | ||||
|               <Button | ||||
|                 variant="outlined" | ||||
|                 onClick={() => setIsSelectArticleDialogOpen(true)} | ||||
|                 startIcon={<Plus size={16} />} | ||||
|                 sx={{ minWidth: "auto", px: 2 }} | ||||
|               > | ||||
|                 Выбрать | ||||
|               </Button> | ||||
|             </Box> | ||||
|           </Box> | ||||
|  | ||||
|           {/* Селектор видеозаставки */} | ||||
|           <Box className="flex flex-col gap-2"> | ||||
|             <label className="text-sm font-medium text-gray-700"> | ||||
|               Видеозаставка | ||||
|             </label> | ||||
|             <Box className="flex gap-2"> | ||||
|               <Box | ||||
|                 className="flex-1" | ||||
|                 onClick={handleVideoPreviewClick} | ||||
|                 sx={{ | ||||
|                   cursor: | ||||
|                     editRouteData.video_preview && | ||||
|                     editRouteData.video_preview !== "" | ||||
|                       ? "pointer" | ||||
|                       : "default", | ||||
|                 }} | ||||
|               > | ||||
|                 <Box | ||||
|                   className="w-full h-[50px] border border-gray-400 rounded-sm flex items-center justify-between px-4" | ||||
|                   sx={{ | ||||
|                     "& .MuiInputBase-input": { | ||||
|                       color: | ||||
|                         editRouteData.video_preview && | ||||
|                         editRouteData.video_preview !== "" | ||||
|                           ? "inherit" | ||||
|                           : "#999", | ||||
|                       cursor: | ||||
|                         editRouteData.video_preview && | ||||
|                         editRouteData.video_preview !== "" | ||||
|                           ? "pointer" | ||||
|                           : "default", | ||||
|                     }, | ||||
|                   }} | ||||
|                 > | ||||
|                   <Typography variant="body1" className="text-sm"> | ||||
|                     {editRouteData.video_preview && | ||||
|                     editRouteData.video_preview !== "" | ||||
|                       ? "Видео выбрано" | ||||
|                       : "Видео не выбрано"} | ||||
|                   </Typography> | ||||
|                   {editRouteData.video_preview && | ||||
|                     editRouteData.video_preview !== "" && ( | ||||
|                       <Box | ||||
|                         onClick={(e) => { | ||||
|                           e.stopPropagation(); | ||||
|                           routeStore.setEditRouteData({ video_preview: "" }); | ||||
|                         }} | ||||
|                         sx={{ | ||||
|                           cursor: "pointer", | ||||
|                           color: "#999", | ||||
|                           "&:hover": { | ||||
|                             color: "#666", | ||||
|                           }, | ||||
|                         }} | ||||
|                       > | ||||
|                         <Typography | ||||
|                           variant="body1" | ||||
|                           className="text-lg font-bold" | ||||
|                         > | ||||
|                           × | ||||
|                         </Typography> | ||||
|                       </Box> | ||||
|                     )} | ||||
|                 </Box> | ||||
|               </Box> | ||||
|               <Button | ||||
|                 variant="outlined" | ||||
|                 onClick={() => setIsSelectVideoDialogOpen(true)} | ||||
|                 startIcon={<Plus size={16} />} | ||||
|                 sx={{ minWidth: "auto", px: 2 }} | ||||
|               > | ||||
|                 Выбрать | ||||
|               </Button> | ||||
|             </Box> | ||||
|           </Box> | ||||
|  | ||||
|           <FormControl fullWidth required> | ||||
|             <InputLabel>Прямой/обратный маршрут</InputLabel> | ||||
|             <Select | ||||
| @@ -453,6 +387,45 @@ export const RouteEditPage = observer(() => { | ||||
|               }) | ||||
|             } | ||||
|           /> | ||||
|  | ||||
|           <Typography variant="subtitle1" sx={{ fontWeight: 600 }}> | ||||
|             Обращение к пассажирам | ||||
|           </Typography> | ||||
|           <Box className="flex gap-2"> | ||||
|             <TextField | ||||
|               className="flex-1" | ||||
|               value={selectedArticle?.heading || "Статья не выбрана"} | ||||
|               placeholder="Выберите статью" | ||||
|               disabled | ||||
|               fullWidth | ||||
|               sx={{ | ||||
|                 "& .MuiInputBase-input": { | ||||
|                   color: selectedArticle ? "inherit" : "#999", | ||||
|                 }, | ||||
|               }} | ||||
|             /> | ||||
|             <Button | ||||
|               variant="outlined" | ||||
|               onClick={() => setIsSelectArticleDialogOpen(true)} | ||||
|               startIcon={<Plus size={16} />} | ||||
|               sx={{ minWidth: "auto", px: 2 }} | ||||
|             > | ||||
|               Выбрать | ||||
|             </Button> | ||||
|           </Box> | ||||
|  | ||||
|           {/* Правая часть - Видео (30%) */} | ||||
|  | ||||
|           <VideoPreviewCard | ||||
|             title="Видеозаставка" | ||||
|             videoId={editRouteData.video_preview} | ||||
|             onVideoClick={handleVideoPreviewClick} | ||||
|             onDeleteVideoClick={() => { | ||||
|               routeStore.setEditRouteData({ video_preview: "" }); | ||||
|             }} | ||||
|             onSelectVideoClick={handleVideoFileSelect} | ||||
|             className="w-full" | ||||
|           /> | ||||
|         </Box> | ||||
|  | ||||
|         <LinkedItems | ||||
| @@ -494,8 +467,8 @@ export const RouteEditPage = observer(() => { | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       {/* Модальное окно выбора статьи */} | ||||
|       <SelectArticleModal | ||||
|       {/* Модальное окно выбора или создания статьи */} | ||||
|       <ArticleSelectOrCreateDialog | ||||
|         open={isSelectArticleDialogOpen} | ||||
|         onClose={() => setIsSelectArticleDialogOpen(false)} | ||||
|         onSelectArticle={handleArticleSelect} | ||||
| @@ -519,19 +492,35 @@ export const RouteEditPage = observer(() => { | ||||
|         <DialogTitle>Предпросмотр видео</DialogTitle> | ||||
|         <DialogContent> | ||||
|           <Box className="flex justify-center items-center p-4"> | ||||
|             <MediaViewer | ||||
|               media={{ | ||||
|                 id: editRouteData.video_preview, | ||||
|                 media_type: 2, | ||||
|                 filename: "video_preview", | ||||
|               }} | ||||
|             /> | ||||
|             {editRouteData.video_preview && ( | ||||
|               <MediaViewer | ||||
|                 media={{ | ||||
|                   id: editRouteData.video_preview, | ||||
|                   media_type: 2, | ||||
|                   filename: "video_preview", | ||||
|                 }} | ||||
|               /> | ||||
|             )} | ||||
|           </Box> | ||||
|         </DialogContent> | ||||
|         <DialogActions> | ||||
|           <Button onClick={() => setIsVideoPreviewOpen(false)}>Закрыть</Button> | ||||
|         </DialogActions> | ||||
|       </Dialog> | ||||
|  | ||||
|       {/* Модальное окно загрузки видео */} | ||||
|       <UploadMediaDialog | ||||
|         open={isUploadVideoDialogOpen} | ||||
|         onClose={() => { | ||||
|           setIsUploadVideoDialogOpen(false); | ||||
|           setFileToUpload(null); | ||||
|         }} | ||||
|         hardcodeType="video_preview" | ||||
|         contextObjectName={editRouteData.route_name || "Маршрут"} | ||||
|         contextType="sight" | ||||
|         initialFile={fileToUpload || undefined} | ||||
|         afterUpload={handleVideoUpload} | ||||
|       /> | ||||
|     </Paper> | ||||
|   ); | ||||
| }); | ||||
|   | ||||
| @@ -50,6 +50,22 @@ export const RouteListPage = observer(() => { | ||||
|         ); | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       field: "route_name", | ||||
|       headerName: "Название маршрута", | ||||
|       flex: 1, | ||||
|       renderCell: (params: GridRenderCellParams) => { | ||||
|         return ( | ||||
|           <div className="w-full h-full flex items-center"> | ||||
|             {params.value ? ( | ||||
|               params.value | ||||
|             ) : ( | ||||
|               <Minus size={20} className="text-red-500" /> | ||||
|             )} | ||||
|           </div> | ||||
|         ); | ||||
|       }, | ||||
|     }, | ||||
|     { | ||||
|       field: "route_number", | ||||
|       headerName: "Номер маршрута", | ||||
| @@ -122,6 +138,7 @@ export const RouteListPage = observer(() => { | ||||
|     carrier_id: route.carrier_id, | ||||
|     route_number: route.route_number, | ||||
|     route_direction: route.route_direction ? "Прямой" : "Обратный", | ||||
|     route_name: route.route_name, | ||||
|   })); | ||||
|  | ||||
|   return ( | ||||
|   | ||||
							
								
								
									
										1083
									
								
								src/shared/modals/ArticleSelectOrCreateDialog/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1083
									
								
								src/shared/modals/ArticleSelectOrCreateDialog/index.tsx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -2,3 +2,4 @@ export * from "./SelectArticleDialog"; | ||||
| export * from "./SelectMediaDialog"; | ||||
| export * from "./PreviewMediaDialog"; | ||||
| export * from "./UploadMediaDialog"; | ||||
| export * from "./ArticleSelectOrCreateDialog"; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { makeAutoObservable, runInAction } from "mobx"; | ||||
| import { authInstance } from "@shared"; | ||||
|  | ||||
| export type Route = { | ||||
|   route_name: string; | ||||
|   carrier: string; | ||||
|   carrier_id: number; | ||||
|   center_latitude: number; | ||||
| @@ -97,6 +98,7 @@ class RouteStore { | ||||
|   }; | ||||
|  | ||||
|   editRouteData = { | ||||
|     route_name: "", | ||||
|     carrier: "", | ||||
|     carrier_id: 0, | ||||
|     center_latitude: "", | ||||
| @@ -110,7 +112,7 @@ class RouteStore { | ||||
|     route_sys_number: "", | ||||
|     scale_max: 0, | ||||
|     scale_min: 0, | ||||
|     video_preview: "", | ||||
|     video_preview: "" as string | undefined, | ||||
|   }; | ||||
|  | ||||
|   setEditRouteData = (data: any) => { | ||||
| @@ -118,6 +120,9 @@ class RouteStore { | ||||
|   }; | ||||
|  | ||||
|   editRoute = async (id: number) => { | ||||
|     if (!this.editRouteData.video_preview) { | ||||
|       delete this.editRouteData.video_preview; | ||||
|     } | ||||
|     const response = await authInstance.patch(`/route/${id}`, { | ||||
|       ...this.editRouteData, | ||||
|       center_latitude: parseFloat(this.editRouteData.center_latitude), | ||||
|   | ||||
| @@ -11,6 +11,7 @@ interface VideoPreviewCardProps { | ||||
|   onDeleteVideoClick: () => void; | ||||
|   onSelectVideoClick: (file?: File) => void; | ||||
|   tooltipText?: string; | ||||
|   className?: string; | ||||
| } | ||||
|  | ||||
| export const VideoPreviewCard: React.FC<VideoPreviewCardProps> = ({ | ||||
| @@ -20,6 +21,7 @@ export const VideoPreviewCard: React.FC<VideoPreviewCardProps> = ({ | ||||
|   onDeleteVideoClick, | ||||
|   onSelectVideoClick, | ||||
|   tooltipText, | ||||
|   className, | ||||
| }) => { | ||||
|   const fileInputRef = useRef<HTMLInputElement>(null); | ||||
|   const [isDragOver, setIsDragOver] = useState(false); | ||||
| @@ -89,7 +91,10 @@ export const VideoPreviewCard: React.FC<VideoPreviewCardProps> = ({ | ||||
|         gap: 1, | ||||
|         flex: 1, | ||||
|         minWidth: 150, | ||||
|         width: "min-content", | ||||
|         mx: "auto", | ||||
|       }} | ||||
|       className={className} | ||||
|     > | ||||
|       <Box sx={{ display: "flex", alignItems: "center" }}> | ||||
|         <Typography variant="subtitle2" gutterBottom sx={{ mb: 0, mr: 0.5 }}> | ||||
| @@ -127,7 +132,10 @@ export const VideoPreviewCard: React.FC<VideoPreviewCardProps> = ({ | ||||
|           </button> | ||||
|         )} | ||||
|         {videoId ? ( | ||||
|           <Box sx={{ position: "relative", width: "100%", height: "100%" }}> | ||||
|           <Box | ||||
|             sx={{ position: "relative", width: "100%", height: "100%" }} | ||||
|             className={className} | ||||
|           > | ||||
|             <video | ||||
|               src={`${ | ||||
|                 import.meta.env.VITE_KRBL_MEDIA | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user