diff --git a/src/pages/article/show.tsx b/src/pages/article/show.tsx index f1f5224..73f5dd3 100644 --- a/src/pages/article/show.tsx +++ b/src/pages/article/show.tsx @@ -1,42 +1,95 @@ -import {Stack, Typography, Box, Grid2 as Grid, Button} from '@mui/material' +import {Stack, Typography, Box, Grid2 as Grid, Button, MenuItem, Select, FormControl, InputLabel, TextField} from '@mui/material' import {useShow} from '@refinedev/core' -import {Show, TextFieldComponent as TextField} from '@refinedev/mui' +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<any[]>([]) - const [mediaLoading, setMediaLoading] = useState(true) + 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) => { - setMedia(response?.data || []) - setMediaLoading(false) + setLinkedMedia(response?.data || []) }) .catch(() => { - setMedia([]) - setMediaLoading(false) + 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) + }) + .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(() => { - setMedia((prevMedia) => prevMedia.filter((item) => item.id !== mediaId)) + setLinkedMedia((prevMedia) => prevMedia.filter((item) => item.id !== mediaId)) }) .catch((error) => { console.error('Error deleting media:', error) @@ -50,9 +103,9 @@ export const ArticleShow = () => { ] const mediaFields = [ - {label: 'ID', data: 'id'}, - {label: 'Filename', data: 'filename'}, - {label: 'Media Type', data: 'media_type'}, + {label: 'ID', data: 'id' as keyof MediaItem}, + {label: 'Filename', data: 'filename' as keyof MediaItem}, + {label: 'Media Type', data: 'media_type' as keyof MediaItem}, ] return ( @@ -63,7 +116,7 @@ export const ArticleShow = () => { <Typography variant="body1" fontWeight="bold"> {label} </Typography> - <TextField value={record?.[data]} /> + <TextFieldComponent value={record?.[data] || ''} /> </Stack> ))} @@ -75,28 +128,12 @@ export const ArticleShow = () => { <Grid container gap={2}> {mediaLoading ? ( <Typography>Loading media...</Typography> - ) : media.length > 0 ? ( - media.map((mediaItem, index) => ( + ) : linkedMedia.length > 0 ? ( + linkedMedia.map((mediaItem, index) => ( <Box key={index} sx={{border: '2px solid #dddddd25', padding: '20px', marginBottom: '8px'}}> {record && ( - <Box - sx={{ - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - marginBottom: '20px', - }} - > - <img - src={`${BACKEND_URL}/media/${mediaItem?.id}/download`} - alt={mediaItem?.filename} - style={{ - maxWidth: '100%', - height: '20vh', - objectFit: 'contain', - borderRadius: 8, - }} - /> + <Box sx={{display: 'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '20px'}}> + <img src={`${BACKEND_URL}/media/${mediaItem?.id}/download`} alt={mediaItem?.filename} style={{maxWidth: '100%', height: '20vh', objectFit: 'contain', borderRadius: 8}} /> </Box> )} @@ -117,6 +154,33 @@ export const ArticleShow = () => { <Typography>No media found</Typography> )} </Grid> + + <Stack gap={2}> + <Typography variant="body1" fontWeight="bold"> + Link Media + </Typography> + + <Stack gap={2.5}> + <FormControl fullWidth> + <InputLabel>Media</InputLabel> + <Select value={selectedMediaId} onChange={(e) => setSelectedMediaId(e.target.value)} label="Media" fullWidth> + {availableMedia.map((mediaItem) => ( + <MenuItem key={mediaItem.id} value={mediaItem.id}> + {mediaItem.filename} + </MenuItem> + ))} + </Select> + </FormControl> + + <FormControl fullWidth> + <TextField type="number" label="Media Order" name="heading" value={mediaOrder} onChange={(e) => setMediaOrder(Number(e.target.value))} fullWidth InputLabelProps={{shrink: true}} /> + </FormControl> + + <Button variant="contained" onClick={linkMedia} disabled={!selectedMediaId}> + Link Media + </Button> + </Stack> + </Stack> </Stack> </Stack> </Show>