182 lines
5.9 KiB
TypeScript
182 lines
5.9 KiB
TypeScript
import {Stack, Typography, Grid2 as Grid, Button, MenuItem, Select, FormControl, InputLabel, TextField, Card, CardMedia, CardContent, CardActions} from '@mui/material'
|
||
import {useShow} from '@refinedev/core'
|
||
import {Show, TextFieldComponent} from '@refinedev/mui'
|
||
|
||
import {useEffect, useState} from 'react'
|
||
import axios from 'axios'
|
||
|
||
import {BACKEND_URL} from '../../lib/constants'
|
||
|
||
type MediaItem = {
|
||
id: string
|
||
filename: string
|
||
media_type: string
|
||
}
|
||
|
||
export const ArticleShow = () => {
|
||
const {query} = useShow({})
|
||
const {data, isLoading} = query
|
||
const record = data?.data
|
||
|
||
const [media, setMedia] = useState<MediaItem[]>([])
|
||
const [linkedMedia, setLinkedMedia] = useState<MediaItem[]>([])
|
||
const [selectedMediaId, setSelectedMediaId] = useState<string>('')
|
||
const [mediaOrder, setMediaOrder] = useState<number>(1)
|
||
const [mediaLoading, setMediaLoading] = useState<boolean>(true)
|
||
|
||
useEffect(() => {
|
||
if (record?.id) {
|
||
axios
|
||
.get(`${BACKEND_URL}/article/${record.id}/media`)
|
||
.then((response) => {
|
||
setLinkedMedia(response?.data || [])
|
||
})
|
||
.catch(() => {
|
||
setLinkedMedia([])
|
||
})
|
||
}
|
||
}, [record?.id])
|
||
|
||
useEffect(() => {
|
||
axios
|
||
.get(`${BACKEND_URL}/media`)
|
||
.then((response) => {
|
||
setMedia(response?.data || [])
|
||
setMediaLoading(false)
|
||
})
|
||
.catch(() => {
|
||
setMedia([])
|
||
setMediaLoading(false)
|
||
})
|
||
}, [])
|
||
|
||
const availableMedia = media.filter((mediaItem) => !linkedMedia.some((linkedItem) => linkedItem.id === mediaItem.id))
|
||
|
||
const linkMedia = () => {
|
||
if (selectedMediaId) {
|
||
const requestData = {
|
||
media_id: selectedMediaId,
|
||
media_order: mediaOrder,
|
||
}
|
||
|
||
axios
|
||
.post(`${BACKEND_URL}/article/${record?.id}/media`, requestData, {
|
||
headers: {
|
||
accept: 'application/json',
|
||
'Content-Type': 'application/json',
|
||
},
|
||
})
|
||
.then(() => {
|
||
axios
|
||
.get(`${BACKEND_URL}/article/${record?.id}/media`)
|
||
.then((response) => {
|
||
setLinkedMedia(response?.data || [])
|
||
setMediaOrder(mediaOrder + 1)
|
||
setSelectedMediaId('')
|
||
})
|
||
.catch(() => {
|
||
setLinkedMedia([])
|
||
})
|
||
})
|
||
.catch((error) => {
|
||
console.error('Error linking media:', error)
|
||
})
|
||
}
|
||
}
|
||
|
||
const deleteMedia = (mediaId: string) => {
|
||
axios
|
||
.delete(`${BACKEND_URL}/article/${record?.id}/media`, {
|
||
data: {media_id: mediaId},
|
||
})
|
||
.then(() => {
|
||
setLinkedMedia((prevMedia) => prevMedia.filter((item) => item.id !== mediaId))
|
||
})
|
||
.catch((error) => {
|
||
console.error('Error deleting media:', error)
|
||
})
|
||
}
|
||
|
||
const fields = [
|
||
// {label: 'ID', data: 'id'},
|
||
{label: 'Заголовок', data: 'heading'},
|
||
{label: 'Контент', data: 'body'},
|
||
]
|
||
|
||
const mediaFields = [
|
||
// {label: 'ID', data: 'id' as keyof MediaItem},
|
||
{label: 'Имя', data: 'filename' as keyof MediaItem},
|
||
{label: 'Тип', data: 'media_type' as keyof MediaItem},
|
||
]
|
||
|
||
return (
|
||
<Show isLoading={isLoading}>
|
||
<Stack gap={4}>
|
||
{fields.map(({label, data}) => (
|
||
<Stack key={data} gap={1}>
|
||
<Typography variant="h6" fontWeight="bold">
|
||
{label}
|
||
</Typography>
|
||
<TextFieldComponent value={record?.[data] || ''} />
|
||
</Stack>
|
||
))}
|
||
|
||
<Stack gap={2}>
|
||
<Typography variant="h6" fontWeight="bold">
|
||
Медиа
|
||
</Typography>
|
||
<Grid container spacing={2}>
|
||
{mediaLoading ? (
|
||
<Typography>Загрузка медиа...</Typography>
|
||
) : linkedMedia.length > 0 ? (
|
||
linkedMedia.map((mediaItem) => (
|
||
<Grid key={mediaItem.id}>
|
||
<Card sx={{backgroundColor: '#1e1e1e', borderRadius: 2}}>
|
||
<CardMedia component="img" height="200" image={`${BACKEND_URL}/media/${mediaItem?.id}/download`} alt={mediaItem?.filename} sx={{objectFit: 'contain', backgroundColor: '#2e2e2e'}} />
|
||
<CardContent>
|
||
{mediaFields.map(({label, data}) => (
|
||
<Typography key={data} variant="body2" color="textSecondary">
|
||
<strong>{label}:</strong> {mediaItem?.[data]}
|
||
</Typography>
|
||
))}
|
||
</CardContent>
|
||
<CardActions>
|
||
<Button variant="outlined" color="error" onClick={() => deleteMedia(mediaItem?.id)} fullWidth>
|
||
Отвязать
|
||
</Button>
|
||
</CardActions>
|
||
</Card>
|
||
</Grid>
|
||
))
|
||
) : (
|
||
<Typography>Нет привязанных медиа</Typography>
|
||
)}
|
||
</Grid>
|
||
|
||
{/* sx={{width: '650px'}} */}
|
||
<Stack gap={2} mt={4}>
|
||
{' '}
|
||
<Typography variant="h6" fontWeight="bold">
|
||
Привязать медиа
|
||
</Typography>
|
||
<FormControl fullWidth>
|
||
<InputLabel>Медиа</InputLabel>
|
||
<Select value={selectedMediaId} onChange={(e) => setSelectedMediaId(e.target.value)} fullWidth>
|
||
{availableMedia.map((mediaItem) => (
|
||
<MenuItem key={mediaItem.id} value={mediaItem.id}>
|
||
{mediaItem.filename}
|
||
</MenuItem>
|
||
))}
|
||
</Select>
|
||
</FormControl>
|
||
<TextField type="number" label="Порядок отображения медиа" value={mediaOrder} onChange={(e) => setMediaOrder(Number(e.target.value))} fullWidth InputLabelProps={{shrink: true}} />
|
||
<Button variant="contained" onClick={linkMedia} disabled={!selectedMediaId}>
|
||
Привязать
|
||
</Button>
|
||
</Stack>
|
||
</Stack>
|
||
</Stack>
|
||
</Show>
|
||
)
|
||
}
|