last changes
This commit is contained in:
parent
177653d84a
commit
042b53e6a4
13089
package-lock.json
generated
Normal file
13089
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -21,8 +21,7 @@ import routerBindings, {
|
|||||||
import { ColorModeContextProvider } from "./contexts/color-mode";
|
import { ColorModeContextProvider } from "./contexts/color-mode";
|
||||||
import { Header } from "./components/header";
|
import { Header } from "./components/header";
|
||||||
import { Login } from "./pages/login";
|
import { Login } from "./pages/login";
|
||||||
import { authProvider } from "./authProvider";
|
import { authProvider, i18nProvider } from "@providers";
|
||||||
import { i18nProvider } from "./i18nProvider";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CountryList,
|
CountryList,
|
||||||
|
@ -12,7 +12,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|||||||
import { axiosInstance } from "../providers/data";
|
import { axiosInstance } from "../providers/data";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { MarkdownEditor } from "./MarkdownEditor";
|
import { MarkdownEditor } from "./MarkdownEditor";
|
||||||
import React, { useState, useCallback } from "react";
|
import React, { useState, useCallback, useEffect } from "react";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import {
|
import {
|
||||||
ALLOWED_IMAGE_TYPES,
|
ALLOWED_IMAGE_TYPES,
|
||||||
@ -20,6 +20,8 @@ import {
|
|||||||
} from "../components/media/MediaFormUtils";
|
} from "../components/media/MediaFormUtils";
|
||||||
import { LinkedItems } from "./LinkedItems";
|
import { LinkedItems } from "./LinkedItems";
|
||||||
import { mediaFields, MediaItem } from "../pages/article/types";
|
import { mediaFields, MediaItem } from "../pages/article/types";
|
||||||
|
import { LanguageSelector } from "@ui";
|
||||||
|
import { EVERY_LANGUAGE, Languages, languageStore } from "@stores";
|
||||||
|
|
||||||
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
||||||
|
|
||||||
@ -47,12 +49,15 @@ export const CreateSightArticle = ({
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [mediaFiles, setMediaFiles] = useState<MediaFile[]>([]);
|
const [mediaFiles, setMediaFiles] = useState<MediaFile[]>([]);
|
||||||
|
const { language, setLanguageAction } = languageStore;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register: registerItem,
|
register: registerItem,
|
||||||
|
watch,
|
||||||
control: controlItem,
|
control: controlItem,
|
||||||
handleSubmit: handleSubmitItem,
|
handleSubmit: handleSubmitItem,
|
||||||
reset: resetItem,
|
reset: resetItem,
|
||||||
|
setValue,
|
||||||
formState: { errors: itemErrors },
|
formState: { errors: itemErrors },
|
||||||
} = useForm({
|
} = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@ -61,6 +66,45 @@ export const CreateSightArticle = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [articleData, setArticleData] = useState({
|
||||||
|
heading: EVERY_LANGUAGE(""),
|
||||||
|
body: EVERY_LANGUAGE("")
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateTranslations() {
|
||||||
|
const newArticleData = {
|
||||||
|
...articleData,
|
||||||
|
heading: {
|
||||||
|
...articleData.heading,
|
||||||
|
[language]: watch("heading") ?? "",
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
...articleData.body,
|
||||||
|
[language]: watch("body") ?? "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setArticleData(newArticleData);
|
||||||
|
return newArticleData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const handleFormSubmit = handleSubmit((values: FieldValues) => {
|
||||||
|
// const newTranslations = updateTranslations();
|
||||||
|
// console.log(newTranslations);
|
||||||
|
// return onFinish({
|
||||||
|
// translations: newTranslations
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue("heading", articleData.heading[language] ?? "");
|
||||||
|
setValue("body", articleData.body[language] ?? "");
|
||||||
|
}, [language, articleData, setValue]);
|
||||||
|
|
||||||
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
|
updateTranslations();
|
||||||
|
setLanguageAction(lang);
|
||||||
|
};
|
||||||
|
|
||||||
const simpleMDEOptions = React.useMemo(
|
const simpleMDEOptions = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
placeholder: "Введите контент в формате Markdown...",
|
placeholder: "Введите контент в формате Markdown...",
|
||||||
@ -109,7 +153,10 @@ export const CreateSightArticle = ({
|
|||||||
// Создаем статью
|
// Создаем статью
|
||||||
const response = await axiosInstance.post(
|
const response = await axiosInstance.post(
|
||||||
`${import.meta.env.VITE_KRBL_API}/${childResource}`,
|
`${import.meta.env.VITE_KRBL_API}/${childResource}`,
|
||||||
data
|
{
|
||||||
|
...data,
|
||||||
|
translations: updateTranslations()
|
||||||
|
}
|
||||||
);
|
);
|
||||||
const itemId = response.data.id;
|
const itemId = response.data.id;
|
||||||
|
|
||||||
@ -119,7 +166,7 @@ export const CreateSightArticle = ({
|
|||||||
import.meta.env.VITE_KRBL_API
|
import.meta.env.VITE_KRBL_API
|
||||||
}/${parentResource}/${parentId}/${childResource}`
|
}/${parentResource}/${parentId}/${childResource}`
|
||||||
);
|
);
|
||||||
const existingItems = existingItemsResponse.data || [];
|
const existingItems = existingItemsResponse.data ?? [];
|
||||||
const nextPageNum = existingItems.length + 1;
|
const nextPageNum = existingItems.length + 1;
|
||||||
|
|
||||||
if (!left) {
|
if (!left) {
|
||||||
@ -189,6 +236,7 @@ export const CreateSightArticle = ({
|
|||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails sx={{ background: theme.palette.background.paper }}>
|
<AccordionDetails sx={{ background: theme.palette.background.paper }}>
|
||||||
<Box component="form" onSubmit={handleSubmitItem(handleCreate)}>
|
<Box component="form" onSubmit={handleSubmitItem(handleCreate)}>
|
||||||
|
<LanguageSelector action={handleLanguageChange} />
|
||||||
<TextField
|
<TextField
|
||||||
{...registerItem("heading", {
|
{...registerItem("heading", {
|
||||||
required: "Это поле является обязательным",
|
required: "Это поле является обязательным",
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import { languageStore } from "../../store/LanguageStore";
|
import { Languages, languageStore } from "../../store/LanguageStore";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
export const LanguageSwitch = observer(({ action }: any) => {
|
export const LanguageSwitch = observer(({ action }: any) => {
|
||||||
const { language, setLanguageAction } = languageStore;
|
const { language, setLanguageAction } = languageStore;
|
||||||
|
|
||||||
const handleLanguageChange = (lang: string) => {
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
if (action) {
|
action?.();
|
||||||
action();
|
|
||||||
}
|
|
||||||
setLanguageAction(lang);
|
setLanguageAction(lang);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -287,114 +287,116 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>({
|
|||||||
|
|
||||||
<AccordionDetails sx={{ background: theme.palette.background.paper }}>
|
<AccordionDetails sx={{ background: theme.palette.background.paper }}>
|
||||||
<Stack gap={2}>
|
<Stack gap={2}>
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
{linkedItems?.length > 0 && (
|
||||||
<TableContainer component={Paper}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
<Table>
|
<TableContainer component={Paper}>
|
||||||
<TableHead>
|
<Table>
|
||||||
<TableRow>
|
<TableHead>
|
||||||
{type === "edit" && dragAllowed && (
|
<TableRow>
|
||||||
<TableCell width="40px"></TableCell>
|
{type === "edit" && dragAllowed && (
|
||||||
)}
|
<TableCell width="40px"></TableCell>
|
||||||
<TableCell key="id">№</TableCell>
|
)}
|
||||||
{fields.map((field) => (
|
<TableCell key="id">№</TableCell>
|
||||||
<TableCell key={String(field.data)}>
|
{fields.map((field) => (
|
||||||
{field.label}
|
<TableCell key={String(field.data)}>
|
||||||
</TableCell>
|
{field.label}
|
||||||
))}
|
</TableCell>
|
||||||
|
|
||||||
{type === "edit" && (
|
|
||||||
<TableCell width="120px">Действие</TableCell>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
|
|
||||||
<Droppable
|
|
||||||
droppableId="droppable"
|
|
||||||
isDropDisabled={type !== "edit" || !dragAllowed}
|
|
||||||
>
|
|
||||||
{(provided) => (
|
|
||||||
<TableBody
|
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.droppableProps}
|
|
||||||
>
|
|
||||||
{linkedItems.map((item, index) => (
|
|
||||||
<Draggable
|
|
||||||
key={item.id}
|
|
||||||
draggableId={"q" + String(item.id)}
|
|
||||||
index={index}
|
|
||||||
isDragDisabled={type !== "edit" || !dragAllowed}
|
|
||||||
>
|
|
||||||
{(provided) => (
|
|
||||||
<TableRow
|
|
||||||
sx={{
|
|
||||||
cursor:
|
|
||||||
childResource === "article"
|
|
||||||
? "pointer"
|
|
||||||
: "default",
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
if (childResource === "article") {
|
|
||||||
setArticleModalOpenAction(true);
|
|
||||||
setArticleIdAction(item.id);
|
|
||||||
}
|
|
||||||
if (childResource === "station") {
|
|
||||||
setStationModalOpenAction(true);
|
|
||||||
setStationIdAction(item.id);
|
|
||||||
setRouteIdAction(Number(parentId));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.draggableProps}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
hover
|
|
||||||
>
|
|
||||||
{type === "edit" && dragAllowed && (
|
|
||||||
<TableCell {...provided.dragHandleProps}>
|
|
||||||
<IconButton size="small">
|
|
||||||
<DragIndicatorIcon />
|
|
||||||
</IconButton>
|
|
||||||
</TableCell>
|
|
||||||
)}
|
|
||||||
<TableCell key={String(item.id)}>
|
|
||||||
{index + 1}
|
|
||||||
</TableCell>
|
|
||||||
{fields.map((field, index) => (
|
|
||||||
<TableCell
|
|
||||||
key={String(field.data) + String(index)}
|
|
||||||
>
|
|
||||||
{field.render
|
|
||||||
? field.render(item[field.data])
|
|
||||||
: item[field.data]}
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{type === "edit" && (
|
|
||||||
<TableCell>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
color="error"
|
|
||||||
size="small"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
deleteItem(item.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Отвязать
|
|
||||||
</Button>
|
|
||||||
</TableCell>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{provided.placeholder}
|
{type === "edit" && (
|
||||||
</TableBody>
|
<TableCell width="120px">Действие</TableCell>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</TableRow>
|
||||||
</Table>
|
</TableHead>
|
||||||
</TableContainer>
|
|
||||||
</DragDropContext>
|
<Droppable
|
||||||
|
droppableId="droppable"
|
||||||
|
isDropDisabled={type !== "edit" || !dragAllowed}
|
||||||
|
>
|
||||||
|
{(provided) => (
|
||||||
|
<TableBody
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.droppableProps}
|
||||||
|
>
|
||||||
|
{linkedItems.map((item, index) => (
|
||||||
|
<Draggable
|
||||||
|
key={item.id}
|
||||||
|
draggableId={"q" + String(item.id)}
|
||||||
|
index={index}
|
||||||
|
isDragDisabled={type !== "edit" || !dragAllowed}
|
||||||
|
>
|
||||||
|
{(provided) => (
|
||||||
|
<TableRow
|
||||||
|
sx={{
|
||||||
|
cursor:
|
||||||
|
childResource === "article"
|
||||||
|
? "pointer"
|
||||||
|
: "default",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
if (childResource === "article") {
|
||||||
|
setArticleModalOpenAction(true);
|
||||||
|
setArticleIdAction(item.id);
|
||||||
|
}
|
||||||
|
if (childResource === "station") {
|
||||||
|
setStationModalOpenAction(true);
|
||||||
|
setStationIdAction(item.id);
|
||||||
|
setRouteIdAction(Number(parentId));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
hover
|
||||||
|
>
|
||||||
|
{type === "edit" && dragAllowed && (
|
||||||
|
<TableCell {...provided.dragHandleProps}>
|
||||||
|
<IconButton size="small">
|
||||||
|
<DragIndicatorIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
<TableCell key={String(item.id)}>
|
||||||
|
{index + 1}
|
||||||
|
</TableCell>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<TableCell
|
||||||
|
key={String(field.data) + String(index)}
|
||||||
|
>
|
||||||
|
{field.render
|
||||||
|
? field.render(item[field.data])
|
||||||
|
: item[field.data]}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{type === "edit" && (
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="error"
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
deleteItem(item.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Отвязать
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{provided.placeholder}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</DragDropContext>
|
||||||
|
)}
|
||||||
|
|
||||||
{linkedItems.length === 0 && !isLoading && (
|
{linkedItems.length === 0 && !isLoading && (
|
||||||
<Typography color="textSecondary" textAlign="center" py={2}>
|
<Typography color="textSecondary" textAlign="center" py={2}>
|
||||||
@ -448,7 +450,7 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{childResource === "article" && (
|
{/* {childResource === "article" && (
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
<TextField
|
<TextField
|
||||||
type="number"
|
type="number"
|
||||||
@ -464,7 +466,7 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>({
|
|||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)} */}
|
||||||
|
|
||||||
{childResource === "media" && (
|
{childResource === "media" && (
|
||||||
<FormControl fullWidth>
|
<FormControl fullWidth>
|
||||||
|
@ -4,20 +4,17 @@ import { observer } from "mobx-react-lite";
|
|||||||
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 "easymde/dist/easymde.min.css";
|
import "easymde/dist/easymde.min.css";
|
||||||
import { memo, useMemo, useEffect, useCallback } from "react";
|
import { memo, useMemo, useEffect, useCallback, useState } from "react";
|
||||||
import { MarkdownEditor } from "../../MarkdownEditor";
|
import { MarkdownEditor } from "../../MarkdownEditor";
|
||||||
import { Edit } from "@refinedev/mui";
|
import { Edit } from "@refinedev/mui";
|
||||||
import { languageStore } from "../../../store/LanguageStore";
|
import { languageStore } from "../../../store/LanguageStore";
|
||||||
import { LanguageSwitch } from "../../LanguageSwitch/index";
|
import { LanguageSwitch } from "../../LanguageSwitch/index";
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import {
|
import {
|
||||||
ALLOWED_IMAGE_TYPES,
|
ALLOWED_IMAGE_TYPES,
|
||||||
ALLOWED_VIDEO_TYPES,
|
ALLOWED_VIDEO_TYPES,
|
||||||
} from "../../media/MediaFormUtils";
|
} from "../../media/MediaFormUtils";
|
||||||
import { axiosInstance } from "../../../providers/data";
|
import { TOKEN_KEY, axiosInstance } from "@providers";
|
||||||
import { TOKEN_KEY } from "../../../authProvider";
|
|
||||||
import { LinkedItems } from "../../../components/LinkedItems";
|
import { LinkedItems } from "../../../components/LinkedItems";
|
||||||
import { mediaFields, MediaItem } from "../../../pages/article/types";
|
import { mediaFields, MediaItem } from "../../../pages/article/types";
|
||||||
|
|
||||||
|
71
src/components/ui/LanguageSelector.tsx
Normal file
71
src/components/ui/LanguageSelector.tsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { Box } from "@mui/material";
|
||||||
|
import { Languages, languageStore } from "@stores";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
|
|
||||||
|
export const LanguageSelector = observer(({
|
||||||
|
action
|
||||||
|
}: {action?: (lang: Languages) => void}) => {
|
||||||
|
const { language, setLanguageAction } = languageStore;
|
||||||
|
|
||||||
|
function handleLanguageChange(language: Languages) {
|
||||||
|
if(action) action(language);
|
||||||
|
else setLanguageAction(language);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
gap: 2,
|
||||||
|
height: "min-content"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
flex: 1,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
bgcolor: language === "ru" ? "primary.main" : "transparent",
|
||||||
|
color: language === "ru" ? "white" : "inherit",
|
||||||
|
borderRadius: 1,
|
||||||
|
p: 1,
|
||||||
|
}}
|
||||||
|
onClick={() => handleLanguageChange("ru")}
|
||||||
|
>
|
||||||
|
RU
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
flex: 1,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
bgcolor: language === "en" ? "primary.main" : "transparent",
|
||||||
|
color: language === "en" ? "white" : "inherit",
|
||||||
|
borderRadius: 1,
|
||||||
|
p: 1,
|
||||||
|
}}
|
||||||
|
onClick={() => handleLanguageChange("en")}
|
||||||
|
>
|
||||||
|
EN
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
flex: 1,
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
bgcolor: language === "zh" ? "primary.main" : "transparent",
|
||||||
|
color: language === "zh" ? "white" : "inherit",
|
||||||
|
borderRadius: 1,
|
||||||
|
p: 1,
|
||||||
|
}}
|
||||||
|
onClick={() => handleLanguageChange("zh")}
|
||||||
|
>
|
||||||
|
ZH
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
97
src/components/ui/MediaView.tsx
Normal file
97
src/components/ui/MediaView.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { Box } from "@mui/material";
|
||||||
|
import { TOKEN_KEY } from "@providers";
|
||||||
|
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||||
|
import { ModelViewer } from "./ModelViewer";
|
||||||
|
|
||||||
|
export interface MediaData {
|
||||||
|
filename?: string;
|
||||||
|
id: string | number;
|
||||||
|
media_name?: string;
|
||||||
|
media_type: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MediaView({media} : Readonly<{media?: MediaData}>) {
|
||||||
|
const token = localStorage.getItem(TOKEN_KEY);
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{maxHeight: "50vh", height: "100%", width: "100%", display: "flex", justifyContent: "center"}}
|
||||||
|
>
|
||||||
|
{media?.media_type === 1 && (
|
||||||
|
<img
|
||||||
|
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
|
media?.id
|
||||||
|
}/download?token=${token}`}
|
||||||
|
alt={media?.filename}
|
||||||
|
style={{
|
||||||
|
maxWidth: "100%",
|
||||||
|
height: "100%",
|
||||||
|
objectFit: "contain",
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{media?.media_type === 2 && (
|
||||||
|
<video
|
||||||
|
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
|
media?.id
|
||||||
|
}/download?token=${token}`}
|
||||||
|
style={{
|
||||||
|
|
||||||
|
objectFit: "contain",
|
||||||
|
borderRadius: 30,
|
||||||
|
}}
|
||||||
|
controls
|
||||||
|
autoPlay
|
||||||
|
muted
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{media?.media_type === 3 && (
|
||||||
|
<img
|
||||||
|
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
|
media?.id
|
||||||
|
}/download?token=${token}`}
|
||||||
|
alt={media?.filename}
|
||||||
|
style={{
|
||||||
|
maxWidth: "100%",
|
||||||
|
height: "100%",
|
||||||
|
objectFit: "contain",
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{media?.media_type === 4 && (
|
||||||
|
<img
|
||||||
|
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
|
media?.id
|
||||||
|
}/download?token=${token}`}
|
||||||
|
alt={media?.filename}
|
||||||
|
style={{
|
||||||
|
maxWidth: "100%",
|
||||||
|
height: "100%",
|
||||||
|
objectFit: "contain",
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{media?.media_type === 5 && (
|
||||||
|
<ReactPhotoSphereViewer
|
||||||
|
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
|
media?.id
|
||||||
|
}/download?token=${token}`}
|
||||||
|
width={"100%"}
|
||||||
|
height={"100%"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{media?.media_type === 6 && (
|
||||||
|
<ModelViewer
|
||||||
|
fileUrl={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
|
media?.id
|
||||||
|
}/download?token=${token}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
@ -6,7 +6,7 @@ type ModelViewerProps = {
|
|||||||
height?: string;
|
height?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModelViewer = ({ fileUrl, height = "80vh" }: ModelViewerProps) => {
|
export const ModelViewer = ({ fileUrl, height = "100%" }: ModelViewerProps) => {
|
||||||
const { scene } = useGLTF(fileUrl);
|
const { scene } = useGLTF(fileUrl);
|
||||||
|
|
||||||
return (
|
return (
|
5
src/components/ui/index.ts
Normal file
5
src/components/ui/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './Icons';
|
||||||
|
export * from './LanguageSelector';
|
||||||
|
export * from './SidebarTitle';
|
||||||
|
export * from './MediaView';
|
||||||
|
export * from './ModelViewer';
|
@ -10,4 +10,4 @@ export const MEDIA_TYPES = [
|
|||||||
export const VEHICLE_TYPES = [
|
export const VEHICLE_TYPES = [
|
||||||
{ label: "Трамвай", value: 1 },
|
{ label: "Трамвай", value: 1 },
|
||||||
{ label: "Троллейбус", value: 2 },
|
{ label: "Троллейбус", value: 2 },
|
||||||
];
|
];
|
1
src/lib/index.ts
Normal file
1
src/lib/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { MEDIA_TYPES, VEHICLE_TYPES } from './constants'
|
@ -1,94 +1,92 @@
|
|||||||
import { Box, TextField, Typography, Paper } from "@mui/material";
|
import { Box, TextField, Typography, Paper } from "@mui/material";
|
||||||
import { Create } from "@refinedev/mui";
|
import { Create } 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, FieldValues } from "react-hook-form";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import Cookies from "js-cookie";
|
|
||||||
import { MarkdownEditor } from "../../components/MarkdownEditor";
|
import { MarkdownEditor } from "../../components/MarkdownEditor";
|
||||||
import "easymde/dist/easymde.min.css";
|
import "easymde/dist/easymde.min.css";
|
||||||
|
import { LanguageSelector } from "@ui";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { EVERY_LANGUAGE, Languages, languageStore, META_LANGUAGE } from "@stores";
|
||||||
|
import { axiosInstance } from "@/providers/data";
|
||||||
|
|
||||||
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
||||||
|
|
||||||
export const ArticleCreate = () => {
|
export const ArticleCreate = observer(() => {
|
||||||
const [language, setLanguage] = useState(Cookies.get("lang")!);
|
const { language, setLanguageAction } = languageStore;
|
||||||
const [articleData, setArticleData] = useState<{
|
const [articleData, setArticleData] = useState({
|
||||||
ru: { heading: string; body: string };
|
heading: EVERY_LANGUAGE(""),
|
||||||
en: { heading: string; body: string };
|
body: EVERY_LANGUAGE("")
|
||||||
zh: { heading: string; body: string };
|
|
||||||
}>({
|
|
||||||
ru: { heading: "", body: "" },
|
|
||||||
en: { heading: "", body: "" },
|
|
||||||
zh: { heading: "", body: "" },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
refineCore: { formLoading },
|
refineCore: { formLoading, onFinish },
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
setValue,
|
setValue,
|
||||||
|
handleSubmit,
|
||||||
} = useForm({
|
} = useForm({
|
||||||
refineCoreProps: {
|
refineCoreProps: {
|
||||||
resource: "article/",
|
resource: "article",
|
||||||
meta: {
|
...META_LANGUAGE(language)
|
||||||
headers: {
|
|
||||||
"Accept-Language": language,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
warnWhenUnsavedChanges: false
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const lang = Cookies.get("lang")!;
|
|
||||||
Cookies.set("lang", language);
|
|
||||||
return () => {
|
|
||||||
Cookies.set("lang", lang);
|
|
||||||
};
|
|
||||||
}, [language]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setValue(
|
|
||||||
"heading",
|
|
||||||
articleData[language as keyof typeof articleData]?.heading || ""
|
|
||||||
);
|
|
||||||
setValue(
|
|
||||||
"body",
|
|
||||||
articleData[language as keyof typeof articleData]?.body || ""
|
|
||||||
);
|
|
||||||
setPreview(articleData[language as keyof typeof articleData]?.body || "");
|
|
||||||
setHeadingPreview(
|
|
||||||
articleData[language as keyof typeof articleData]?.heading || ""
|
|
||||||
);
|
|
||||||
}, [language, articleData, setValue]);
|
|
||||||
|
|
||||||
const handleLanguageChange = (lang: string) => {
|
|
||||||
setArticleData((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
[language]: {
|
|
||||||
heading: watch("heading") || "",
|
|
||||||
body: watch("body") || "",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
setLanguage(lang);
|
|
||||||
Cookies.set("lang", lang);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [preview, setPreview] = useState("");
|
|
||||||
const [headingPreview, setHeadingPreview] = useState("");
|
|
||||||
|
|
||||||
// Следим за изменениями в полях body и heading
|
// Следим за изменениями в полях body и heading
|
||||||
const bodyContent = watch("body");
|
const bodyContent = watch("body");
|
||||||
const headingContent = watch("heading");
|
const headingContent = watch("heading");
|
||||||
|
|
||||||
|
function updateTranslations() {
|
||||||
|
const newArticleData = {
|
||||||
|
...articleData,
|
||||||
|
heading: {
|
||||||
|
...articleData.heading,
|
||||||
|
[language]: watch("heading") ?? "",
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
...articleData.body,
|
||||||
|
[language]: watch("body") ?? "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setArticleData(newArticleData);
|
||||||
|
return newArticleData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFormSubmit = handleSubmit((values: FieldValues) => {
|
||||||
|
const newTranslations = updateTranslations();
|
||||||
|
console.log(newTranslations);
|
||||||
|
return onFinish({
|
||||||
|
translations: newTranslations
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPreview(bodyContent || "");
|
setValue("heading", articleData.heading[language] ?? "");
|
||||||
|
setValue("body", articleData.body[language] ?? "");
|
||||||
|
setPreview(articleData.body[language] ?? "");
|
||||||
|
setHeadingPreview(articleData.heading[language] ?? "");
|
||||||
|
}, [language, articleData, setValue]);
|
||||||
|
|
||||||
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
|
updateTranslations();
|
||||||
|
setLanguageAction(lang);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [preview, setPreview] = useState("");
|
||||||
|
const [headingPreview, setHeadingPreview] = useState("");
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPreview(bodyContent ?? "");
|
||||||
}, [bodyContent]);
|
}, [bodyContent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHeadingPreview(headingContent || "");
|
setHeadingPreview(headingContent ?? "");
|
||||||
}, [headingContent]);
|
}, [headingContent]);
|
||||||
|
|
||||||
const simpleMDEOptions = React.useMemo(
|
const simpleMDEOptions = React.useMemo(
|
||||||
@ -100,63 +98,14 @@ export const ArticleCreate = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
<Create isLoading={formLoading} saveButtonProps={{
|
||||||
|
//...saveButtonProps,
|
||||||
|
onClick: handleFormSubmit
|
||||||
|
}}>
|
||||||
<Box sx={{ display: "flex", flex: 1, gap: 2 }}>
|
<Box sx={{ display: "flex", flex: 1, gap: 2 }}>
|
||||||
{/* Форма создания */}
|
{/* Форма создания */}
|
||||||
<Box sx={{ display: "flex", flex: 1, flexDirection: "column", gap: 2 }}>
|
<Box sx={{ display: "flex", flex: 1, flexDirection: "column", gap: 2 }}>
|
||||||
<Box
|
<LanguageSelector action={handleLanguageChange} />
|
||||||
sx={{
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
gap: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
bgcolor: language === "ru" ? "primary.main" : "transparent",
|
|
||||||
color: language === "ru" ? "white" : "inherit",
|
|
||||||
p: 1,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => handleLanguageChange("ru")}
|
|
||||||
>
|
|
||||||
RU
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
bgcolor: language === "en" ? "primary.main" : "transparent",
|
|
||||||
color: language === "en" ? "white" : "inherit",
|
|
||||||
p: 1,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => handleLanguageChange("en")}
|
|
||||||
>
|
|
||||||
EN
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
bgcolor: language === "zh" ? "primary.main" : "transparent",
|
|
||||||
color: language === "zh" ? "white" : "inherit",
|
|
||||||
p: 1,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => handleLanguageChange("zh")}
|
|
||||||
>
|
|
||||||
ZH
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box
|
<Box
|
||||||
component="form"
|
component="form"
|
||||||
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
||||||
@ -273,4 +222,4 @@ export const ArticleCreate = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Create>
|
</Create>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Box, TextField, Typography, Paper } from "@mui/material";
|
import { Box, TextField, Typography, Paper } from "@mui/material";
|
||||||
import { Edit } from "@refinedev/mui";
|
import { Edit } 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, FieldValues } from "react-hook-form";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
import React, { useState, useEffect, useMemo } from "react";
|
import React, { useState, useEffect, useMemo } from "react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
@ -10,23 +10,19 @@ import { useList } from "@refinedev/core";
|
|||||||
import { MarkdownEditor } from "../../components/MarkdownEditor";
|
import { MarkdownEditor } from "../../components/MarkdownEditor";
|
||||||
import { LinkedItems } from "../../components/LinkedItems";
|
import { LinkedItems } from "../../components/LinkedItems";
|
||||||
import { MediaItem, mediaFields } from "./types";
|
import { MediaItem, mediaFields } from "./types";
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
import "easymde/dist/easymde.min.css";
|
import "easymde/dist/easymde.min.css";
|
||||||
import { languageStore } from "../../store/LanguageStore";
|
import { EVERY_LANGUAGE, Languages, languageStore, META_LANGUAGE } from "@stores";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { LanguageSelector, MediaView } from "@ui";
|
||||||
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
||||||
|
|
||||||
export const ArticleEdit = observer(() => {
|
export const ArticleEdit = observer(() => {
|
||||||
const { language, setLanguageAction } = languageStore;
|
const { language, setLanguageAction } = languageStore;
|
||||||
|
|
||||||
const [articleData, setArticleData] = useState<{
|
const [articleData, setArticleData] = useState({
|
||||||
ru: { heading: string; body: string };
|
heading: EVERY_LANGUAGE(""),
|
||||||
en: { heading: string; body: string };
|
body: EVERY_LANGUAGE("")
|
||||||
zh: { heading: string; body: string };
|
|
||||||
}>({
|
|
||||||
ru: { heading: "", body: "" },
|
|
||||||
en: { heading: "", body: "" },
|
|
||||||
zh: { heading: "", body: "" },
|
|
||||||
});
|
});
|
||||||
const { id: articleId } = useParams<{ id: string }>();
|
const { id: articleId } = useParams<{ id: string }>();
|
||||||
const [preview, setPreview] = useState("");
|
const [preview, setPreview] = useState("");
|
||||||
@ -41,6 +37,7 @@ export const ArticleEdit = observer(() => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
|
refineCore: { onFinish },
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -48,54 +45,54 @@ export const ArticleEdit = observer(() => {
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
setValue,
|
setValue,
|
||||||
} = useForm<{ heading: string; body: string }>({
|
} = useForm<{ heading: string; body: string }>({
|
||||||
refineCoreProps: {
|
refineCoreProps: META_LANGUAGE(language)
|
||||||
meta: {
|
|
||||||
headers: {
|
|
||||||
"Accept-Language": language,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (articleData[language as keyof typeof articleData]?.heading) {
|
|
||||||
setValue(
|
|
||||||
"heading",
|
|
||||||
articleData[language as keyof typeof articleData]?.heading
|
|
||||||
);
|
|
||||||
setHeadingPreview(
|
|
||||||
articleData[language as keyof typeof articleData]?.heading || ""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (articleData[language as keyof typeof articleData]?.body) {
|
|
||||||
setValue(
|
|
||||||
"body",
|
|
||||||
articleData[language as keyof typeof articleData]?.body || ""
|
|
||||||
);
|
|
||||||
setPreview(articleData[language as keyof typeof articleData]?.body || "");
|
|
||||||
}
|
|
||||||
}, [language, articleData, setValue]);
|
|
||||||
|
|
||||||
const handleLanguageChange = (lang: string) => {
|
|
||||||
setArticleData((prevData) => ({
|
|
||||||
...prevData,
|
|
||||||
[language]: {
|
|
||||||
heading: watch("heading") ?? "",
|
|
||||||
body: watch("body") ?? "",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
setLanguageAction(lang);
|
|
||||||
};
|
|
||||||
|
|
||||||
const bodyContent = watch("body");
|
const bodyContent = watch("body");
|
||||||
const headingContent = watch("heading");
|
const headingContent = watch("heading");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPreview(bodyContent || "");
|
setValue("heading", articleData.heading[language] ?? "");
|
||||||
|
setHeadingPreview(articleData.heading[language] ?? "");
|
||||||
|
setValue("body", articleData.body[language] ?? "");
|
||||||
|
setPreview(articleData.body[language] ?? "");
|
||||||
|
}, [language, articleData, setValue]);
|
||||||
|
|
||||||
|
function updateTranslations() {
|
||||||
|
const newArticleData = {
|
||||||
|
...articleData,
|
||||||
|
heading: {
|
||||||
|
...articleData.heading,
|
||||||
|
[language]: watch("heading") ?? "",
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
...articleData.body,
|
||||||
|
[language]: watch("body") ?? "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setArticleData(newArticleData);
|
||||||
|
return newArticleData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
|
updateTranslations();
|
||||||
|
setLanguageAction(lang);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFormSubmit = handleSubmit((values: FieldValues) => {
|
||||||
|
const newTranslations = updateTranslations();
|
||||||
|
console.log(newTranslations);
|
||||||
|
return onFinish({
|
||||||
|
translations: newTranslations
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPreview(bodyContent ?? "");
|
||||||
}, [bodyContent]);
|
}, [bodyContent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHeadingPreview(headingContent || "");
|
setHeadingPreview(headingContent ?? "");
|
||||||
}, [headingContent]);
|
}, [headingContent]);
|
||||||
|
|
||||||
const { data: mediaData } = useList<MediaItem>({
|
const { data: mediaData } = useList<MediaItem>({
|
||||||
@ -109,64 +106,17 @@ export const ArticleEdit = observer(() => {
|
|||||||
}, [setLanguageAction]);
|
}, [setLanguageAction]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edit saveButtonProps={saveButtonProps}>
|
<Edit saveButtonProps={{
|
||||||
|
...saveButtonProps,
|
||||||
|
onClick: handleFormSubmit
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Box sx={{ display: "flex", gap: 2 }}>
|
<Box sx={{ display: "flex", gap: 2 }}>
|
||||||
{/* Форма редактирования */}
|
{/* Форма редактирования */}
|
||||||
{/* Форма создания */}
|
{/* Форма создания */}
|
||||||
<Box sx={{ display: "flex", flex: 1, flexDirection: "column", gap: 2 }}>
|
<Box sx={{ display: "flex", flex: 1, flexDirection: "column", gap: 2 }}>
|
||||||
<Box
|
|
||||||
sx={{
|
<LanguageSelector action={handleLanguageChange} />
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
gap: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
bgcolor: language === "ru" ? "primary.main" : "transparent",
|
|
||||||
color: language === "ru" ? "white" : "inherit",
|
|
||||||
p: 1,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => handleLanguageChange("ru")}
|
|
||||||
>
|
|
||||||
RU
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
bgcolor: language === "en" ? "primary.main" : "transparent",
|
|
||||||
color: language === "en" ? "white" : "inherit",
|
|
||||||
p: 1,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => handleLanguageChange("en")}
|
|
||||||
>
|
|
||||||
EN
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
cursor: "pointer",
|
|
||||||
flex: 1,
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
bgcolor: language === "zh" ? "primary.main" : "transparent",
|
|
||||||
color: language === "zh" ? "white" : "inherit",
|
|
||||||
p: 1,
|
|
||||||
borderRadius: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => handleLanguageChange("zh")}
|
|
||||||
>
|
|
||||||
ZH
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
<Box
|
<Box
|
||||||
component="form"
|
component="form"
|
||||||
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
||||||
@ -317,7 +267,8 @@ export const ArticleEdit = observer(() => {
|
|||||||
borderColor: "primary.main",
|
borderColor: "primary.main",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<MediaView media={media} />
|
||||||
|
{/* <img
|
||||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||||
media.id
|
media.id
|
||||||
}/download?token=${localStorage.getItem(TOKEN_KEY)}`}
|
}/download?token=${localStorage.getItem(TOKEN_KEY)}`}
|
||||||
@ -327,7 +278,7 @@ export const ArticleEdit = observer(() => {
|
|||||||
height: "100%",
|
height: "100%",
|
||||||
objectFit: "cover",
|
objectFit: "cover",
|
||||||
}}
|
}}
|
||||||
/>
|
/> */}
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -8,21 +8,18 @@ import {
|
|||||||
useDataGrid,
|
useDataGrid,
|
||||||
} from "@refinedev/mui";
|
} from "@refinedev/mui";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
|
import { useDelete } from "@refinedev/core";
|
||||||
|
|
||||||
import { localeText } from "../../locales/ru/localeText";
|
import { localeText } from "../../locales/ru/localeText";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { languageStore } from "../../store/LanguageStore";
|
import { languageStore, META_LANGUAGE } from "@stores";
|
||||||
|
|
||||||
export const ArticleList = observer(() => {
|
export const ArticleList = observer(() => {
|
||||||
const { language } = languageStore;
|
const { language } = languageStore;
|
||||||
|
|
||||||
const { dataGridProps } = useDataGrid({
|
const { dataGridProps } = useDataGrid({
|
||||||
resource: "article/",
|
resource: "article",
|
||||||
meta: {
|
...META_LANGUAGE(language)
|
||||||
headers: {
|
|
||||||
"Accept-Language": language,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = React.useMemo<GridColDef[]>(
|
const columns = React.useMemo<GridColDef[]>(
|
||||||
@ -70,7 +67,10 @@ export const ArticleList = observer(() => {
|
|||||||
<>
|
<>
|
||||||
<EditButton hideText recordItemId={row.id} />
|
<EditButton hideText recordItemId={row.id} />
|
||||||
<ShowButton hideText recordItemId={row.id} />
|
<ShowButton hideText recordItemId={row.id} />
|
||||||
<DeleteButton hideText recordItemId={row.id} />
|
<DeleteButton
|
||||||
|
hideText
|
||||||
|
recordItemId={row.id}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,7 @@ export type MediaItem = {
|
|||||||
id: number
|
id: number
|
||||||
filename: string
|
filename: string
|
||||||
media_name: string
|
media_name: string
|
||||||
media_type: string
|
media_type: number
|
||||||
media_order?: number
|
media_order?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
import { Autocomplete, Box, TextField } from "@mui/material";
|
import { Autocomplete, Box, TextField } from "@mui/material";
|
||||||
import { Edit, useAutocomplete } from "@refinedev/mui";
|
import { Edit, useAutocomplete } from "@refinedev/mui";
|
||||||
import { useForm } from "@refinedev/react-hook-form";
|
import { useForm } from "@refinedev/react-hook-form";
|
||||||
|
import { languageStore, META_LANGUAGE } from "@stores";
|
||||||
|
import { LanguageSelector, MediaData, MediaView } from "@ui";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
import { Controller } from "react-hook-form";
|
import { Controller } from "react-hook-form";
|
||||||
|
|
||||||
export const CarrierEdit = () => {
|
export const CarrierEdit = observer(() => {
|
||||||
|
const { language } = languageStore;
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm();
|
} = useForm({
|
||||||
|
refineCoreProps: META_LANGUAGE(language)
|
||||||
|
});
|
||||||
|
|
||||||
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
||||||
resource: "city",
|
resource: "city",
|
||||||
@ -20,6 +27,7 @@ export const CarrierEdit = () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
...META_LANGUAGE("ru")
|
||||||
});
|
});
|
||||||
|
|
||||||
const { autocompleteProps: mediaAutocompleteProps } = useAutocomplete({
|
const { autocompleteProps: mediaAutocompleteProps } = useAutocomplete({
|
||||||
@ -31,6 +39,7 @@ export const CarrierEdit = () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
...META_LANGUAGE(language)
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -40,6 +49,7 @@ export const CarrierEdit = () => {
|
|||||||
sx={{ display: "flex", flexDirection: "column" }}
|
sx={{ display: "flex", flexDirection: "column" }}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
>
|
>
|
||||||
|
<LanguageSelector />
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="city_id"
|
name="city_id"
|
||||||
@ -110,70 +120,77 @@ export const CarrierEdit = () => {
|
|||||||
name="short_name"
|
name="short_name"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<Box component="form"
|
||||||
{...register("main_color", {
|
sx={{ display: "flex" }}
|
||||||
// required: 'Это поле является обязательным',
|
autoComplete="off"
|
||||||
})}
|
>
|
||||||
error={!!(errors as any)?.main_color}
|
<TextField
|
||||||
helperText={(errors as any)?.main_color?.message}
|
{...register("main_color", {
|
||||||
margin="normal"
|
// required: 'Это поле является обязательным',
|
||||||
fullWidth
|
})}
|
||||||
InputLabelProps={{ shrink: true }}
|
error={!!(errors as any)?.main_color}
|
||||||
type="color"
|
helperText={(errors as any)?.main_color?.message}
|
||||||
label={"Основной цвет"}
|
margin="normal"
|
||||||
name="main_color"
|
fullWidth
|
||||||
sx={{
|
InputLabelProps={{ shrink: true }}
|
||||||
"& input": {
|
type="color"
|
||||||
height: "50px",
|
label={"Основной цвет"}
|
||||||
paddingBlock: "14px",
|
name="main_color"
|
||||||
paddingInline: "14px",
|
sx={{
|
||||||
cursor: "pointer",
|
"& input": {
|
||||||
},
|
height: "50px",
|
||||||
}}
|
paddingBlock: "14px",
|
||||||
/>
|
paddingInline: "14px",
|
||||||
|
cursor: "pointer",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
{...register("left_color", {
|
{...register("left_color", {
|
||||||
// required: 'Это поле является обязательным',
|
// required: 'Это поле является обязательным',
|
||||||
})}
|
})}
|
||||||
error={!!(errors as any)?.left_color}
|
error={!!(errors as any)?.left_color}
|
||||||
helperText={(errors as any)?.left_color?.message}
|
helperText={(errors as any)?.left_color?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
type="color"
|
type="color"
|
||||||
label={"Цвет левого виджета"}
|
label={"Цвет левого виджета"}
|
||||||
name="left_color"
|
name="left_color"
|
||||||
sx={{
|
sx={{
|
||||||
"& input": {
|
marginLeft: "16px",
|
||||||
height: "50px",
|
marginRight: "16px",
|
||||||
paddingBlock: "14px",
|
"& input": {
|
||||||
paddingInline: "14px",
|
height: "50px",
|
||||||
cursor: "pointer",
|
paddingBlock: "14px",
|
||||||
},
|
paddingInline: "14px",
|
||||||
}}
|
cursor: "pointer",
|
||||||
/>
|
},
|
||||||
<TextField
|
}}
|
||||||
{...register("right_color", {
|
/>
|
||||||
// required: 'Это поле является обязательным',
|
<TextField
|
||||||
})}
|
{...register("right_color", {
|
||||||
error={!!(errors as any)?.right_color}
|
// required: 'Это поле является обязательным',
|
||||||
helperText={(errors as any)?.right_color?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.right_color}
|
||||||
fullWidth
|
helperText={(errors as any)?.right_color?.message}
|
||||||
InputLabelProps={{ shrink: true }}
|
margin="normal"
|
||||||
type="color"
|
fullWidth
|
||||||
label={"Цвет правого виджета"}
|
InputLabelProps={{ shrink: true }}
|
||||||
name="right_color"
|
type="color"
|
||||||
sx={{
|
label={"Цвет правого виджета"}
|
||||||
"& input": {
|
name="right_color"
|
||||||
height: "50px",
|
sx={{
|
||||||
paddingBlock: "14px",
|
"& input": {
|
||||||
paddingInline: "14px",
|
height: "50px",
|
||||||
cursor: "pointer",
|
paddingBlock: "14px",
|
||||||
},
|
paddingInline: "14px",
|
||||||
}}
|
cursor: "pointer",
|
||||||
/>
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
{...register("slogan", {
|
{...register("slogan", {
|
||||||
@ -231,7 +248,10 @@ export const CarrierEdit = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<Box height={150} sx={{display: "flex", justifyContent: "start"}}>
|
||||||
|
<MediaView media={{id: watch("logo"), media_type: 1}} />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Edit>
|
</Edit>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Box, Stack, Typography } from "@mui/material";
|
import { Box, Stack, Typography } from "@mui/material";
|
||||||
import { useShow } from "@refinedev/core";
|
import { useShow } from "@refinedev/core";
|
||||||
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
|
import { MediaView } from "@ui";
|
||||||
|
|
||||||
export type FieldType = {
|
export type FieldType = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -81,13 +82,9 @@ export const CarrierShow = () => {
|
|||||||
label: "Логотип",
|
label: "Логотип",
|
||||||
data: "logo",
|
data: "logo",
|
||||||
render: (value: number) => (
|
render: (value: number) => (
|
||||||
<img
|
<Box height={150} sx={{display: "flex", justifyContent: "start"}}>
|
||||||
src={`${
|
<MediaView media={{id: value, media_type: 1}} />
|
||||||
import.meta.env.VITE_KRBL_MEDIA
|
</Box>
|
||||||
}${value}/download?token=${localStorage.getItem(TOKEN_KEY)}`}
|
|
||||||
alt={String(value)}
|
|
||||||
style={{ maxWidth: "10%", objectFit: "contain", borderRadius: 8 }}
|
|
||||||
/>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -1,18 +1,26 @@
|
|||||||
import {Autocomplete, Box, TextField} from '@mui/material'
|
import {Autocomplete, Box, TextField} from '@mui/material'
|
||||||
import {Edit, useAutocomplete} from '@refinedev/mui'
|
import {Edit, useAutocomplete} from '@refinedev/mui'
|
||||||
import {useForm} from '@refinedev/react-hook-form'
|
import {useForm} from '@refinedev/react-hook-form'
|
||||||
|
import { EVERY_LANGUAGE, Languages, languageStore, META_LANGUAGE } from '@stores'
|
||||||
|
import { LanguageSelector } from '@ui'
|
||||||
|
import { observer } from 'mobx-react-lite'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
import {Controller} from 'react-hook-form'
|
import {Controller} from 'react-hook-form'
|
||||||
|
|
||||||
export const CityEdit = () => {
|
export const CityEdit = observer(() => {
|
||||||
|
const { language } = languageStore;
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
formState: {errors},
|
formState: {errors},
|
||||||
} = useForm({})
|
} = useForm({
|
||||||
|
refineCoreProps: META_LANGUAGE(language)
|
||||||
|
})
|
||||||
|
|
||||||
const {autocompleteProps: countryAutocompleteProps} = useAutocomplete({
|
const {autocompleteProps: countryAutocompleteProps} = useAutocomplete({
|
||||||
resource: 'country',
|
resource: 'country',
|
||||||
|
...META_LANGUAGE(language)
|
||||||
})
|
})
|
||||||
|
|
||||||
const {autocompleteProps: mediaAutocompleteProps} = useAutocomplete({
|
const {autocompleteProps: mediaAutocompleteProps} = useAutocomplete({
|
||||||
@ -24,11 +32,14 @@ export const CityEdit = () => {
|
|||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
...META_LANGUAGE(language)
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edit saveButtonProps={saveButtonProps}>
|
<Edit saveButtonProps={saveButtonProps}>
|
||||||
<Box component="form" sx={{display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
<Box component="form" sx={{display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
||||||
|
<LanguageSelector/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="country_code"
|
name="country_code"
|
||||||
@ -94,4 +105,4 @@ export const CityEdit = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Edit>
|
</Edit>
|
||||||
)
|
)
|
||||||
}
|
})
|
@ -1,7 +1,7 @@
|
|||||||
import { Stack, Typography } from "@mui/material";
|
import { Stack, Typography } from "@mui/material";
|
||||||
import { useShow } from "@refinedev/core";
|
import { useShow } from "@refinedev/core";
|
||||||
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
|
|
||||||
export const CityShow = () => {
|
export const CityShow = () => {
|
||||||
const { query } = useShow({});
|
const { query } = useShow({});
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import { Box, TextField } from "@mui/material";
|
import { Box, TextField } from "@mui/material";
|
||||||
import { Edit } from "@refinedev/mui";
|
import { Edit } from "@refinedev/mui";
|
||||||
import { useForm } from "@refinedev/react-hook-form";
|
import { useForm } from "@refinedev/react-hook-form";
|
||||||
|
import { languageStore, META_LANGUAGE } from "@stores";
|
||||||
|
import { LanguageSelector } from "@ui";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
export const CountryEdit = () => {
|
export const CountryEdit = observer(() => {
|
||||||
|
const { language } = languageStore;
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
register,
|
register,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm({});
|
} = useForm({
|
||||||
|
refineCoreProps: META_LANGUAGE(language)
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edit saveButtonProps={saveButtonProps}>
|
<Edit saveButtonProps={saveButtonProps}>
|
||||||
@ -16,6 +22,7 @@ export const CountryEdit = () => {
|
|||||||
sx={{ display: "flex", flexDirection: "column" }}
|
sx={{ display: "flex", flexDirection: "column" }}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
>
|
>
|
||||||
|
<LanguageSelector />
|
||||||
<TextField
|
<TextField
|
||||||
{...register("code", {
|
{...register("code", {
|
||||||
required: "Это поле является обязательным",
|
required: "Это поле является обязательным",
|
||||||
@ -27,6 +34,7 @@ export const CountryEdit = () => {
|
|||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
type="text"
|
type="text"
|
||||||
label={"Код *"}
|
label={"Код *"}
|
||||||
|
disabled
|
||||||
name="code"
|
name="code"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
@ -45,4 +53,4 @@ export const CountryEdit = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Edit>
|
</Edit>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
useMediaFileUpload,
|
useMediaFileUpload,
|
||||||
} from "../../components/media/MediaFormUtils";
|
} from "../../components/media/MediaFormUtils";
|
||||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||||
import { ModelViewer } from "./ModelViewer/index";
|
import { ModelViewer } from "@ui";
|
||||||
|
|
||||||
type MediaFormValues = {
|
type MediaFormValues = {
|
||||||
media_name: string;
|
media_name: string;
|
||||||
|
@ -11,8 +11,8 @@ import { useEffect } from "react";
|
|||||||
import { useShow } from "@refinedev/core";
|
import { useShow } from "@refinedev/core";
|
||||||
import { Controller } from "react-hook-form";
|
import { Controller } from "react-hook-form";
|
||||||
|
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
import { MEDIA_TYPES } from "../../lib/constants";
|
import { MEDIA_TYPES } from "@lib";
|
||||||
import {
|
import {
|
||||||
ALLOWED_IMAGE_TYPES,
|
ALLOWED_IMAGE_TYPES,
|
||||||
ALLOWED_VIDEO_TYPES,
|
ALLOWED_VIDEO_TYPES,
|
||||||
@ -22,6 +22,9 @@ import {
|
|||||||
ALLOWED_3D_MODEL_TYPES,
|
ALLOWED_3D_MODEL_TYPES,
|
||||||
useMediaFileUpload,
|
useMediaFileUpload,
|
||||||
} from "../../components/media/MediaFormUtils";
|
} from "../../components/media/MediaFormUtils";
|
||||||
|
import { languageStore, META_LANGUAGE } from "@stores";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { LanguageSelector, MediaData, MediaView } from "@ui";
|
||||||
|
|
||||||
type MediaFormValues = {
|
type MediaFormValues = {
|
||||||
media_name: string;
|
media_name: string;
|
||||||
@ -29,7 +32,8 @@ type MediaFormValues = {
|
|||||||
file?: File;
|
file?: File;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MediaEdit = () => {
|
export const MediaEdit = observer(() => {
|
||||||
|
const { language } = languageStore;
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
refineCore: { onFinish },
|
refineCore: { onFinish },
|
||||||
@ -47,6 +51,7 @@ export const MediaEdit = () => {
|
|||||||
media_type: "",
|
media_type: "",
|
||||||
file: undefined,
|
file: undefined,
|
||||||
},
|
},
|
||||||
|
refineCoreProps: META_LANGUAGE(language)
|
||||||
});
|
});
|
||||||
|
|
||||||
const { query } = useShow();
|
const { query } = useShow();
|
||||||
@ -100,6 +105,7 @@ export const MediaEdit = () => {
|
|||||||
sx={{ display: "flex", flexDirection: "column" }}
|
sx={{ display: "flex", flexDirection: "column" }}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
>
|
>
|
||||||
|
<LanguageSelector />
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="media_type"
|
name="media_type"
|
||||||
@ -177,7 +183,7 @@ export const MediaEdit = () => {
|
|||||||
hidden
|
hidden
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
accept={
|
accept={
|
||||||
selectedMediaType === 1
|
selectedMediaType === 1
|
||||||
? ALLOWED_IMAGE_TYPES.join(",")
|
? ALLOWED_IMAGE_TYPES.join(",")
|
||||||
: selectedMediaType === 2
|
: selectedMediaType === 2
|
||||||
? ALLOWED_VIDEO_TYPES.join(",")
|
? ALLOWED_VIDEO_TYPES.join(",")
|
||||||
@ -207,7 +213,9 @@ export const MediaEdit = () => {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{previewUrl && selectedMediaType === 1 && (
|
|
||||||
|
<MediaView media={record as MediaData} />
|
||||||
|
{/* {previewUrl && selectedMediaType === 1 && (
|
||||||
<Box mt={2} display="flex" justifyContent="center">
|
<Box mt={2} display="flex" justifyContent="center">
|
||||||
<img
|
<img
|
||||||
src={previewUrl}
|
src={previewUrl}
|
||||||
@ -215,9 +223,9 @@ export const MediaEdit = () => {
|
|||||||
style={{ maxWidth: "200px", borderRadius: 8 }}
|
style={{ maxWidth: "200px", borderRadius: 8 }}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)} */}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Edit>
|
</Edit>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -3,11 +3,16 @@ import {CustomDataGrid} from '../../components/CustomDataGrid'
|
|||||||
import {DeleteButton, EditButton, List, ShowButton, useDataGrid} from '@refinedev/mui'
|
import {DeleteButton, EditButton, List, ShowButton, useDataGrid} from '@refinedev/mui'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {MEDIA_TYPES} from '../../lib/constants'
|
import {MEDIA_TYPES} from '../../lib/constants'
|
||||||
|
import { observer } from "mobx-react-lite"
|
||||||
|
|
||||||
import {localeText} from '../../locales/ru/localeText'
|
import {localeText} from '../../locales/ru/localeText'
|
||||||
|
import { languageStore, META_LANGUAGE } from '@stores'
|
||||||
|
|
||||||
export const MediaList = () => {
|
export const MediaList = observer(() => {
|
||||||
const {dataGridProps} = useDataGrid({})
|
const { language } = languageStore;
|
||||||
|
const {dataGridProps} = useDataGrid({
|
||||||
|
...META_LANGUAGE(language)
|
||||||
|
})
|
||||||
|
|
||||||
const columns = React.useMemo<GridColDef[]>(
|
const columns = React.useMemo<GridColDef[]>(
|
||||||
() => [
|
() => [
|
||||||
@ -77,7 +82,7 @@ export const MediaList = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<List>
|
<List>
|
||||||
<CustomDataGrid {...dataGridProps} columns={columns} localeText={localeText} getRowId={(row: any) => row.id} />
|
<CustomDataGrid {...dataGridProps} columns={columns} localeText={localeText} getRowId={(row: any) => row.id} languageEnabled/>
|
||||||
</List>
|
</List>
|
||||||
)
|
)
|
||||||
}
|
});
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import { Stack, Typography, Box, Button } from "@mui/material";
|
import { Stack, Typography, Box, Button } from "@mui/material";
|
||||||
import { useShow } from "@refinedev/core";
|
import { useShow } from "@refinedev/core";
|
||||||
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
||||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
import { MEDIA_TYPES } from "@lib";
|
||||||
import sky from "./12414.jpg";
|
import { TOKEN_KEY } from "@providers";
|
||||||
import { MEDIA_TYPES } from "../../lib/constants";
|
import { MediaData, MediaView } from "@ui";
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
|
||||||
import { ModelViewer } from "./ModelViewer/index";
|
|
||||||
|
|
||||||
export const MediaShow = () => {
|
export const MediaShow = () => {
|
||||||
const { query } = useShow({});
|
const { query } = useShow({});
|
||||||
@ -29,83 +27,7 @@ export const MediaShow = () => {
|
|||||||
return (
|
return (
|
||||||
<Show isLoading={isLoading}>
|
<Show isLoading={isLoading}>
|
||||||
<Stack gap={4}>
|
<Stack gap={4}>
|
||||||
{record && record.media_type === 1 && (
|
<MediaView media={record as MediaData} />
|
||||||
<img
|
|
||||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
|
||||||
record?.id
|
|
||||||
}/download?token=${token}`}
|
|
||||||
alt={record?.filename}
|
|
||||||
style={{
|
|
||||||
maxWidth: "100%",
|
|
||||||
height: "40vh",
|
|
||||||
objectFit: "contain",
|
|
||||||
borderRadius: 8,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{record && record.media_type === 2 && (
|
|
||||||
<video
|
|
||||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
|
||||||
record?.id
|
|
||||||
}/download?token=${token}`}
|
|
||||||
style={{
|
|
||||||
maxWidth: "50%",
|
|
||||||
|
|
||||||
objectFit: "contain",
|
|
||||||
borderRadius: 30,
|
|
||||||
}}
|
|
||||||
controls
|
|
||||||
autoPlay
|
|
||||||
muted
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{record && record.media_type === 3 && (
|
|
||||||
<img
|
|
||||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
|
||||||
record?.id
|
|
||||||
}/download?token=${token}`}
|
|
||||||
alt={record?.filename}
|
|
||||||
style={{
|
|
||||||
maxWidth: "100%",
|
|
||||||
height: "40vh",
|
|
||||||
objectFit: "contain",
|
|
||||||
borderRadius: 8,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{record && record.media_type === 4 && (
|
|
||||||
<img
|
|
||||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
|
||||||
record?.id
|
|
||||||
}/download?token=${token}`}
|
|
||||||
alt={record?.filename}
|
|
||||||
style={{
|
|
||||||
maxWidth: "100%",
|
|
||||||
height: "40vh",
|
|
||||||
objectFit: "contain",
|
|
||||||
borderRadius: 8,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{record && record.media_type === 5 && (
|
|
||||||
<ReactPhotoSphereViewer
|
|
||||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
|
||||||
record?.id
|
|
||||||
}/download?token=${token}`}
|
|
||||||
width={"100%"}
|
|
||||||
height={"80vh"}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{record && record.media_type === 6 && (
|
|
||||||
<ModelViewer
|
|
||||||
fileUrl={`${import.meta.env.VITE_KRBL_MEDIA}${
|
|
||||||
record?.id
|
|
||||||
}/download?token=${token}`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{fields.map(({ label, data, render }) => (
|
{fields.map(({ label, data, render }) => (
|
||||||
<Stack key={data} gap={1}>
|
<Stack key={data} gap={1}>
|
||||||
<Typography variant="body1" fontWeight="bold">
|
<Typography variant="body1" fontWeight="bold">
|
||||||
|
@ -5,11 +5,12 @@ import {
|
|||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Typography,
|
Typography,
|
||||||
|
Button,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { Edit, useAutocomplete } from "@refinedev/mui";
|
import { Edit, 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 { useParams } from "react-router";
|
import { useNavigate, useParams } from "react-router";
|
||||||
import { LinkedItems } from "../../components/LinkedItems";
|
import { LinkedItems } from "../../components/LinkedItems";
|
||||||
import {
|
import {
|
||||||
StationItem,
|
StationItem,
|
||||||
@ -29,6 +30,7 @@ export const RouteEdit = () => {
|
|||||||
setValue,
|
setValue,
|
||||||
watch,
|
watch,
|
||||||
} = useForm({});
|
} = useForm({});
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { id: routeId } = useParams<{ id: string }>();
|
const { id: routeId } = useParams<{ id: string }>();
|
||||||
|
|
||||||
@ -53,38 +55,213 @@ export const RouteEdit = () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { autocompleteProps: governorAppealAutocompleteProps } = useAutocomplete({
|
||||||
|
resource: "article",
|
||||||
|
|
||||||
|
onSearch: (value) => [
|
||||||
|
{
|
||||||
|
field: "heading",
|
||||||
|
operator: "contains",
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "media_type",
|
||||||
|
operator: "contains",
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edit saveButtonProps={saveButtonProps}>
|
<Edit saveButtonProps={saveButtonProps}>
|
||||||
<Box
|
<Box
|
||||||
component="form"
|
sx={{display: "flex", flexDirection: "column", gap:1}}
|
||||||
sx={{ display: "flex", flexDirection: "column" }}
|
|
||||||
autoComplete="off"
|
|
||||||
>
|
>
|
||||||
<Controller
|
<Box
|
||||||
|
component="form"
|
||||||
|
sx={{ display: "flex", flexDirection: "column"}}
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="carrier_id"
|
||||||
|
rules={{ required: "Это поле является обязательным" }}
|
||||||
|
defaultValue={null}
|
||||||
|
render={({ field }) => (
|
||||||
|
<Autocomplete
|
||||||
|
{...carrierAutocompleteProps}
|
||||||
|
value={
|
||||||
|
carrierAutocompleteProps.options.find(
|
||||||
|
(option) => option.id === field.value
|
||||||
|
) || null
|
||||||
|
}
|
||||||
|
onChange={(_, value) => {
|
||||||
|
field.onChange(value?.id || "");
|
||||||
|
}}
|
||||||
|
getOptionLabel={(item) => {
|
||||||
|
return item ? item.short_name : "";
|
||||||
|
}}
|
||||||
|
isOptionEqualToValue={(option, value) => {
|
||||||
|
return option.id === value?.id;
|
||||||
|
}}
|
||||||
|
filterOptions={(options, { inputValue }) => {
|
||||||
|
return options.filter((option) =>
|
||||||
|
option.short_name
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(inputValue.toLowerCase())
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
label="Выберите перевозчика"
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
error={!!errors.carrier_id}
|
||||||
|
helperText={(errors as any)?.carrier_id?.message}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...register("route_number", {
|
||||||
|
required: "Это поле является обязательным",
|
||||||
|
setValueAs: (value) => String(value),
|
||||||
|
})}
|
||||||
|
error={!!(errors as any)?.route_number}
|
||||||
|
helperText={(errors as any)?.route_number?.message}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type="text"
|
||||||
|
label={"Номер маршрута"}
|
||||||
|
name="route_number"
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="route_direction" // boolean
|
||||||
|
control={control}
|
||||||
|
defaultValue={false}
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormControlLabel
|
||||||
|
label="Прямой маршрут?"
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
{...field}
|
||||||
|
checked={field.value}
|
||||||
|
onChange={(e) => field.onChange(e.target.checked)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
color="textSecondary"
|
||||||
|
sx={{ mt: 0, mb: 1 }}
|
||||||
|
>
|
||||||
|
(Прямой / Обратный)
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...register("path", {
|
||||||
|
required: "Это поле является обязательным",
|
||||||
|
setValueAs: (value: string) => {
|
||||||
|
try {
|
||||||
|
const lines = value.trim().split("\n");
|
||||||
|
return lines.map((line) => {
|
||||||
|
const [lat, lon] = line
|
||||||
|
.trim()
|
||||||
|
.split(/[\s,]+/)
|
||||||
|
.map(Number);
|
||||||
|
return [lat, lon];
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validate: (value: unknown) => {
|
||||||
|
if (!Array.isArray(value)) return "Неверный формат";
|
||||||
|
if (value.length === 0)
|
||||||
|
return "Введите хотя бы одну пару координат";
|
||||||
|
if (
|
||||||
|
!value.every(
|
||||||
|
(point: unknown) => Array.isArray(point) && point.length === 2
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return "Каждая строка должна содержать две координаты";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!value.every((point: unknown[]) =>
|
||||||
|
point.every(
|
||||||
|
(coord: unknown) =>
|
||||||
|
!isNaN(Number(coord)) && typeof coord === "number"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return "Координаты должны быть числами";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
error={!!(errors as any)?.path}
|
||||||
|
helperText={(errors as any)?.path?.message}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type="text"
|
||||||
|
label={"Координаты маршрута *"}
|
||||||
|
name="path"
|
||||||
|
placeholder="55.7558 37.6173
|
||||||
|
55.7539 37.6208"
|
||||||
|
multiline
|
||||||
|
rows={4}
|
||||||
|
sx={{
|
||||||
|
marginBottom: 2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...register("route_sys_number", {
|
||||||
|
required: "Это поле является обязательным",
|
||||||
|
})}
|
||||||
|
error={!!(errors as any)?.route_sys_number}
|
||||||
|
helperText={(errors as any)?.route_sys_number?.message}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type="number"
|
||||||
|
label={"Системный номер маршрута *"}
|
||||||
|
name="route_sys_number"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="carrier_id"
|
name="governor_appeal"
|
||||||
rules={{ required: "Это поле является обязательным" }}
|
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...carrierAutocompleteProps}
|
{...governorAppealAutocompleteProps}
|
||||||
value={
|
value={
|
||||||
carrierAutocompleteProps.options.find(
|
governorAppealAutocompleteProps.options.find(
|
||||||
(option) => option.id === field.value
|
(option) => option.id === field.value
|
||||||
) || null
|
) ?? null
|
||||||
}
|
}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || "");
|
field.onChange(value?.id ?? "");
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.short_name : "";
|
return item ? item.heading : "";
|
||||||
}}
|
}}
|
||||||
isOptionEqualToValue={(option, value) => {
|
isOptionEqualToValue={(option, value) => {
|
||||||
return option.id === value?.id;
|
return option.id === value?.id;
|
||||||
}}
|
}}
|
||||||
filterOptions={(options, { inputValue }) => {
|
filterOptions={(options, { inputValue }) => {
|
||||||
return options.filter((option) =>
|
return options.filter((option) =>
|
||||||
option.short_name
|
option.heading
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(inputValue.toLowerCase())
|
.includes(inputValue.toLowerCase())
|
||||||
);
|
);
|
||||||
@ -92,242 +269,128 @@ export const RouteEdit = () => {
|
|||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField
|
<TextField
|
||||||
{...params}
|
{...params}
|
||||||
label="Выберите перевозчика"
|
label="Обращение губернатора"
|
||||||
margin="normal"
|
margin="normal"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
error={!!errors.carrier_id}
|
error={!!errors.arms}
|
||||||
helperText={(errors as any)?.carrier_id?.message}
|
helperText={(errors as any)?.arms?.message}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
{...register("route_number", {
|
{...register("scale_min", {
|
||||||
required: "Это поле является обязательным",
|
// required: 'Это поле является обязательным',
|
||||||
setValueAs: (value) => String(value),
|
setValueAs: (value) => Number(value),
|
||||||
})}
|
})}
|
||||||
error={!!(errors as any)?.route_number}
|
error={!!(errors as any)?.scale_min}
|
||||||
helperText={(errors as any)?.route_number?.message}
|
helperText={(errors as any)?.scale_min?.message}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
fullWidth
|
fullWidth
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
type="text"
|
type="number"
|
||||||
label={"Номер маршрута"}
|
label={"Масштаб (мин)"}
|
||||||
name="route_number"
|
name="scale_min"
|
||||||
/>
|
/>
|
||||||
<Controller
|
|
||||||
name="route_direction" // boolean
|
<TextField
|
||||||
control={control}
|
{...register("scale_max", {
|
||||||
defaultValue={false}
|
// required: 'Это поле является обязательным',
|
||||||
render={({ field }: { field: any }) => (
|
setValueAs: (value) => Number(value),
|
||||||
<FormControlLabel
|
})}
|
||||||
label="Прямой маршрут?"
|
error={!!(errors as any)?.scale_max}
|
||||||
control={
|
helperText={(errors as any)?.scale_max?.message}
|
||||||
<Checkbox
|
margin="normal"
|
||||||
{...field}
|
fullWidth
|
||||||
checked={field.value}
|
InputLabelProps={{ shrink: true }}
|
||||||
onChange={(e) => field.onChange(e.target.checked)}
|
type="number"
|
||||||
/>
|
label={"Масштаб (макс)"}
|
||||||
}
|
name="scale_max"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...register("rotate", {
|
||||||
|
// required: 'Это поле является обязательным',
|
||||||
|
setValueAs: (value) => Number(value),
|
||||||
|
})}
|
||||||
|
error={!!(errors as any)?.rotate}
|
||||||
|
helperText={(errors as any)?.rotate?.message}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type="number"
|
||||||
|
label={"Поворот"}
|
||||||
|
name="rotate"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...register("center_latitude", {
|
||||||
|
// required: 'Это поле является обязательным',
|
||||||
|
setValueAs: (value) => Number(value),
|
||||||
|
})}
|
||||||
|
error={!!(errors as any)?.center_latitude}
|
||||||
|
helperText={(errors as any)?.center_latitude?.message}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type="number"
|
||||||
|
label={"Центр. широта"}
|
||||||
|
name="center_latitude"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...register("center_longitude", {
|
||||||
|
// required: 'Это поле является обязательным',
|
||||||
|
setValueAs: (value) => Number(value),
|
||||||
|
})}
|
||||||
|
error={!!(errors as any)?.center_longitude}
|
||||||
|
helperText={(errors as any)?.center_longitude?.message}
|
||||||
|
margin="normal"
|
||||||
|
fullWidth
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
type="number"
|
||||||
|
label={"Центр. долгота"}
|
||||||
|
name="center_longitude"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{routeId && (
|
||||||
|
<>
|
||||||
|
<LinkedItems<StationItem>
|
||||||
|
type="edit"
|
||||||
|
parentId={routeId}
|
||||||
|
parentResource="route"
|
||||||
|
childResource="station"
|
||||||
|
fields={stationFields}
|
||||||
|
title="станции"
|
||||||
|
dragAllowed={true}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Typography
|
<LinkedItems<VehicleItem>
|
||||||
variant="caption"
|
type="edit"
|
||||||
color="textSecondary"
|
parentId={routeId}
|
||||||
sx={{ mt: 0, mb: 1 }}
|
parentResource="route"
|
||||||
>
|
childResource="vehicle"
|
||||||
(Прямой / Обратный)
|
fields={vehicleFields}
|
||||||
</Typography>
|
title="транспортные средства"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<TextField
|
<Box sx={{ display: 'flex', justifyContent: 'flex-start' }}>
|
||||||
{...register("path", {
|
<Button
|
||||||
required: "Это поле является обязательным",
|
variant="contained"
|
||||||
setValueAs: (value: string) => {
|
color="primary"
|
||||||
try {
|
onClick={() => navigate(`/route-preview/${routeId}`)}
|
||||||
const lines = value.trim().split("\n");
|
>
|
||||||
return lines.map((line) => {
|
Предпросмотр маршрута
|
||||||
const [lat, lon] = line
|
</Button>
|
||||||
.trim()
|
</Box>
|
||||||
.split(/[\s,]+/)
|
|
||||||
.map(Number);
|
|
||||||
return [lat, lon];
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
validate: (value: unknown) => {
|
|
||||||
if (!Array.isArray(value)) return "Неверный формат";
|
|
||||||
if (value.length === 0)
|
|
||||||
return "Введите хотя бы одну пару координат";
|
|
||||||
if (
|
|
||||||
!value.every(
|
|
||||||
(point: unknown) => Array.isArray(point) && point.length === 2
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return "Каждая строка должна содержать две координаты";
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!value.every((point: unknown[]) =>
|
|
||||||
point.every(
|
|
||||||
(coord: unknown) =>
|
|
||||||
!isNaN(Number(coord)) && typeof coord === "number"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return "Координаты должны быть числами";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.path}
|
|
||||||
helperText={(errors as any)?.path?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="text"
|
|
||||||
label={"Координаты маршрута *"}
|
|
||||||
name="path"
|
|
||||||
placeholder="55.7558 37.6173
|
|
||||||
55.7539 37.6208"
|
|
||||||
multiline
|
|
||||||
rows={4}
|
|
||||||
sx={{
|
|
||||||
marginBottom: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("route_sys_number", {
|
|
||||||
required: "Это поле является обязательным",
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.route_sys_number}
|
|
||||||
helperText={(errors as any)?.route_sys_number?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Системный номер маршрута *"}
|
|
||||||
name="route_sys_number"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("governor_appeal", {
|
|
||||||
// required: 'Это поле является обязательным',
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.governor_appeal}
|
|
||||||
helperText={(errors as any)?.governor_appeal?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Обращение губернатора"}
|
|
||||||
name="governor_appeal"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("scale_min", {
|
|
||||||
// required: 'Это поле является обязательным',
|
|
||||||
setValueAs: (value) => Number(value),
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.scale_min}
|
|
||||||
helperText={(errors as any)?.scale_min?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Масштаб (мин)"}
|
|
||||||
name="scale_min"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("scale_max", {
|
|
||||||
// required: 'Это поле является обязательным',
|
|
||||||
setValueAs: (value) => Number(value),
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.scale_max}
|
|
||||||
helperText={(errors as any)?.scale_max?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Масштаб (макс)"}
|
|
||||||
name="scale_max"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("rotate", {
|
|
||||||
// required: 'Это поле является обязательным',
|
|
||||||
setValueAs: (value) => Number(value),
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.rotate}
|
|
||||||
helperText={(errors as any)?.rotate?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Поворот"}
|
|
||||||
name="rotate"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("center_latitude", {
|
|
||||||
// required: 'Это поле является обязательным',
|
|
||||||
setValueAs: (value) => Number(value),
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.center_latitude}
|
|
||||||
helperText={(errors as any)?.center_latitude?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Центр. широта"}
|
|
||||||
name="center_latitude"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
|
||||||
{...register("center_longitude", {
|
|
||||||
// required: 'Это поле является обязательным',
|
|
||||||
setValueAs: (value) => Number(value),
|
|
||||||
})}
|
|
||||||
error={!!(errors as any)?.center_longitude}
|
|
||||||
helperText={(errors as any)?.center_longitude?.message}
|
|
||||||
margin="normal"
|
|
||||||
fullWidth
|
|
||||||
InputLabelProps={{ shrink: true }}
|
|
||||||
type="number"
|
|
||||||
label={"Центр. долгота"}
|
|
||||||
name="center_longitude"
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{routeId && (
|
|
||||||
<>
|
|
||||||
<LinkedItems<StationItem>
|
|
||||||
type="edit"
|
|
||||||
parentId={routeId}
|
|
||||||
parentResource="route"
|
|
||||||
childResource="station"
|
|
||||||
fields={stationFields}
|
|
||||||
title="станции"
|
|
||||||
dragAllowed={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<LinkedItems<VehicleItem>
|
|
||||||
type="edit"
|
|
||||||
parentId={routeId}
|
|
||||||
parentResource="route"
|
|
||||||
childResource="vehicle"
|
|
||||||
fields={vehicleFields}
|
|
||||||
title="транспортные средства"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Edit>
|
</Edit>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -7,12 +7,15 @@ import {
|
|||||||
ShowButton,
|
ShowButton,
|
||||||
useDataGrid,
|
useDataGrid,
|
||||||
} from "@refinedev/mui";
|
} from "@refinedev/mui";
|
||||||
import { Typography } from "@mui/material";
|
import { Button, Typography } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import MapIcon from '@mui/icons-material/Map';
|
||||||
|
|
||||||
import { localeText } from "../../locales/ru/localeText";
|
import { localeText } from "../../locales/ru/localeText";
|
||||||
|
import { useLink } from "@refinedev/core";
|
||||||
|
|
||||||
export const RouteList = () => {
|
export const RouteList = () => {
|
||||||
|
const Link = useLink();
|
||||||
const { dataGridProps } = useDataGrid({
|
const { dataGridProps } = useDataGrid({
|
||||||
resource: "route/",
|
resource: "route/",
|
||||||
});
|
});
|
||||||
@ -123,10 +126,10 @@ export const RouteList = () => {
|
|||||||
headerName: "Направление маршрута",
|
headerName: "Направление маршрута",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
flex: 1,
|
||||||
align: "left",
|
align: "left",
|
||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
flex: 1,
|
|
||||||
renderCell: ({ value }) => (
|
renderCell: ({ value }) => (
|
||||||
<Typography style={{ color: value ? "#48989f" : "#7f6b58" }}>
|
<Typography style={{ color: value ? "#48989f" : "#7f6b58" }}>
|
||||||
{value ? "прямое" : "обратное"}
|
{value ? "прямое" : "обратное"}
|
||||||
@ -139,7 +142,7 @@ export const RouteList = () => {
|
|||||||
cellClassName: "route-actions",
|
cellClassName: "route-actions",
|
||||||
align: "right",
|
align: "right",
|
||||||
headerAlign: "center",
|
headerAlign: "center",
|
||||||
minWidth: 120,
|
minWidth: 160,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
sortable: false,
|
sortable: false,
|
||||||
filterable: false,
|
filterable: false,
|
||||||
@ -148,6 +151,11 @@ export const RouteList = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EditButton hideText recordItemId={row.id} />
|
<EditButton hideText recordItemId={row.id} />
|
||||||
|
<Link to={`/route-preview/${row.id}`}>
|
||||||
|
<Button sx={{minWidth: 0}} >
|
||||||
|
<MapIcon fontSize="small" />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
<ShowButton hideText recordItemId={row.id} />
|
<ShowButton hideText recordItemId={row.id} />
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
hideText
|
hideText
|
||||||
|
@ -5,6 +5,8 @@ import { LinkedItems } from "../../components/LinkedItems";
|
|||||||
import {
|
import {
|
||||||
StationItem,
|
StationItem,
|
||||||
VehicleItem,
|
VehicleItem,
|
||||||
|
SightItem,
|
||||||
|
sightFields,
|
||||||
stationFields,
|
stationFields,
|
||||||
vehicleFields,
|
vehicleFields,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
@ -88,6 +90,15 @@ export const RouteShow = () => {
|
|||||||
fields={vehicleFields}
|
fields={vehicleFields}
|
||||||
title="транспортные средства"
|
title="транспортные средства"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<LinkedItems<SightItem>
|
||||||
|
type="show"
|
||||||
|
parentId={record.id}
|
||||||
|
parentResource="route"
|
||||||
|
childResource="sight"
|
||||||
|
fields={sightFields}
|
||||||
|
title="достопримечательности"
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -16,6 +16,15 @@ export type VehicleItem = {
|
|||||||
[key: string]: string | number;
|
[key: string]: string | number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SightItem = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
city: string;
|
||||||
|
city_id: number;
|
||||||
|
address: string;
|
||||||
|
[key: string]: string | number;
|
||||||
|
};
|
||||||
|
|
||||||
export type FieldType<T> = {
|
export type FieldType<T> = {
|
||||||
label: string;
|
label: string;
|
||||||
data: keyof T;
|
data: keyof T;
|
||||||
@ -27,6 +36,12 @@ export const stationFields: Array<FieldType<StationItem>> = [
|
|||||||
{ label: "Описание", data: "description" },
|
{ label: "Описание", data: "description" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const sightFields: Array<FieldType<SightItem>> = [
|
||||||
|
{ label: "Название", data: "name" },
|
||||||
|
{ label: "Город", data: "city" },
|
||||||
|
{ label: "Адрес", data: "address" },
|
||||||
|
];
|
||||||
|
|
||||||
export const vehicleFields: Array<FieldType<VehicleItem>> = [
|
export const vehicleFields: Array<FieldType<VehicleItem>> = [
|
||||||
{ label: "Бортовой номер", data: "tail_number" },
|
{ label: "Бортовой номер", data: "tail_number" },
|
||||||
{
|
{
|
||||||
|
@ -2,13 +2,10 @@ import { Autocomplete, Box, TextField, Typography, Paper } 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 { cityStore } from "../../store/CityStore";
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import Cookies from "js-cookie";
|
import { Languages, languageStore, cityStore } from "@stores";
|
||||||
import { useLocation } from "react-router";
|
|
||||||
import { languageStore } from "../../store/LanguageStore";
|
|
||||||
export const SightCreate = observer(() => {
|
export const SightCreate = observer(() => {
|
||||||
const { language, setLanguageAction } = languageStore;
|
const { language, setLanguageAction } = languageStore;
|
||||||
const [sightData, setSightData] = useState({
|
const [sightData, setSightData] = useState({
|
||||||
@ -27,7 +24,7 @@ export const SightCreate = observer(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Состояния для предпросмотра
|
// Состояния для предпросмотра
|
||||||
const handleLanguageChange = (lang: string) => {
|
const handleLanguageChange = (lang: Languages) => {
|
||||||
setSightData((prevData) => ({
|
setSightData((prevData) => ({
|
||||||
...prevData,
|
...prevData,
|
||||||
[language]: {
|
[language]: {
|
||||||
|
@ -16,15 +16,14 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { LinkedItems } from "../../components/LinkedItems";
|
import { LinkedItems } from "../../components/LinkedItems";
|
||||||
import { CreateSightArticle } from "../../components/CreateSightArticle";
|
import { CreateSightArticle } from "../../components/CreateSightArticle";
|
||||||
import { ArticleItem, articleFields } from "./types";
|
import { ArticleItem, articleFields } from "./types";
|
||||||
import { TOKEN_KEY } from "../../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
import { languageStore } from "../../store/LanguageStore";
|
import { Languages, languageStore, articleStore } from "@stores";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { LanguageSwitch } from "../../components/LanguageSwitch/index";
|
import { LanguageSwitch } from "../../components/LanguageSwitch/index";
|
||||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||||
import { ModelViewer } from "../media/ModelViewer";
|
import { ModelViewer } from "@ui";
|
||||||
import { articleStore } from "../../store/ArticleStore";
|
|
||||||
import { ArticleEditModal } from "../../components/modals/ArticleEditModal/index";
|
import { ArticleEditModal } from "../../components/modals/ArticleEditModal/index";
|
||||||
|
|
||||||
function a11yProps(index: number) {
|
function a11yProps(index: number) {
|
||||||
@ -132,12 +131,7 @@ export const SightEdit = observer(() => {
|
|||||||
operator: "contains",
|
operator: "contains",
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
meta: {
|
|
||||||
headers: {
|
|
||||||
"Accept-Language": language,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { autocompleteProps: articleAutocompleteProps } = useAutocomplete({
|
const { autocompleteProps: articleAutocompleteProps } = useAutocomplete({
|
||||||
@ -154,13 +148,7 @@ export const SightEdit = observer(() => {
|
|||||||
operator: "contains",
|
operator: "contains",
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
|
|
||||||
meta: {
|
|
||||||
headers: {
|
|
||||||
"Accept-Language": language,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -428,7 +416,7 @@ export const SightEdit = observer(() => {
|
|||||||
address: watch("address") ?? "",
|
address: watch("address") ?? "",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
setLanguageAction(lang);
|
setLanguageAction(lang as Languages);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@ -444,8 +432,8 @@ export const SightEdit = observer(() => {
|
|||||||
onChange={(_, newValue) => setTabValue(newValue)}
|
onChange={(_, newValue) => setTabValue(newValue)}
|
||||||
aria-label="basic tabs example"
|
aria-label="basic tabs example"
|
||||||
>
|
>
|
||||||
<Tab label="Левая статья" {...a11yProps(1)} />
|
<Tab label="Левый виджет" {...a11yProps(1)} />
|
||||||
<Tab label="Правая статья" {...a11yProps(2)} />
|
<Tab label="Правый виджет" {...a11yProps(2)} />
|
||||||
<Tab label="Основная информация" {...a11yProps(3)} />
|
<Tab label="Основная информация" {...a11yProps(3)} />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Box>
|
</Box>
|
||||||
@ -1189,7 +1177,7 @@ export const SightEdit = observer(() => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{mediaFile && mediaFile.src && mediaFile.media_type == 5 && (
|
{mediaFile?.src && mediaFile.media_type == 5 && (
|
||||||
<ReactPhotoSphereViewer
|
<ReactPhotoSphereViewer
|
||||||
src={mediaFile.src}
|
src={mediaFile.src}
|
||||||
height={"300px"}
|
height={"300px"}
|
||||||
@ -1217,9 +1205,8 @@ export const SightEdit = observer(() => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{previewSelected &&
|
{previewSelected &&
|
||||||
previewMedia &&
|
previewMedia?.src &&
|
||||||
previewMedia.src &&
|
previewMedia?.media_type === 1 && (
|
||||||
previewMedia.media_type === 1 && (
|
|
||||||
<img
|
<img
|
||||||
src={previewMedia.src}
|
src={previewMedia.src}
|
||||||
alt={previewMedia.filename}
|
alt={previewMedia.filename}
|
||||||
@ -1233,8 +1220,7 @@ export const SightEdit = observer(() => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{previewSelected &&
|
{previewSelected &&
|
||||||
previewMedia &&
|
previewMedia?.media_type === 2 && (
|
||||||
previewMedia.media_type === 2 && (
|
|
||||||
<video
|
<video
|
||||||
src={previewMedia.src}
|
src={previewMedia.src}
|
||||||
style={{
|
style={{
|
||||||
@ -1249,8 +1235,7 @@ export const SightEdit = observer(() => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{previewSelected &&
|
{previewSelected &&
|
||||||
previewMedia &&
|
previewMedia?.media_type === 3 && (
|
||||||
previewMedia.media_type === 3 && (
|
|
||||||
<img
|
<img
|
||||||
src={previewMedia.src}
|
src={previewMedia.src}
|
||||||
alt={previewMedia.filename}
|
alt={previewMedia.filename}
|
||||||
@ -1263,8 +1248,7 @@ export const SightEdit = observer(() => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{previewSelected &&
|
{previewSelected &&
|
||||||
previewMedia &&
|
previewMedia?.media_type === 4 && (
|
||||||
previewMedia.media_type === 4 && (
|
|
||||||
<img
|
<img
|
||||||
src={previewMedia.src}
|
src={previewMedia.src}
|
||||||
alt={previewMedia.filename}
|
alt={previewMedia.filename}
|
||||||
@ -1278,9 +1262,8 @@ export const SightEdit = observer(() => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{previewSelected &&
|
{previewSelected &&
|
||||||
previewMedia &&
|
previewMedia?.src &&
|
||||||
previewMedia.src &&
|
previewMedia?.media_type == 5 && (
|
||||||
previewMedia.media_type == 5 && (
|
|
||||||
<ReactPhotoSphereViewer
|
<ReactPhotoSphereViewer
|
||||||
src={previewMedia.src}
|
src={previewMedia.src}
|
||||||
height={"300px"}
|
height={"300px"}
|
||||||
@ -1289,8 +1272,7 @@ export const SightEdit = observer(() => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{previewSelected &&
|
{previewSelected &&
|
||||||
previewMedia &&
|
previewMedia?.media_type === 6 && (
|
||||||
previewMedia.media_type === 6 && (
|
|
||||||
<ModelViewer height={"400px"} fileUrl={previewMedia.src} />
|
<ModelViewer height={"400px"} fileUrl={previewMedia.src} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import { useForm } from "@refinedev/react-hook-form";
|
|||||||
import { Controller } from "react-hook-form";
|
import { Controller } from "react-hook-form";
|
||||||
|
|
||||||
import { VEHICLE_TYPES } from "../../lib/constants";
|
import { VEHICLE_TYPES } from "../../lib/constants";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { languageStore, META_LANGUAGE } from "@stores";
|
||||||
|
|
||||||
type VehicleFormValues = {
|
type VehicleFormValues = {
|
||||||
tail_number: number;
|
tail_number: number;
|
||||||
@ -11,13 +13,16 @@ type VehicleFormValues = {
|
|||||||
city_id: number;
|
city_id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VehicleEdit = () => {
|
export const VehicleEdit = observer(() => {
|
||||||
|
const { language } = languageStore;
|
||||||
const {
|
const {
|
||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<VehicleFormValues>({});
|
} = useForm<VehicleFormValues>({
|
||||||
|
refineCoreProps: META_LANGUAGE(language)
|
||||||
|
});
|
||||||
|
|
||||||
const { autocompleteProps: carrierAutocompleteProps } = useAutocomplete({
|
const { autocompleteProps: carrierAutocompleteProps } = useAutocomplete({
|
||||||
resource: "carrier",
|
resource: "carrier",
|
||||||
@ -136,4 +141,4 @@ export const VehicleEdit = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Edit>
|
</Edit>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import dataProvider from "@refinedev/simple-rest";
|
import dataProvider from "@refinedev/simple-rest";
|
||||||
|
|
||||||
import { TOKEN_KEY } from "../authProvider";
|
import { TOKEN_KEY } from "@providers";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { languageStore } from "../store/LanguageStore";
|
import { languageStore } from "../store/LanguageStore";
|
||||||
|
@ -2,7 +2,7 @@ import i18n from 'i18next'
|
|||||||
import {initReactI18next} from 'react-i18next'
|
import {initReactI18next} from 'react-i18next'
|
||||||
import {I18nProvider} from '@refinedev/core'
|
import {I18nProvider} from '@refinedev/core'
|
||||||
|
|
||||||
import translationRU from './locales/ru/translation.json'
|
import translationRU from '../locales/ru/translation.json'
|
||||||
|
|
||||||
i18n.use(initReactI18next).init({
|
i18n.use(initReactI18next).init({
|
||||||
resources: {
|
resources: {
|
3
src/providers/index.ts
Normal file
3
src/providers/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './data'
|
||||||
|
export * from './authProvider'
|
||||||
|
export * from './i18nProvider'
|
@ -1,15 +1,34 @@
|
|||||||
import { makeAutoObservable } from "mobx";
|
import { makeAutoObservable } from "mobx";
|
||||||
|
|
||||||
|
export type Languages = "en" | "ru" | "zh";
|
||||||
class LanguageStore {
|
class LanguageStore {
|
||||||
language = "ru";
|
language: Languages = "ru";
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setLanguageAction = (language: string) => {
|
setLanguageAction = (language: Languages) => {
|
||||||
this.language = language;
|
this.language = language;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const languageStore = new LanguageStore();
|
export const languageStore = new LanguageStore();
|
||||||
|
|
||||||
|
export const META_LANGUAGE = (language: Languages) => {
|
||||||
|
return {
|
||||||
|
meta: {
|
||||||
|
headers: {
|
||||||
|
"Accept-Language": language,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EVERY_LANGUAGE = (data: any) => {
|
||||||
|
return {
|
||||||
|
"en": data,
|
||||||
|
"ru": data,
|
||||||
|
"zh": data,
|
||||||
|
}
|
||||||
|
}
|
4
src/store/index.ts
Normal file
4
src/store/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './ArticleStore';
|
||||||
|
export * from './CityStore';
|
||||||
|
export * from './LanguageStore';
|
||||||
|
export * from './StationStore';
|
@ -17,11 +17,12 @@
|
|||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@mt/common-types": ["src/preview/types"],
|
"@stores": ["./src/store"],
|
||||||
"@mt/components": ["src/preview/components"],
|
"@ui": ["./src/components/ui"],
|
||||||
"@mt/i18n": ["src/preview/i18n"],
|
"@providers": ["./src/providers"],
|
||||||
"@mt/widgets": ["src/preview/widgets"],
|
"@lib": ["./src/lib"],
|
||||||
"@mt/utils": ["src/preview/utils"]
|
"@components": ["./src/components"],
|
||||||
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src", "svg.d.ts"],
|
"include": ["src", "svg.d.ts"],
|
||||||
|
@ -7,11 +7,12 @@ export default defineConfig({
|
|||||||
plugins: [svgr(), react()],
|
plugins: [svgr(), react()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@mt/common-types": path.resolve(__dirname, "./src/preview/types"),
|
"@ui": path.resolve(__dirname, "./src/components/ui"),
|
||||||
"@mt/components": path.resolve(__dirname, "./src/preview/components"),
|
"@stores": path.resolve(__dirname, "./src/store"),
|
||||||
"@mt/i18n": path.resolve(__dirname, "./src/preview/i18n"),
|
"@providers": path.resolve(__dirname, "./src/providers"),
|
||||||
"@mt/widgets": path.resolve(__dirname, "./src/preview/widgets"),
|
"@lib": path.resolve(__dirname, "./src/lib"),
|
||||||
"@mt/utils": path.resolve(__dirname, "./src/preview/utils"),
|
"@components": path.resolve(__dirname, "./src/components"),
|
||||||
|
"@": path.resolve(__dirname, "./src/"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
273
yarn.lock
273
yarn.lock
@ -453,10 +453,110 @@
|
|||||||
resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz"
|
resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz"
|
||||||
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
||||||
|
|
||||||
"@esbuild/win32-x64@^0.25.3":
|
"@esbuild/android-arm@0.18.20":
|
||||||
version "0.25.3"
|
version "0.18.20"
|
||||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz"
|
resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz"
|
||||||
integrity sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==
|
integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
|
||||||
|
|
||||||
|
"@esbuild/android-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz"
|
||||||
|
integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
|
||||||
|
|
||||||
|
"@esbuild/android-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz"
|
||||||
|
integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz"
|
||||||
|
integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-arm@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz"
|
||||||
|
integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz"
|
||||||
|
integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz"
|
||||||
|
integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz"
|
||||||
|
integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz"
|
||||||
|
integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz"
|
||||||
|
integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz"
|
||||||
|
integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz"
|
||||||
|
integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz"
|
||||||
|
integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz"
|
||||||
|
integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32@0.18.20":
|
||||||
|
version "0.18.20"
|
||||||
|
resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz"
|
||||||
|
integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
|
||||||
|
|
||||||
"@esbuild/win32-x64@0.18.20":
|
"@esbuild/win32-x64@0.18.20":
|
||||||
version "0.18.20"
|
version "0.18.20"
|
||||||
@ -758,31 +858,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.27.0"
|
"@babel/runtime" "^7.27.0"
|
||||||
|
|
||||||
"@mui/types@^7.4.1":
|
|
||||||
version "7.4.1"
|
|
||||||
resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.1.tgz"
|
|
||||||
integrity sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.27.0"
|
|
||||||
|
|
||||||
"@mui/types@~7.2.24":
|
"@mui/types@~7.2.24":
|
||||||
version "7.2.24"
|
version "7.2.24"
|
||||||
resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz"
|
resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz"
|
||||||
integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==
|
integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==
|
||||||
|
|
||||||
"@mui/utils@^5.16.6 || ^6.0.0 || ^7.0.0":
|
"@mui/utils@^5.16.6 || ^6.0.0 || ^7.0.0", "@mui/utils@^6.0.0-alpha.1", "@mui/utils@^6.0.0-alpha.3", "@mui/utils@^6.4.9":
|
||||||
version "7.0.2"
|
|
||||||
resolved "https://registry.npmjs.org/@mui/utils/-/utils-7.0.2.tgz"
|
|
||||||
integrity sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==
|
|
||||||
dependencies:
|
|
||||||
"@babel/runtime" "^7.27.0"
|
|
||||||
"@mui/types" "^7.4.1"
|
|
||||||
"@types/prop-types" "^15.7.14"
|
|
||||||
clsx "^2.1.1"
|
|
||||||
prop-types "^15.8.1"
|
|
||||||
react-is "^19.1.0"
|
|
||||||
|
|
||||||
"@mui/utils@^6.0.0-alpha.1", "@mui/utils@^6.0.0-alpha.3", "@mui/utils@^6.4.9":
|
|
||||||
version "6.4.9"
|
version "6.4.9"
|
||||||
resolved "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz"
|
resolved "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz"
|
||||||
integrity sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==
|
integrity sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==
|
||||||
@ -1470,14 +1551,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
|
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
|
||||||
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*", "@types/node@^18.16.2":
|
||||||
version "22.15.2"
|
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-22.15.2.tgz"
|
|
||||||
integrity sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==
|
|
||||||
dependencies:
|
|
||||||
undici-types "~6.21.0"
|
|
||||||
|
|
||||||
"@types/node@^18.16.2":
|
|
||||||
version "18.19.87"
|
version "18.19.87"
|
||||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.19.87.tgz"
|
resolved "https://registry.npmjs.org/@types/node/-/node-18.19.87.tgz"
|
||||||
integrity sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==
|
integrity sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==
|
||||||
@ -1541,14 +1615,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz"
|
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz"
|
||||||
integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==
|
integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==
|
||||||
|
|
||||||
"@types/react@*":
|
"@types/react@*", "@types/react@^18.0.0", "@types/react@16 || 17 || 18 || 19":
|
||||||
version "19.1.2"
|
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz"
|
|
||||||
integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==
|
|
||||||
dependencies:
|
|
||||||
csstype "^3.0.2"
|
|
||||||
|
|
||||||
"@types/react@^18.0.0":
|
|
||||||
version "18.3.20"
|
version "18.3.20"
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz"
|
resolved "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz"
|
||||||
integrity sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==
|
integrity sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==
|
||||||
@ -1556,13 +1623,6 @@
|
|||||||
"@types/prop-types" "*"
|
"@types/prop-types" "*"
|
||||||
csstype "^3.0.2"
|
csstype "^3.0.2"
|
||||||
|
|
||||||
"@types/react@16 || 17 || 18 || 19":
|
|
||||||
version "19.1.2"
|
|
||||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz"
|
|
||||||
integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==
|
|
||||||
dependencies:
|
|
||||||
csstype "^3.0.2"
|
|
||||||
|
|
||||||
"@types/semver@^7.3.12":
|
"@types/semver@^7.3.12":
|
||||||
version "7.7.0"
|
version "7.7.0"
|
||||||
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz"
|
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz"
|
||||||
@ -1597,12 +1657,7 @@
|
|||||||
resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz"
|
resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz"
|
||||||
integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==
|
integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==
|
||||||
|
|
||||||
"@types/unist@^2", "@types/unist@^2.0.0", "@types/unist@^2.0.3":
|
"@types/unist@^2", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
|
||||||
version "2.0.11"
|
|
||||||
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz"
|
|
||||||
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
|
|
||||||
|
|
||||||
"@types/unist@^2.0.2":
|
|
||||||
version "2.0.11"
|
version "2.0.11"
|
||||||
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz"
|
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz"
|
||||||
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
|
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
|
||||||
@ -2959,7 +3014,12 @@ estraverse@^4.1.1:
|
|||||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
||||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||||
|
|
||||||
estraverse@^5.1.0, estraverse@^5.2.0:
|
estraverse@^5.1.0:
|
||||||
|
version "5.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||||
|
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||||
|
|
||||||
|
estraverse@^5.2.0:
|
||||||
version "5.3.0"
|
version "5.3.0"
|
||||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||||
@ -3282,6 +3342,11 @@ fs.realpath@^1.0.0:
|
|||||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||||
|
|
||||||
|
fsevents@~2.3.2:
|
||||||
|
version "2.3.3"
|
||||||
|
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
|
||||||
|
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||||
|
|
||||||
function-bind@^1.1.2:
|
function-bind@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||||
@ -4023,7 +4088,12 @@ kind-of@^5.0.2:
|
|||||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz"
|
resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz"
|
||||||
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
||||||
|
|
||||||
kind-of@^6.0.0, kind-of@^6.0.2:
|
kind-of@^6.0.0:
|
||||||
|
version "6.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
|
||||||
|
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||||
|
|
||||||
|
kind-of@^6.0.2:
|
||||||
version "6.0.3"
|
version "6.0.3"
|
||||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
|
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
|
||||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||||
@ -4359,7 +4429,19 @@ mdast-util-to-hast@^13.0.0:
|
|||||||
unist-util-visit "^5.0.0"
|
unist-util-visit "^5.0.0"
|
||||||
vfile "^6.0.0"
|
vfile "^6.0.0"
|
||||||
|
|
||||||
mdast-util-to-markdown@^0.6.0, mdast-util-to-markdown@^0.6.1, mdast-util-to-markdown@~0.6.0:
|
mdast-util-to-markdown@^0.6.0:
|
||||||
|
version "0.6.5"
|
||||||
|
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
||||||
|
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/unist" "^2.0.0"
|
||||||
|
longest-streak "^2.0.0"
|
||||||
|
mdast-util-to-string "^2.0.0"
|
||||||
|
parse-entities "^2.0.0"
|
||||||
|
repeat-string "^1.0.0"
|
||||||
|
zwitch "^1.0.0"
|
||||||
|
|
||||||
|
mdast-util-to-markdown@^0.6.1:
|
||||||
version "0.6.5"
|
version "0.6.5"
|
||||||
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
||||||
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
||||||
@ -4386,6 +4468,18 @@ mdast-util-to-markdown@^2.0.0:
|
|||||||
unist-util-visit "^5.0.0"
|
unist-util-visit "^5.0.0"
|
||||||
zwitch "^2.0.0"
|
zwitch "^2.0.0"
|
||||||
|
|
||||||
|
mdast-util-to-markdown@~0.6.0:
|
||||||
|
version "0.6.5"
|
||||||
|
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
||||||
|
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/unist" "^2.0.0"
|
||||||
|
longest-streak "^2.0.0"
|
||||||
|
mdast-util-to-string "^2.0.0"
|
||||||
|
parse-entities "^2.0.0"
|
||||||
|
repeat-string "^1.0.0"
|
||||||
|
zwitch "^1.0.0"
|
||||||
|
|
||||||
mdast-util-to-string@^2.0.0:
|
mdast-util-to-string@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz"
|
resolved "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz"
|
||||||
@ -4659,7 +4753,7 @@ micromark-util-types@^2.0.0:
|
|||||||
resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz"
|
resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz"
|
||||||
integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==
|
integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==
|
||||||
|
|
||||||
micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3:
|
micromark@^2.11.3:
|
||||||
version "2.11.4"
|
version "2.11.4"
|
||||||
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
||||||
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
||||||
@ -4690,6 +4784,22 @@ micromark@^4.0.0:
|
|||||||
micromark-util-symbol "^2.0.0"
|
micromark-util-symbol "^2.0.0"
|
||||||
micromark-util-types "^2.0.0"
|
micromark-util-types "^2.0.0"
|
||||||
|
|
||||||
|
micromark@~2.11.0:
|
||||||
|
version "2.11.4"
|
||||||
|
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
||||||
|
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.0.0"
|
||||||
|
parse-entities "^2.0.0"
|
||||||
|
|
||||||
|
micromark@~2.11.3:
|
||||||
|
version "2.11.4"
|
||||||
|
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
||||||
|
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.0.0"
|
||||||
|
parse-entities "^2.0.0"
|
||||||
|
|
||||||
micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8:
|
micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8:
|
||||||
version "4.0.8"
|
version "4.0.8"
|
||||||
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
||||||
@ -4978,7 +5088,14 @@ os-tmpdir@~1.0.2:
|
|||||||
resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
|
||||||
integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
|
integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
|
||||||
|
|
||||||
p-limit@^2.0.0, p-limit@^2.2.0:
|
p-limit@^2.0.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
|
||||||
|
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
|
||||||
|
dependencies:
|
||||||
|
p-try "^2.0.0"
|
||||||
|
|
||||||
|
p-limit@^2.2.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
|
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
|
||||||
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
|
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
|
||||||
@ -5456,7 +5573,7 @@ react-is@^17.0.2:
|
|||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
||||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||||
|
|
||||||
react-is@^19.0.0, react-is@^19.1.0:
|
react-is@^19.0.0:
|
||||||
version "19.1.0"
|
version "19.1.0"
|
||||||
resolved "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz"
|
resolved "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz"
|
||||||
integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==
|
integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==
|
||||||
@ -5636,7 +5753,14 @@ redeyed@~2.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esprima "~4.0.0"
|
esprima "~4.0.0"
|
||||||
|
|
||||||
redux@^4.0.0, redux@^4.0.4:
|
redux@^4.0.0:
|
||||||
|
version "4.2.1"
|
||||||
|
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
|
||||||
|
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.9.2"
|
||||||
|
|
||||||
|
redux@^4.0.4:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
|
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
|
||||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||||
@ -5857,18 +5981,18 @@ semver@^6.3.1:
|
|||||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
||||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||||
|
|
||||||
semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3:
|
semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@7.5.2:
|
||||||
version "7.7.1"
|
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz"
|
|
||||||
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
|
||||||
|
|
||||||
semver@7.5.2:
|
|
||||||
version "7.5.2"
|
version "7.5.2"
|
||||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz"
|
resolved "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz"
|
||||||
integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==
|
integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache "^6.0.0"
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
|
semver@^7.5.3:
|
||||||
|
version "7.7.1"
|
||||||
|
resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz"
|
||||||
|
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
||||||
|
|
||||||
send@0.19.0:
|
send@0.19.0:
|
||||||
version "0.19.0"
|
version "0.19.0"
|
||||||
resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz"
|
resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz"
|
||||||
@ -6015,7 +6139,17 @@ source-map@^0.5.7:
|
|||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
||||||
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
|
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
|
||||||
|
|
||||||
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
|
source-map@^0.6.0:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||||
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
source-map@^0.6.1:
|
||||||
|
version "0.6.1"
|
||||||
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||||
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
|
|
||||||
|
source-map@~0.6.1:
|
||||||
version "0.6.1"
|
version "0.6.1"
|
||||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||||
@ -6444,11 +6578,6 @@ undici-types@~5.26.4:
|
|||||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
|
resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
|
||||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||||
|
|
||||||
undici-types@~6.21.0:
|
|
||||||
version "6.21.0"
|
|
||||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz"
|
|
||||||
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
|
|
||||||
|
|
||||||
unicode-emoji-modifier-base@^1.0.0:
|
unicode-emoji-modifier-base@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz"
|
resolved "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user