Refactor FilePicker and AttachmentList components to enhance type definitions and improve code clarity

This commit is contained in:
Nawaz Dhandala
2025-11-19 16:02:41 +00:00
parent a036830009
commit 8d5f8454c4
2 changed files with 50 additions and 16 deletions

View File

@@ -14,7 +14,8 @@ import React, {
useEffect,
useState,
} from "react";
import { useDropzone } from "react-dropzone";
import { useDropzone, type FileRejection } from "react-dropzone";
import type { AxiosProgressEvent } from "axios";
export interface ComponentProps {
initialValue?: undefined | Array<FileModel> | FileModel;
@@ -41,6 +42,21 @@ type UploadStatus = {
errorMessage?: string | undefined;
};
type AddUploadStatusFunction = (status: UploadStatus) => void;
type UpdateUploadStatusFunction = (
id: string,
updates: Partial<UploadStatus>,
) => void;
type UpdateUploadProgressFunction = (
id: string,
total?: number,
loaded?: number,
) => void;
type RemoveUploadStatusFunction = (id: string) => void;
type BuildFileSizeErrorFunction = (fileNames: Array<string>) => string;
type ResolveMimeTypeFunction = (file: File) => MimeType | undefined;
type FormatFileSizeFunction = (file: FileModel) => string | null;
const MAX_FILE_SIZE_BYTES: number = 10 * 1024 * 1024; // 10MB limit
const FilePicker: FunctionComponent<ComponentProps> = (
@@ -53,13 +69,15 @@ const FilePicker: FunctionComponent<ComponentProps> = (
const [acceptTypes, setAcceptTypes] = useState<Dictionary<Array<string>>>({});
const [uploadStatuses, setUploadStatuses] = useState<Array<UploadStatus>>([]);
const addUploadStatus = (status: UploadStatus): void => {
const addUploadStatus: AddUploadStatusFunction = (
status: UploadStatus,
): void => {
setUploadStatuses((current: Array<UploadStatus>) => {
return [...current, status];
});
};
const updateUploadStatus = (
const updateUploadStatus: UpdateUploadStatusFunction = (
id: string,
updates: Partial<UploadStatus>,
): void => {
@@ -75,7 +93,7 @@ const FilePicker: FunctionComponent<ComponentProps> = (
});
};
const updateUploadProgress = (
const updateUploadProgress: UpdateUploadProgressFunction = (
id: string,
total?: number,
loaded?: number,
@@ -101,7 +119,7 @@ const FilePicker: FunctionComponent<ComponentProps> = (
});
};
const removeUploadStatus = (id: string): void => {
const removeUploadStatus: RemoveUploadStatusFunction = (id: string): void => {
setUploadStatuses((current: Array<UploadStatus>) => {
return current.filter((upload: UploadStatus) => {
return upload.id !== id;
@@ -143,7 +161,9 @@ const FilePicker: FunctionComponent<ComponentProps> = (
}
}, [props.value]);
const buildFileSizeError = (fileNames: Array<string>): string => {
const buildFileSizeError: BuildFileSizeErrorFunction = (
fileNames: Array<string>,
): string => {
if (fileNames.length === 0) {
return "";
}
@@ -161,12 +181,12 @@ const FilePicker: FunctionComponent<ComponentProps> = (
noClick: true,
disabled: props.readOnly || isLoading,
maxSize: MAX_FILE_SIZE_BYTES,
onDropRejected: (fileRejections) => {
onDropRejected: (fileRejections: Array<FileRejection>) => {
const oversizedFiles: Array<string> = fileRejections
.filter((rejection) => {
.filter((rejection: FileRejection) => {
return rejection.file.size > MAX_FILE_SIZE_BYTES;
})
.map((rejection) => {
.map((rejection: FileRejection) => {
return rejection.file.name;
});
@@ -185,7 +205,9 @@ const FilePicker: FunctionComponent<ComponentProps> = (
try {
// Upload these files.
const filesResult: Array<FileModel> = [];
const resolveMimeType = (file: File): MimeType | undefined => {
const resolveMimeType: ResolveMimeTypeFunction = (
file: File,
): MimeType | undefined => {
const direct: string | undefined = file.type || undefined;
if (direct && Object.values(MimeType).includes(direct as MimeType)) {
return direct as MimeType;
@@ -260,7 +282,7 @@ const FilePicker: FunctionComponent<ComponentProps> = (
requestOptions: {
overrideRequestUrl: CommonURL.fromURL(FILE_URL),
apiRequestOptions: {
onUploadProgress: (progressEvent) => {
onUploadProgress: (progressEvent: AxiosProgressEvent) => {
updateUploadProgress(
uploadId,
progressEvent.total,
@@ -307,7 +329,9 @@ const FilePicker: FunctionComponent<ComponentProps> = (
type GetThumbsFunction = () => Array<ReactElement>;
const formatFileSize = (file: FileModel): string | null => {
const formatFileSize: FormatFileSizeFunction = (
file: FileModel,
): string | null => {
const buffer: Buffer | undefined = file.file;
if (!buffer) {
return null;
@@ -324,7 +348,7 @@ const FilePicker: FunctionComponent<ComponentProps> = (
const getThumbs: GetThumbsFunction = (): Array<ReactElement> => {
return filesModel.map((file: FileModel, i: number) => {
const key: string = file._id?.toString() || `${file.name || "file"}-${i}`;
const removeFile = (): void => {
const removeFile: VoidFunction = (): void => {
const tempFileModel: Array<FileModel> = [...filesModel];
tempFileModel.splice(i, 1);
setFilesModel(tempFileModel);

View File

@@ -17,6 +17,10 @@ export interface AttachmentListProps {
buildAttachmentUrl?: (fileId: string) => string;
}
type GetFileExtensionFunction = (fileName?: string | null) => string | null;
type GetFileMetadataFunction = (file: FileModel) => string | null;
type GetAttachmentNameFunction = (file: FileModel) => string;
const AttachmentList: FunctionComponent<AttachmentListProps> = (
props: AttachmentListProps,
): ReactElement | null => {
@@ -37,7 +41,9 @@ const AttachmentList: FunctionComponent<AttachmentListProps> = (
const projectId: string | null =
ProjectUtil.getCurrentProjectId()?.toString() || null;
const getFileExtension = (fileName?: string | null): string | null => {
const getFileExtension: GetFileExtensionFunction = (
fileName?: string | null,
): string | null => {
if (!fileName) {
return null;
}
@@ -52,7 +58,9 @@ const AttachmentList: FunctionComponent<AttachmentListProps> = (
return trimmedName.substring(lastDotIndex + 1).toUpperCase();
};
const getFileMetadata = (file: FileModel): string | null => {
const getFileMetadata: GetFileMetadataFunction = (
file: FileModel,
): string | null => {
const metadataParts: Array<string> = [];
if (file.fileType) {
@@ -72,7 +80,9 @@ const AttachmentList: FunctionComponent<AttachmentListProps> = (
return metadataParts.join(" • ");
};
const getAttachmentName = (file: FileModel): string => {
const getAttachmentName: GetAttachmentNameFunction = (
file: FileModel,
): string => {
if (file.name) {
return file.name;
}