diff --git a/package.json b/package.json index ca3a5580..126127a6 100644 --- a/package.json +++ b/package.json @@ -169,7 +169,7 @@ "src/**/*.{js,jsx,mjs}" ], "moduleNameMapper": { - "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/src/__mocks__/fileMock.js", "\\.(css|scss)$": "identity-obj-proxy" }, "testMatch": [ diff --git a/src/components/inputs/upload-input-v3/__tests__/upload-input-v3.test.js b/src/components/inputs/upload-input-v3/__tests__/upload-input-v3.test.js index 78e26f44..e7a940ae 100644 --- a/src/components/inputs/upload-input-v3/__tests__/upload-input-v3.test.js +++ b/src/components/inputs/upload-input-v3/__tests__/upload-input-v3.test.js @@ -288,6 +288,51 @@ describe('UploadInputV3', () => { }); }); + describe('File Preview and Download', () => { + test('renders a preview image linked to the file', () => { + const files = [{ filename: 'image.png', size: 102400, public_url: 'https://cdn.example.com/image.png' }]; + render(); + const img = screen.getByRole('img', { name: 'image.png' }); + const previewLink = img.closest('a'); + expect(previewLink).toHaveAttribute('href', 'https://cdn.example.com/image.png'); + expect(previewLink).toHaveAttribute('target', '_blank'); + expect(previewLink).not.toHaveAttribute('download'); + }); + + test('prefers private_url and falls back to public_url when private_url is "#"', () => { + const { rerender, container } = render(); + expect(container.querySelector('a[download]')).toHaveAttribute('href', 'https://private.example.com/a.png'); + + rerender(); + expect(container.querySelector('a[download]')).toHaveAttribute('href', 'https://cdn.example.com/a.png'); + }); + + test('filename is a download link with correct href', () => { + const files = [{ filename: 'document.pdf', size: 102400, public_url: 'https://cdn.example.com/document.pdf' }]; + const { container } = render(); + const downloadLink = container.querySelector('a[download]'); + expect(downloadLink).toHaveAttribute('href', 'https://cdn.example.com/document.pdf'); + expect(downloadLink).toHaveAttribute('target', '_blank'); + expect(downloadLink).toHaveTextContent('document.pdf'); + }); + + test('preview image falls back to file_icon on load error', () => { + const files = [{ filename: 'document.pdf', size: 102400, public_url: 'https://cdn.example.com/document.pdf' }]; + render(); + const img = screen.getByRole('img', { name: 'document.pdf' }); + fireEvent.error(img); + expect(img).not.toHaveAttribute('src', 'https://cdn.example.com/document.pdf'); + }); + }); + describe('Edge Cases', () => { test('handles empty value array', () => { const { container } = render(); diff --git a/src/components/inputs/upload-input-v3/index.js b/src/components/inputs/upload-input-v3/index.js index d90e6a75..7d95d79d 100644 --- a/src/components/inputs/upload-input-v3/index.js +++ b/src/components/inputs/upload-input-v3/index.js @@ -25,6 +25,8 @@ import CheckCircleIcon from "@mui/icons-material/CheckCircle"; import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; import CloseIcon from "@mui/icons-material/Close"; import { DropzoneV3 } from './dropzone-v3'; +import ProgressiveImg from '../../progressive-img'; +import file_icon from '../upload-input/file.png'; import './index.less'; const UploadInputV3 = ({ @@ -41,7 +43,7 @@ const UploadInputV3 = ({ id, parallelChunkUploads = false, maxConcurrentChunks = 6, - onError = () => {}, + onError = () => { }, getAllowedExtensions = null, getMaxSize = null, error, @@ -371,21 +373,37 @@ const UploadInputV3 = ({ {value.map((file, index) => { const filename = file.filename; const fileSize = formatFileSize(file.size); + let src = file?.private_url || file?.public_url || file?.file_url; + if (src === '#') src = file?.public_url; + // custom replace for dropbox case ( download vs raw) + const previewSrc = src ? src.replace("?dl=0", "?raw=1") : filename; return ( - - + + + + {filename}