add post option for media to /article/show page
				
					
				
			This commit is contained in:
		| @@ -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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user