Skip to content
Merged

d < m #940

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@
width: fit-content;
max-width: 100%;
font: 600 13px/22px var(--base-font);
text-wrap: wrap;

&.clarification-item-section-body-bubble-primary {
background: #2987fd;
Expand Down
12 changes: 5 additions & 7 deletions react/src/dashboard/components/elements/FileAttachmentsList.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React, { useCallback } from 'react';
import File from '../../props/models/File';
import { useFileService } from '../../services/FileService';
import { useFundRequestValidatorService } from '../../services/FundRequestValidatorService';
import useFilePreview from '../../services/helpers/useFilePreview';
import { isPdfExtension, isPreviewableExtension } from '../../helpers/filePreview';

export default function FileAttachmentsList({ attachments }: { attachments: Array<{ file: File; date?: string }> }) {
const filePreview = useFilePreview();

const fileService = useFileService();
const fundRequestService = useFundRequestValidatorService();

const hasFilePreview = useCallback((file) => fundRequestService.hasFilePreview(file), [fundRequestService]);

const downloadFile = useCallback(
(e: React.MouseEvent<HTMLElement>, file: File) => {
Expand Down Expand Up @@ -54,12 +51,13 @@ export default function FileAttachmentsList({ attachments }: { attachments: Arra
onClick={(e) => downloadFile(e, attachment.file)}>
<div className="mdi mdi-download" aria-hidden="true" />
</button>
{hasFilePreview(attachment.file) && (

{isPreviewableExtension(attachment.file?.ext) && (
<button
type="button"
className="attachment-action"
title={attachment.file.ext == 'pdf' ? 'Bekijk PDF-bestand' : 'Bekijk file'}
aria-label={attachment.file.ext == 'pdf' ? 'Bekijk PDF-bestand' : 'Bekijk file'}
title={isPdfExtension(attachment.file.ext) ? 'Bekijk PDF-bestand' : 'Bekijk file'}
aria-label={isPdfExtension(attachment.file.ext) ? 'Bekijk PDF-bestand' : 'Bekijk file'}
onClick={(e) => previewFile(e, attachment.file)}>
<div className="mdi mdi-eye" aria-hidden="true" />
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import useOpenModal from '../../../../dashboard/hooks/useOpenModal';
import ModalImagePreview from '../../modals/ModalImagePreview';
import ModalPdfPreview from '../../modals/ModalPdfPreview';
import { FileUploaderItem } from '../../../../webshop/components/elements/file-uploader/FileUploader';
import {
isImageExtension,
isPdfExtension,
isPreviewableExtension,
normalizeFileExtension,
} from '../../../helpers/filePreview';

export default function FileUploaderItemView({
item,
Expand All @@ -31,15 +37,22 @@ export default function FileUploaderItemView({
e.preventDefault();
e.stopPropagation();

if (file.file_data.ext == 'pdf') {
const fileData = file.file_data;
const fileExtension = normalizeFileExtension(fileData?.ext);

if (!fileData || !isPreviewableExtension(fileExtension)) {
return;
}

if (isPdfExtension(fileExtension)) {
fileService
.downloadBlob(file.file_data)
.downloadBlob(fileData)
.then((res) => {
openModal((modal) => <ModalPdfPreview modal={modal} rawPdfFile={res.data} />);
})
.catch((err: ResponseError) => console.error(err));
} else if (['png', 'jpeg', 'jpg'].includes(file.file_data.ext)) {
openModal((modal) => <ModalImagePreview modal={modal} imageSrc={file.file_data.url} />);
} else if (isImageExtension(fileExtension)) {
openModal((modal) => <ModalImagePreview modal={modal} imageSrc={fileData.url} />);
}
},
[fileService, openModal],
Expand Down Expand Up @@ -83,8 +96,8 @@ export default function FileUploaderItemView({
<button
type="button"
className="attachment-action"
title={item.file_data?.ext == 'pdf' ? 'Bekijk PDF-bestand' : 'Bekijk file'}
aria-label={item.file_data?.ext == 'pdf' ? 'Bekijk PDF-bestand' : 'Bekijk file'}
title={isPdfExtension(item.file_data?.ext) ? 'Bekijk PDF-bestand' : 'Bekijk file'}
aria-label={isPdfExtension(item.file_data?.ext) ? 'Bekijk PDF-bestand' : 'Bekijk file'}
onClick={(e) => previewFile(e, item)}>
<div className="mdi mdi-eye" aria-hidden="true" />
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ApiResponseSingle } from '../../../props/ApiResponses';
import ModalReimbursementResolve from '../../modals/ModalReimbursementResolve';
import ModalReimbursementDetailsEdit from '../../modals/ModalReimbursementDetailsEdit';
import useFilePreview from '../../../services/helpers/useFilePreview';
import { isPdfExtension, isPreviewableExtension } from '../../../helpers/filePreview';
import { useFileService } from '../../../services/FileService';
import useTranslate from '../../../hooks/useTranslate';
import usePushApiError from '../../../hooks/usePushApiError';
Expand Down Expand Up @@ -110,10 +111,6 @@ export default function ReimbursementsView() {
[fileService, pushApiError, setProgress],
);

const hasFilePreview = useCallback((file) => {
return ['pdf', 'png', 'jpeg', 'jpg'].includes(file.ext);
}, []);

const previewFile = useCallback(
(e: React.MouseEvent<HTMLElement>, file: File) => {
e?.preventDefault();
Expand Down Expand Up @@ -155,7 +152,7 @@ export default function ReimbursementsView() {
);

const storeNote = useCallback(
(data) => {
(data: object) => {
return reimbursementService.storeNote(activeOrganization.id, reimbursement?.id, data);
},
[activeOrganization.id, reimbursement?.id, reimbursementService],
Expand Down Expand Up @@ -503,10 +500,10 @@ export default function ReimbursementsView() {
<div className="attachment-date">
{reimbursement.created_at_locale}
</div>
{hasFilePreview(file) && (
{isPreviewableExtension(file?.ext) && (
<div
title={
file.ext == 'pdf'
isPdfExtension(file?.ext)
? 'Bekijk PDF-bestand'
: 'Bekijk file'
}
Expand Down
20 changes: 20 additions & 0 deletions react/src/dashboard/helpers/filePreview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const PDF_EXTENSIONS = ['pdf'];
const IMAGE_EXTENSIONS = ['png', 'jpeg', 'jpg'];
const PREVIEW_EXTENSIONS = [...IMAGE_EXTENSIONS, ...PDF_EXTENSIONS];

const normalizeFileExtension = (ext?: string) => (ext || '').toLowerCase();

const isPreviewableExtension = (ext?: string) => PREVIEW_EXTENSIONS.includes(normalizeFileExtension(ext));

const isImageExtension = (ext?: string) => IMAGE_EXTENSIONS.includes(normalizeFileExtension(ext));

const isPdfExtension = (ext?: string) => PDF_EXTENSIONS.includes(normalizeFileExtension(ext));

export {
IMAGE_EXTENSIONS,
PREVIEW_EXTENSIONS,
isImageExtension,
isPdfExtension,
isPreviewableExtension,
normalizeFileExtension,
};
5 changes: 0 additions & 5 deletions react/src/dashboard/services/FundRequestValidatorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import ApiRequestService from './ApiRequestService';
import FundRequest, { FundRequestFormula } from '../props/models/FundRequest';
import ApiResponse, { ApiResponseSingle, ResponseSimple } from '../props/ApiResponses';
import Note from '../props/models/Note';
import File from '../props/models/File';
import FundRequestRecord from '../props/models/FundRequestRecord';
import { ConfigurableTableColumn } from '../components/pages/vouchers/hooks/useConfigurableTable';
import { ExportFieldProp } from '../components/modals/ModalExportDataSelect';
Expand Down Expand Up @@ -119,10 +118,6 @@ export class FundRequestValidatorService<T = FundRequest> {
return this.apiRequest.post(`${this.prefix}/${organizationId}/fund-requests/${id}/notes`, data);
}

public hasFilePreview(file: File) {
return ['pdf', 'png', 'jpeg', 'jpg'].includes(file.ext);
}

public getColumns(): Array<ConfigurableTableColumn> {
const list = ['id', 'requester_email', 'fund_name', 'created_at', 'assignee_email', 'state'].filter(
(item) => item,
Expand Down
16 changes: 14 additions & 2 deletions react/src/dashboard/services/helpers/useFilePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ import useOpenModal from '../../hooks/useOpenModal';
import File from '../../props/models/File';
import { useFileService } from '../FileService';
import usePushApiError from '../../hooks/usePushApiError';
import {
isImageExtension,
isPdfExtension,
isPreviewableExtension,
normalizeFileExtension,
} from '../../helpers/filePreview';

export default function useFilePreview() {
const openModal = useOpenModal();
Expand All @@ -14,14 +20,20 @@ export default function useFilePreview() {

return useCallback(
(file: File) => {
if (file.ext == 'pdf') {
const extension = normalizeFileExtension(file?.ext);

if (!isPreviewableExtension(extension)) {
return;
}

if (isPdfExtension(extension)) {
fileService
.downloadBlob(file)
.then((res) => {
openModal((modal) => <ModalPdfPreview modal={modal} rawPdfFile={res.data} />);
})
.catch(pushApiError);
} else if (['png', 'jpeg', 'jpg'].includes(file.ext)) {
} else if (isImageExtension(extension)) {
openModal((modal) => <ModalImagePreview modal={modal} imageSrc={file.url} />);
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ResponseError } from '../../../../dashboard/props/ApiResponses';
import useTranslate from '../../../../dashboard/hooks/useTranslate';
import classNames from 'classnames';
import BlockWarning from '../block-warning/BlockWarning';
import { isPreviewableExtension } from '../../../../dashboard/helpers/filePreview';

export type FileUploaderItem = {
id?: string;
Expand Down Expand Up @@ -104,7 +105,7 @@ export default function FileUploader({
id: uniqueId('file_uploader_'),
file: null,
file_data: file,
has_preview: ['pdf', 'png', 'jpeg', 'jpg'].includes(file.ext),
has_preview: isPreviewableExtension(file.ext),
uploaded: true,
}),
) || [],
Expand Down Expand Up @@ -159,7 +160,7 @@ export default function FileUploader({
uploaded: true,
uploading: false,
file_data: res.data.data,
has_preview: ['pdf', 'png', 'jpeg', 'jpg'].includes(res.data.data?.ext),
has_preview: isPreviewableExtension(res.data.data?.ext),
}));

callbackRef?.current?.onFileUploaded?.(makeFileEvent(filesRef?.current, fileItem));
Expand Down Expand Up @@ -247,8 +248,30 @@ export default function FileUploader({

const filterSelectedFiles = useCallback(
(files: FileList) => {
if (!acceptedFiles?.length) {
return [...files];
}

const accepted = acceptedFiles.map((item) => item.toLowerCase());

return [...files].filter((file) => {
return acceptedFiles.includes('.' + file.name.split('.')[file.name.split('.').length - 1]);
const fileName = file.name.toLowerCase();
const fileType = (file.type || '').toLowerCase();
const lastDotIndex = fileName.lastIndexOf('.');
const extension = lastDotIndex === -1 ? '' : fileName.slice(lastDotIndex);

return accepted.some((item) => {
if (item.startsWith('.')) {
return extension === item;
}

if (item.endsWith('/*')) {
const prefix = item.slice(0, -1);
return fileType.startsWith(prefix);
}

return fileType === item;
});
});
},
[acceptedFiles],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import ModalPdfPreview from '../../modals/ModalPdfPreview';
import { FileUploaderItem } from './FileUploader';
import useTranslate from '../../../../dashboard/hooks/useTranslate';
import classNames from 'classnames';
import {
isImageExtension,
isPdfExtension,
isPreviewableExtension,
normalizeFileExtension,
} from '../../../../dashboard/helpers/filePreview';

export default function FileUploaderItemView({
item,
Expand All @@ -32,22 +38,33 @@ export default function FileUploaderItemView({
const name = useMemo(() => {
return item.file?.name || item.file_data?.original_name || '';
}, [item.file?.name, item.file_data?.original_name]);
const extension = useMemo(() => name?.split('.')[name.split('.').length - 1], [name]);

const extension = useMemo(() => {
const lastDotIndex = name.lastIndexOf('.');
return lastDotIndex === -1 ? '' : name.slice(lastDotIndex + 1).toLowerCase();
}, [name]);

const previewFile = useCallback(
(e: React.MouseEvent, file: Partial<FileUploaderItem>) => {
e.preventDefault();
e.stopPropagation();

if (file.file_data.ext == 'pdf') {
const fileData = file.file_data;
const fileExtension = normalizeFileExtension(fileData?.ext);

if (!fileData || !isPreviewableExtension(fileExtension)) {
return;
}

if (isPdfExtension(fileExtension)) {
fileService
.downloadBlob(file.file_data)
.downloadBlob(fileData)
.then((res) => {
openModal((modal) => <ModalPdfPreview modal={modal} rawPdfFile={res.data} />);
})
.catch((err: ResponseError) => console.error(err));
} else if (['png', 'jpeg', 'jpg'].includes(file.file_data.ext)) {
openModal((modal) => <ModalImagePreview modal={modal} imageSrc={file.file_data.url} />);
} else if (isImageExtension(fileExtension)) {
openModal((modal) => <ModalImagePreview modal={modal} imageSrc={fileData.url} />);
}
},
[fileService, openModal],
Expand Down
Loading