add preview
functionality for /sight
route
This commit is contained in:
parent
2fe19516f6
commit
24a8bcad0a
@ -1,7 +1,10 @@
|
|||||||
import {Autocomplete, Box, TextField} from '@mui/material'
|
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 {Link} from 'react-router'
|
||||||
|
import React, {useState, useEffect} from 'react'
|
||||||
|
import {TOKEN_KEY} from '../../authProvider'
|
||||||
|
|
||||||
export const SightCreate = () => {
|
export const SightCreate = () => {
|
||||||
const {
|
const {
|
||||||
@ -9,6 +12,7 @@ export const SightCreate = () => {
|
|||||||
refineCore: {formLoading},
|
refineCore: {formLoading},
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
|
watch,
|
||||||
formState: {errors},
|
formState: {errors},
|
||||||
} = useForm({
|
} = useForm({
|
||||||
refineCoreProps: {
|
refineCoreProps: {
|
||||||
@ -16,6 +20,17 @@ export const SightCreate = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Состояния для предпросмотра
|
||||||
|
const [namePreview, setNamePreview] = useState('')
|
||||||
|
const [coordinatesPreview, setCoordinatesPreview] = useState({latitude: '', longitude: ''})
|
||||||
|
const [cityPreview, setCityPreview] = useState('')
|
||||||
|
const [thumbnailPreview, setThumbnailPreview] = useState<string | null>(null)
|
||||||
|
const [watermarkLUPreview, setWatermarkLUPreview] = useState<string | null>(null)
|
||||||
|
const [watermarkRDPreview, setWatermarkRDPreview] = useState<string | null>(null)
|
||||||
|
const [leftArticlePreview, setLeftArticlePreview] = useState('')
|
||||||
|
const [previewArticlePreview, setPreviewArticlePreview] = useState('')
|
||||||
|
|
||||||
|
// Автокомплиты
|
||||||
const {autocompleteProps: cityAutocompleteProps} = useAutocomplete({
|
const {autocompleteProps: cityAutocompleteProps} = useAutocomplete({
|
||||||
resource: 'city',
|
resource: 'city',
|
||||||
onSearch: (value) => [
|
onSearch: (value) => [
|
||||||
@ -49,201 +64,419 @@ export const SightCreate = () => {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Следим за изменениями во всех полях
|
||||||
|
const nameContent = watch('name')
|
||||||
|
const latitudeContent = watch('latitude')
|
||||||
|
const longitudeContent = watch('longitude')
|
||||||
|
const cityContent = watch('city_id')
|
||||||
|
const thumbnailContent = watch('thumbnail')
|
||||||
|
const watermarkLUContent = watch('watermark_lu')
|
||||||
|
const watermarkRDContent = watch('watermark_rd')
|
||||||
|
const leftArticleContent = watch('left_article')
|
||||||
|
const previewArticleContent = watch('preview_article')
|
||||||
|
|
||||||
|
// Обновляем состояния при изменении полей
|
||||||
|
useEffect(() => {
|
||||||
|
setNamePreview(nameContent || '')
|
||||||
|
}, [nameContent])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCoordinatesPreview({
|
||||||
|
latitude: latitudeContent || '',
|
||||||
|
longitude: longitudeContent || '',
|
||||||
|
})
|
||||||
|
}, [latitudeContent, longitudeContent])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedCity = cityAutocompleteProps.options.find((option) => option.id === cityContent)
|
||||||
|
setCityPreview(selectedCity?.name || '')
|
||||||
|
}, [cityContent, cityAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedThumbnail = mediaAutocompleteProps.options.find((option) => option.id === thumbnailContent)
|
||||||
|
setThumbnailPreview(selectedThumbnail ? `https://wn.krbl.ru/media/${selectedThumbnail.id}/download?token=${localStorage.getItem(TOKEN_KEY)}` : null)
|
||||||
|
}, [thumbnailContent, mediaAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedWatermarkLU = mediaAutocompleteProps.options.find((option) => option.id === watermarkLUContent)
|
||||||
|
setWatermarkLUPreview(selectedWatermarkLU ? `https://wn.krbl.ru/media/${selectedWatermarkLU.id}/download?token=${localStorage.getItem(TOKEN_KEY)}` : null)
|
||||||
|
}, [watermarkLUContent, mediaAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedWatermarkRD = mediaAutocompleteProps.options.find((option) => option.id === watermarkRDContent)
|
||||||
|
setWatermarkRDPreview(selectedWatermarkRD ? `https://wn.krbl.ru/media/${selectedWatermarkRD.id}/download?token=${localStorage.getItem(TOKEN_KEY)}` : null)
|
||||||
|
}, [watermarkRDContent, mediaAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedLeftArticle = articleAutocompleteProps.options.find((option) => option.id === leftArticleContent)
|
||||||
|
setLeftArticlePreview(selectedLeftArticle?.heading || '')
|
||||||
|
}, [leftArticleContent, articleAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedPreviewArticle = articleAutocompleteProps.options.find((option) => option.id === previewArticleContent)
|
||||||
|
setPreviewArticlePreview(selectedPreviewArticle?.heading || '')
|
||||||
|
}, [previewArticleContent, articleAutocompleteProps.options])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
||||||
<Box component="form" sx={{display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
<Box sx={{display: 'flex', gap: 2}}>
|
||||||
<TextField
|
{/* Форма создания */}
|
||||||
{...register('name', {
|
<Box component="form" sx={{flex: 1, display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
||||||
required: 'Это поле является обязательным',
|
<TextField
|
||||||
})}
|
{...register('name', {
|
||||||
error={!!(errors as any)?.name}
|
required: 'Это поле является обязательным',
|
||||||
helperText={(errors as any)?.name?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.name}
|
||||||
fullWidth
|
helperText={(errors as any)?.name?.message}
|
||||||
InputLabelProps={{shrink: true}}
|
margin="normal"
|
||||||
type="text"
|
fullWidth
|
||||||
label={'Название *'}
|
InputLabelProps={{shrink: true}}
|
||||||
name="name"
|
type="text"
|
||||||
/>
|
label={'Название *'}
|
||||||
<TextField
|
name="name"
|
||||||
{...register('latitude', {
|
/>
|
||||||
required: 'Это поле является обязательным',
|
<TextField
|
||||||
valueAsNumber: true,
|
{...register('latitude', {
|
||||||
})}
|
required: 'Это поле является обязательным',
|
||||||
error={!!(errors as any)?.latitude}
|
valueAsNumber: true,
|
||||||
helperText={(errors as any)?.latitude?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.latitude}
|
||||||
fullWidth
|
helperText={(errors as any)?.latitude?.message}
|
||||||
InputLabelProps={{shrink: true}}
|
margin="normal"
|
||||||
type="number"
|
fullWidth
|
||||||
label={'Широта *'}
|
InputLabelProps={{shrink: true}}
|
||||||
name="latitude"
|
type="number"
|
||||||
/>
|
label={'Широта *'}
|
||||||
<TextField
|
name="latitude"
|
||||||
{...register('longitude', {
|
/>
|
||||||
required: 'Это поле является обязательным',
|
<TextField
|
||||||
valueAsNumber: true,
|
{...register('longitude', {
|
||||||
})}
|
required: 'Это поле является обязательным',
|
||||||
error={!!(errors as any)?.longitude}
|
valueAsNumber: true,
|
||||||
helperText={(errors as any)?.longitude?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.longitude}
|
||||||
fullWidth
|
helperText={(errors as any)?.longitude?.message}
|
||||||
InputLabelProps={{shrink: true}}
|
margin="normal"
|
||||||
type="number"
|
fullWidth
|
||||||
label={'Долгота *'}
|
InputLabelProps={{shrink: true}}
|
||||||
name="longitude"
|
type="number"
|
||||||
/>
|
label={'Долгота *'}
|
||||||
|
name="longitude"
|
||||||
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="city_id"
|
name="city_id"
|
||||||
rules={{required: 'Это поле является обязательным'}}
|
rules={{required: 'Это поле является обязательным'}}
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...cityAutocompleteProps}
|
{...cityAutocompleteProps}
|
||||||
value={cityAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={cityAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.name : ''
|
return item ? item.name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите город" margin="normal" variant="outlined" error={!!errors.city_id} helperText={(errors as any)?.city_id?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите город" margin="normal" variant="outlined" error={!!errors.city_id} helperText={(errors as any)?.city_id?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="thumbnail"
|
name="thumbnail"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps}
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.media_name : ''
|
return item ? item.media_name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите обложку" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите обложку" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="watermark_lu"
|
name="watermark_lu"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps}
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.media_name : ''
|
return item ? item.media_name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Левый верх)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Левый верх)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="watermark_rd"
|
name="watermark_rd"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps}
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.media_name : ''
|
return item ? item.media_name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Правый низ)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Правый низ)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="left_article"
|
name="left_article"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...articleAutocompleteProps}
|
{...articleAutocompleteProps}
|
||||||
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.heading : ''
|
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) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Левая статья" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Левая статья" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="preview_article"
|
name="preview_article"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...articleAutocompleteProps}
|
{...articleAutocompleteProps}
|
||||||
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.heading : ''
|
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) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Cтатья-предпросмотр" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Cтатья-предпросмотр" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Блок предпросмотра */}
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
flex: 1,
|
||||||
|
p: 2,
|
||||||
|
maxHeight: 'calc(100vh - 200px)',
|
||||||
|
overflowY: 'auto',
|
||||||
|
position: 'sticky',
|
||||||
|
top: 16,
|
||||||
|
borderRadius: 2,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'background.paper' : '#fff'),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" gutterBottom color="primary">
|
||||||
|
Предпросмотр
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Название */}
|
||||||
|
<Typography variant="h4" gutterBottom sx={{color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800')}}>
|
||||||
|
{namePreview}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Город */}
|
||||||
|
<Typography variant="body1" sx={{mb: 2}}>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Город:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box component="span" sx={{color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800')}}>
|
||||||
|
{cityPreview}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Координаты */}
|
||||||
|
<Typography variant="body1" sx={{mb: 2}}>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Координаты:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box component="span" sx={{color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800')}}>
|
||||||
|
{coordinatesPreview.latitude}, {coordinatesPreview.longitude}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Обложка */}
|
||||||
|
{thumbnailPreview && (
|
||||||
|
<Box sx={{mb: 2}}>
|
||||||
|
<Typography variant="body1" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Обложка:
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={thumbnailPreview}
|
||||||
|
alt="Обложка"
|
||||||
|
sx={{
|
||||||
|
maxWidth: '100%',
|
||||||
|
height: 'auto',
|
||||||
|
borderRadius: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
/>
|
|
||||||
|
{/* Водяные знаки */}
|
||||||
|
<Box sx={{mb: 2}}>
|
||||||
|
<Typography variant="body1" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Водяные знаки:
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{display: 'flex', gap: 2}}>
|
||||||
|
{watermarkLUPreview && (
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body2" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Левый верхний:
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={watermarkLUPreview}
|
||||||
|
alt="Водяной знак (ЛВ)"
|
||||||
|
sx={{
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
objectFit: 'cover',
|
||||||
|
borderRadius: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
{watermarkRDPreview && (
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body2" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Правый нижний:
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={watermarkRDPreview}
|
||||||
|
alt="Водяной знак (ПН)"
|
||||||
|
sx={{
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
objectFit: 'cover',
|
||||||
|
borderRadius: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Связанные статьи */}
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body1" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Связанные статьи:
|
||||||
|
</Typography>
|
||||||
|
{leftArticlePreview && (
|
||||||
|
<Typography variant="body1" gutterBottom>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Левая статья:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
component={Link}
|
||||||
|
to={`/article/show/${watch('left_article')}`}
|
||||||
|
sx={{
|
||||||
|
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{leftArticlePreview}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{previewArticlePreview && (
|
||||||
|
<Typography variant="body1" gutterBottom>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Статья-предпросмотр:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
component={Link}
|
||||||
|
to={`/article/show/${watch('preview_article')}`}
|
||||||
|
sx={{
|
||||||
|
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{previewArticlePreview}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
</Create>
|
</Create>
|
||||||
)
|
)
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import {Autocomplete, Box, TextField} from '@mui/material'
|
import {Autocomplete, Box, TextField, Paper, Typography} 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 {useParams} from 'react-router'
|
||||||
|
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 {Link} from 'react-router'
|
||||||
|
|
||||||
export const SightEdit = () => {
|
export const SightEdit = () => {
|
||||||
const {id: sightId} = useParams<{id: string}>()
|
const {id: sightId} = useParams<{id: string}>()
|
||||||
@ -14,6 +17,7 @@ export const SightEdit = () => {
|
|||||||
saveButtonProps,
|
saveButtonProps,
|
||||||
register,
|
register,
|
||||||
control,
|
control,
|
||||||
|
watch,
|
||||||
formState: {errors},
|
formState: {errors},
|
||||||
} = useForm({})
|
} = useForm({})
|
||||||
|
|
||||||
@ -50,201 +54,439 @@ export const SightEdit = () => {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Состояния для предпросмотра
|
||||||
|
const [namePreview, setNamePreview] = useState('')
|
||||||
|
const [coordinatesPreview, setCoordinatesPreview] = useState({
|
||||||
|
latitude: '',
|
||||||
|
longitude: '',
|
||||||
|
})
|
||||||
|
const [cityPreview, setCityPreview] = useState('')
|
||||||
|
const [thumbnailPreview, setThumbnailPreview] = useState<string | null>(null)
|
||||||
|
const [watermarkLUPreview, setWatermarkLUPreview] = useState<string | null>(null)
|
||||||
|
const [watermarkRDPreview, setWatermarkRDPreview] = useState<string | null>(null)
|
||||||
|
const [leftArticlePreview, setLeftArticlePreview] = useState('')
|
||||||
|
const [previewArticlePreview, setPreviewArticlePreview] = useState('')
|
||||||
|
|
||||||
|
// Следим за изменениями во всех полях
|
||||||
|
const nameContent = watch('name')
|
||||||
|
const latitudeContent = watch('latitude')
|
||||||
|
const longitudeContent = watch('longitude')
|
||||||
|
const cityContent = watch('city_id')
|
||||||
|
const thumbnailContent = watch('thumbnail')
|
||||||
|
const watermarkLUContent = watch('watermark_lu')
|
||||||
|
const watermarkRDContent = watch('watermark_rd')
|
||||||
|
const leftArticleContent = watch('left_article')
|
||||||
|
const previewArticleContent = watch('preview_article')
|
||||||
|
|
||||||
|
// Обновляем состояния при изменении полей
|
||||||
|
useEffect(() => {
|
||||||
|
setNamePreview(nameContent || '')
|
||||||
|
}, [nameContent])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCoordinatesPreview({
|
||||||
|
latitude: latitudeContent || '',
|
||||||
|
longitude: longitudeContent || '',
|
||||||
|
})
|
||||||
|
}, [latitudeContent, longitudeContent])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedCity = cityAutocompleteProps.options.find((option) => option.id === cityContent)
|
||||||
|
setCityPreview(selectedCity?.name || '')
|
||||||
|
}, [cityContent, cityAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedThumbnail = mediaAutocompleteProps.options.find((option) => option.id === thumbnailContent)
|
||||||
|
setThumbnailPreview(selectedThumbnail ? `https://wn.krbl.ru/media/${selectedThumbnail.id}/download?token=${localStorage.getItem(TOKEN_KEY)}` : null)
|
||||||
|
}, [thumbnailContent, mediaAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedWatermarkLU = mediaAutocompleteProps.options.find((option) => option.id === watermarkLUContent)
|
||||||
|
setWatermarkLUPreview(selectedWatermarkLU ? `https://wn.krbl.ru/media/${selectedWatermarkLU.id}/download?token=${localStorage.getItem(TOKEN_KEY)}` : null)
|
||||||
|
}, [watermarkLUContent, mediaAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedWatermarkRD = mediaAutocompleteProps.options.find((option) => option.id === watermarkRDContent)
|
||||||
|
setWatermarkRDPreview(selectedWatermarkRD ? `https://wn.krbl.ru/media/${selectedWatermarkRD.id}/download?token=${localStorage.getItem(TOKEN_KEY)}` : null)
|
||||||
|
}, [watermarkRDContent, mediaAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedLeftArticle = articleAutocompleteProps.options.find((option) => option.id === leftArticleContent)
|
||||||
|
setLeftArticlePreview(selectedLeftArticle?.heading || '')
|
||||||
|
}, [leftArticleContent, articleAutocompleteProps.options])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectedPreviewArticle = articleAutocompleteProps.options.find((option) => option.id === previewArticleContent)
|
||||||
|
setPreviewArticlePreview(selectedPreviewArticle?.heading || '')
|
||||||
|
}, [previewArticleContent, articleAutocompleteProps.options])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Edit saveButtonProps={saveButtonProps}>
|
<Edit saveButtonProps={saveButtonProps}>
|
||||||
<Box component="form" sx={{display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
<Box sx={{display: 'flex', gap: 2}}>
|
||||||
<TextField
|
{/* Форма редактирования */}
|
||||||
{...register('name', {
|
<Box component="form" sx={{flex: 1, display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
||||||
required: 'Это поле является обязательным',
|
<TextField
|
||||||
})}
|
{...register('name', {
|
||||||
error={!!(errors as any)?.name}
|
required: 'Это поле является обязательным',
|
||||||
helperText={(errors as any)?.name?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.name}
|
||||||
fullWidth
|
helperText={(errors as any)?.name?.message}
|
||||||
InputLabelProps={{shrink: true}}
|
margin="normal"
|
||||||
type="text"
|
fullWidth
|
||||||
label={'Название *'}
|
InputLabelProps={{shrink: true}}
|
||||||
name="name"
|
type="text"
|
||||||
/>
|
label={'Название *'}
|
||||||
<TextField
|
name="name"
|
||||||
{...register('latitude', {
|
/>
|
||||||
required: 'Это поле является обязательным',
|
<TextField
|
||||||
valueAsNumber: true,
|
{...register('latitude', {
|
||||||
})}
|
required: 'Это поле является обязательным',
|
||||||
error={!!(errors as any)?.latitude}
|
valueAsNumber: true,
|
||||||
helperText={(errors as any)?.latitude?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.latitude}
|
||||||
fullWidth
|
helperText={(errors as any)?.latitude?.message}
|
||||||
InputLabelProps={{shrink: true}}
|
margin="normal"
|
||||||
type="number"
|
fullWidth
|
||||||
label={'Широта *'}
|
InputLabelProps={{shrink: true}}
|
||||||
name="latitude"
|
type="number"
|
||||||
/>
|
label={'Широта *'}
|
||||||
<TextField
|
name="latitude"
|
||||||
{...register('longitude', {
|
/>
|
||||||
required: 'Это поле является обязательным',
|
<TextField
|
||||||
valueAsNumber: true,
|
{...register('longitude', {
|
||||||
})}
|
required: 'Это поле является обязательным',
|
||||||
error={!!(errors as any)?.longitude}
|
valueAsNumber: true,
|
||||||
helperText={(errors as any)?.longitude?.message}
|
})}
|
||||||
margin="normal"
|
error={!!(errors as any)?.longitude}
|
||||||
fullWidth
|
helperText={(errors as any)?.longitude?.message}
|
||||||
InputLabelProps={{shrink: true}}
|
margin="normal"
|
||||||
type="number"
|
fullWidth
|
||||||
label={'Долгота *'}
|
InputLabelProps={{shrink: true}}
|
||||||
name="longitude"
|
type="number"
|
||||||
/>
|
label={'Долгота *'}
|
||||||
|
name="longitude"
|
||||||
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="city_id"
|
name="city_id"
|
||||||
rules={{required: 'Это поле является обязательным'}}
|
rules={{required: 'Это поле является обязательным'}}
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...cityAutocompleteProps}
|
{...cityAutocompleteProps}
|
||||||
value={cityAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={cityAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.name : ''
|
return item ? item.name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите город" margin="normal" variant="outlined" error={!!errors.city_id} helperText={(errors as any)?.city_id?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите город" margin="normal" variant="outlined" error={!!errors.city_id} helperText={(errors as any)?.city_id?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="thumbnail"
|
name="thumbnail"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps}
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.media_name : ''
|
return item ? item.media_name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите обложку" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите обложку" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="watermark_lu"
|
name="watermark_lu"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps}
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.media_name : ''
|
return item ? item.media_name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Левый верх)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Левый верх)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="watermark_rd"
|
name="watermark_rd"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...mediaAutocompleteProps}
|
{...mediaAutocompleteProps}
|
||||||
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={mediaAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.media_name : ''
|
return item ? item.media_name : ''
|
||||||
}}
|
}}
|
||||||
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) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.media_name.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Правый низ)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Выберите водный знак (Правый низ)" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="left_article"
|
name="left_article"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...articleAutocompleteProps}
|
{...articleAutocompleteProps}
|
||||||
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.heading : ''
|
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) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Левая статья" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Левая статья" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="preview_article"
|
name="preview_article"
|
||||||
defaultValue={null}
|
defaultValue={null}
|
||||||
render={({field}) => (
|
render={({field}) => (
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
{...articleAutocompleteProps}
|
{...articleAutocompleteProps}
|
||||||
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
value={articleAutocompleteProps.options.find((option) => option.id === field.value) || null}
|
||||||
onChange={(_, value) => {
|
onChange={(_, value) => {
|
||||||
field.onChange(value?.id || '')
|
field.onChange(value?.id || '')
|
||||||
}}
|
}}
|
||||||
getOptionLabel={(item) => {
|
getOptionLabel={(item) => {
|
||||||
return item ? item.heading : ''
|
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) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
return options.filter((option) => option.heading.toLowerCase().includes(inputValue.toLowerCase()))
|
||||||
}}
|
}}
|
||||||
renderInput={(params) => <TextField {...params} label="Cтатья-предпросмотр" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
renderInput={(params) => <TextField {...params} label="Cтатья-предпросмотр" margin="normal" variant="outlined" error={!!errors.arms} helperText={(errors as any)?.arms?.message} required />}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Блок предпросмотра */}
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
flex: 1,
|
||||||
|
p: 2,
|
||||||
|
maxHeight: 'calc(100vh - 200px)',
|
||||||
|
overflowY: 'auto',
|
||||||
|
position: 'sticky',
|
||||||
|
top: 16,
|
||||||
|
borderRadius: 2,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'background.paper' : '#fff'),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6" gutterBottom color="primary">
|
||||||
|
Предпросмотр
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Название достопримечательности */}
|
||||||
|
<Typography
|
||||||
|
variant="h4"
|
||||||
|
gutterBottom
|
||||||
|
sx={{
|
||||||
|
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
|
||||||
|
mb: 3,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{namePreview}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Город */}
|
||||||
|
<Typography variant="body1" sx={{mb: 2}}>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Город:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box component="span" sx={{color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800')}}>
|
||||||
|
{cityPreview}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Координаты */}
|
||||||
|
<Typography variant="body1" sx={{mb: 2}}>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Координаты:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box component="span" sx={{color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800')}}>
|
||||||
|
{coordinatesPreview.latitude}, {coordinatesPreview.longitude}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{/* Обложка */}
|
||||||
|
{thumbnailPreview && (
|
||||||
|
<Box sx={{mb: 2}}>
|
||||||
|
<Typography variant="body1" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Обложка:
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={thumbnailPreview}
|
||||||
|
alt="Обложка"
|
||||||
|
sx={{
|
||||||
|
maxWidth: '100%',
|
||||||
|
height: '40vh',
|
||||||
|
borderRadius: 2,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
/>
|
|
||||||
|
{/* Водяные знаки */}
|
||||||
|
<Box sx={{mb: 2}}>
|
||||||
|
<Typography variant="body1" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Водяные знаки:
|
||||||
|
</Typography>
|
||||||
|
<Box sx={{display: 'flex', gap: 2}}>
|
||||||
|
{watermarkLUPreview && (
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body2" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Левый верхний:
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={watermarkLUPreview}
|
||||||
|
alt="Водяной знак (ЛВ)"
|
||||||
|
sx={{
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
objectFit: 'cover',
|
||||||
|
borderRadius: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
{watermarkRDPreview && (
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body2" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Правый нижний:
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={watermarkRDPreview}
|
||||||
|
alt="Водяной знак (ПН)"
|
||||||
|
sx={{
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
objectFit: 'cover',
|
||||||
|
borderRadius: 1,
|
||||||
|
border: '1px solid',
|
||||||
|
borderColor: 'primary.main',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Связанные статьи */}
|
||||||
|
<Box>
|
||||||
|
{/* <Typography variant="body1" gutterBottom sx={{color: 'text.secondary'}}>
|
||||||
|
Связанные статьи:
|
||||||
|
</Typography> */}
|
||||||
|
{leftArticlePreview && (
|
||||||
|
<Typography variant="body1" gutterBottom>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Левая статья:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
component={Link}
|
||||||
|
to={`/article/show/${watch('left_article')}`}
|
||||||
|
sx={{
|
||||||
|
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{leftArticlePreview}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{previewArticlePreview && (
|
||||||
|
<Typography variant="body1" gutterBottom>
|
||||||
|
<Box component="span" sx={{color: 'text.secondary'}}>
|
||||||
|
Статья-предпросмотр:{' '}
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
component={Link}
|
||||||
|
to={`/article/show/${watch('preview_article')}`}
|
||||||
|
sx={{
|
||||||
|
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
|
||||||
|
textDecoration: 'none',
|
||||||
|
'&:hover': {
|
||||||
|
textDecoration: 'underline',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{previewArticlePreview}
|
||||||
|
</Box>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{sightId && (
|
{sightId && (
|
||||||
|
Loading…
Reference in New Issue
Block a user