diff --git a/src/modules/details/components/ImageTag.tsx b/src/modules/details/components/ImageTag.tsx index 931cc56..2b04306 100644 --- a/src/modules/details/components/ImageTag.tsx +++ b/src/modules/details/components/ImageTag.tsx @@ -1,27 +1,54 @@ +import axios from 'axios'; +import { useQuery } from 'react-query'; import { CircularProgress } from '@mui/material'; -import { isLabelWithInternallyDisabledControl } from '@testing-library/user-event/dist/utils'; -import { s3GetPresignedUrl} from 'apis/utils/mediaUpload/awsmedia'; -import Loader from 'modules/Auth/components/Loader'; -import { useEffect, useState } from 'react'; +import VisibilityIcon from '@mui/icons-material/Visibility'; +import DownloadIcon from '@mui/icons-material/Download'; +import { s3GetPresignedUrl } from 'apis/utils/mediaUpload/awsmedia'; +import MediaButton from './MediaButton'; +import { MediaS3Tagparams } from '../type'; -export const ImageS3Tag = ({ path }) => { - const [srcImg, setSrcImg] = useState(); - const [isLoading, setIsLoading] = useState(false); - useEffect(() => { - setIsLoading(true); - s3GetPresignedUrl(path) - .then((img) => { - setIsLoading(false); - setSrcImg(img); - }) - .catch((e) => { - console.log('unable to fetch', e); - setIsLoading(false); - }); - }, []); - return isLoading ? ( - - ) : ( - Image +export const MediaS3Tag = ({ path }: MediaS3Tagparams) => { + const { data: srcFile, isLoading, error } = useQuery(['presignedUrl', path], () => s3GetPresignedUrl(path), { + enabled: !!path, + }); + + const handleDownload = async () => { + if (srcFile) { + try { + const response = await axios.get(srcFile, { responseType: 'blob' }); + const blob = new Blob([response.data]); + const downloadUrl = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = downloadUrl; + link.download = path.split('/').pop() || 'download'; + link.click(); + window.URL.revokeObjectURL(downloadUrl); + } catch (error) { + console.error('Download failed:', error); + } + } + }; + + const handleView = () => { + if (srcFile) { + window.open(srcFile, '_blank'); + } + }; + + if (isLoading) { + return ; + } + + return ( +
+ {srcFile ? ( +
+ } /> + } /> +
+ ) : ( +

Unable to load file

+ )} +
); }; diff --git a/src/modules/details/components/MediaButton.tsx b/src/modules/details/components/MediaButton.tsx new file mode 100644 index 0000000..0751906 --- /dev/null +++ b/src/modules/details/components/MediaButton.tsx @@ -0,0 +1,23 @@ +import { Button } from '@mui/material'; +import { ReactNode } from 'react'; +import './styles.scss'; + +interface MediaButtonProps { + handleFunction: () => void; + children: ReactNode; + icon: React.ReactNode; +} + +const MediaButton = ({ handleFunction, children, icon }: MediaButtonProps) => { + return ( + + ); +}; +export default MediaButton; diff --git a/src/modules/details/components/Timeline.tsx b/src/modules/details/components/Timeline.tsx index 07c968e..be7c5f8 100644 --- a/src/modules/details/components/Timeline.tsx +++ b/src/modules/details/components/Timeline.tsx @@ -11,7 +11,7 @@ import { Box, Chip, Paper, Typography } from '@mui/material'; import { DateFormate, getLastDaysFrom } from 'apis/utils/date.utils'; import { ticketStatusColours } from '../constants'; import { ITicketActivity } from '../type'; -import { ImageS3Tag } from './ImageTag'; +import { MediaS3Tag } from './ImageTag'; export const TimelineComponent = ({ activities }: any) => { return ( @@ -76,7 +76,7 @@ const TimeLineDescription = ({ activity }: { activity: ITicketActivity }) => {

)} {activity?.asset_url?.map((item) => ( - + ))} diff --git a/src/modules/details/components/styles.scss b/src/modules/details/components/styles.scss new file mode 100644 index 0000000..6c02205 --- /dev/null +++ b/src/modules/details/components/styles.scss @@ -0,0 +1,10 @@ +.custom-button{ + background-color: rgb(211, 211, 211) !important; + color: #000; + margin: 5px; + border-radius: 16px; +} + +.custom-button:hover { + background-color: rgb(169, 169, 169) !important; +} diff --git a/src/modules/details/index.tsx b/src/modules/details/index.tsx index 18c383c..4dbde9d 100644 --- a/src/modules/details/index.tsx +++ b/src/modules/details/index.tsx @@ -25,7 +25,7 @@ import EditIcon from '@mui/icons-material/Edit'; import { ticketStatusColours } from './constants'; -import { ImageS3Tag } from './components/ImageTag'; +import { MediaS3Tag } from './components/ImageTag'; import { UserContext } from 'App'; import { ROLES } from 'routes/roleConstants'; @@ -133,14 +133,14 @@ function Details() { - Image + Attachment {ticket?.asset_url?.map((item) => ( - + ))} diff --git a/src/modules/details/type.ts b/src/modules/details/type.ts index 4c2f4df..13a3fe9 100644 --- a/src/modules/details/type.ts +++ b/src/modules/details/type.ts @@ -93,3 +93,7 @@ export interface IProgressTicketParams { id: number; setOpenEdit: (value: React.SetStateAction) => void; } + +export interface MediaS3Tagparams { + path: string; +} diff --git a/src/modules/shared/UploadBucket.tsx b/src/modules/shared/UploadBucket.tsx index f5c4e44..9d3d53f 100644 --- a/src/modules/shared/UploadBucket.tsx +++ b/src/modules/shared/UploadBucket.tsx @@ -4,7 +4,7 @@ import { Box } from '@mui/system'; import { IconButton, Typography } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { useState } from 'react'; -import { ALLOWED_TYPES } from './constants'; +import { ALLOWED_TYPES, MAX_FILE_SIZE } from './constants'; export const UploadBucket = ({ isLoading, @@ -32,11 +32,20 @@ export const UploadBucket = ({ if (invalidFile) { setErrorMessage(`Invalid file type: ${invalidFile.name}`); - } else { - setErrorMessage(null); - handleChange(selectedFiles); + return; } + + const oversizedFile = selectedFiles.find((file) => file.size > MAX_FILE_SIZE); + + if (oversizedFile) { + setErrorMessage(`File exceeds size limit: ${oversizedFile.name}`); + return; + } + + setErrorMessage(null); + handleChange(selectedFiles); }; + return (