Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(multidropzone): [SIDE-7] Update MultiDropzone component to have default accept type #315

Merged
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
43 changes: 43 additions & 0 deletions src/lib/components/multiDropzone/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,38 @@ export const ErrorState = () => (
/>
);

export const TooManyFilesErrorState = () => (
<MultiDropzone
maxFiles={2}
isCondensed
uploadedFiles={[
{
id: '123',
progress: 100,
name: 'test_file_name.pdf',
previewUrl: 'http://getpopsure.com/test_file_name.pdf',
},
{
id: '124',
progress: 100,
name: 'test_file_name.pdf',
previewUrl: 'http://getpopsure.com/test_file_name.pdf',
showLoadingSpinner: true,
showProgressBar: false,
},
{
id: '125',
progress: 100,
name: 'test_file_name.pdf',
previewUrl: 'http://getpopsure.com/test_file_name.pdf',
showLoadingSpinner: true,
},
]}
uploading={false}
onFileSelect={() => {}}
/>
);

export const AcceptingOnlyImages = () => (
<MultiDropzone
accept="image"
Expand All @@ -199,6 +231,17 @@ export const AcceptingOnlyDocuments = () => (
/>
);

export const AcceptingOnlyVideos = () => (
<MultiDropzone
accept="video"
isCondensed
uploadedFiles={[]}
onFileSelect={() => {}}
uploading={false}
onRemoveFile={() => {}}
/>
);

export const LimitingFileSizeTo2MB = () => (
<MultiDropzone
isCondensed
Expand Down
14 changes: 7 additions & 7 deletions src/lib/components/multiDropzone/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('MultiDropzone component', () => {
],
});

expect(screen.getByText('Too many files.')).toBeVisible();
expect(screen.getByText('You can upload maximum 1 files.')).toBeVisible();
});

it('should show max file size error message', async () => {
Expand All @@ -82,12 +82,12 @@ describe('MultiDropzone component', () => {
});

expect(
getByText('File type must be one of DOC, DOCX, PDF')
getByText('File type must be DOC, DOCX, PDF')
).toBeInTheDocument();
});

it('should remove wrong filetype error message', async () => {
const { getByAltText, getByTestId, queryByText, user } = setup({
const { getByTestId, queryByText, user } = setup({
accept: 'document',
});
const input = getByTestId(inputTestId);
Expand All @@ -101,7 +101,7 @@ describe('MultiDropzone component', () => {
await user.click(getByTestId('remove-button'));

expect(
queryByText('File type must be one of DOC, DOCX, PDF')
queryByText('File type must be PDF')
).not.toBeInTheDocument();
});
});
Expand All @@ -128,14 +128,14 @@ describe('MultiDropzone component', () => {
const screen = setup({ accept: 'image' });

expect(
screen.getByText('Supports HEIC, BMP, JPEG, JPG, PNG')
screen.getByText('Supports images')
).toBeInTheDocument();
});

it('should show document accept file type label', () => {
const screen = setup({ accept: 'document' });

expect(screen.getByText('Supports DOC, DOCX, PDF')).toBeInTheDocument();
expect(screen.getByText('Supports documents')).toBeInTheDocument();
});

it('should custom document accept file type label', () => {
Expand All @@ -146,7 +146,7 @@ describe('MultiDropzone component', () => {
},
});

expect(screen.getByText('Supports PDF, JPG')).toBeInTheDocument();
expect(screen.getByText('Supports images, videos and documents')).toBeInTheDocument();
});

it('should show disabled text if is uploading', () => {
Expand Down
14 changes: 4 additions & 10 deletions src/lib/components/multiDropzone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
UploadStatus,
} from './types';

import { formatBytes } from '../../util/formatBytes';
import { getPlaceholder } from './utils';

interface MultiDropzoneProps {
uploadedFiles: UploadedFile[];
Expand Down Expand Up @@ -50,13 +50,7 @@ const MultiDropzone = ({
const [errors, setErrors] = useState<ErrorMessage[]>([]);
const formattedAccept = getFormattedAcceptObject(accept);
const fileList = formatAcceptFileList(formattedAccept);
const maxSizePlaceholder =
maxSize && maxSize > 0
? `${textOverrides?.sizeUpToText || 'up to'} ${formatBytes(maxSize)}`
: '';
const placeholder = `${textOverrides?.supportsTextShort || 'Supports'} ${
fileList || 'JPEG, PNG, PDF'
} ${maxSizePlaceholder}`;
const placeholder = getPlaceholder(textOverrides, accept, maxSize);
const isOverMaxFiles = maxFiles > 0 && uploadedFiles.length > maxFiles;

const removeError = (removeId: string) =>
Expand Down Expand Up @@ -156,8 +150,8 @@ const MultiDropzone = ({
)}

<AnimateHeight duration={300} height={isOverMaxFiles ? 'auto' : 0}>
<p className="tc-red-500 p-p--small">
{textOverrides?.tooManyFilesError || 'Too many files.'}
<p className="tc-red-500 mt16">
{textOverrides?.tooManyFilesError || `You can upload maximum ${maxFiles} files.`}
</p>
</AnimateHeight>
</div>
Expand Down
23 changes: 21 additions & 2 deletions src/lib/components/multiDropzone/types.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
import { Accept } from "react-dropzone";

export enum FileMimeTypes {
avi = "video/x-msvideo",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👴

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, I know 😄

bmp = "image/bmp",
doc = "application/msword",
docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
heic = "image/heic",
jpeg = "image/jpeg",
jpg = "image/jpg",
mov = "video/quicktime",
mp4 = "video/mp4",
pdf = "application/pdf",
png = "image/png",
svg = "image/svg+xml",
tif = "image/tiff",
tiff = "image/tiff",
webp = "image/webp",
}

// mp4, mov, avi

export type FileType = keyof typeof FileMimeTypes;

export type UploadStatus = 'UPLOADING' | 'COMPLETE' | 'ERROR';

export const DOCUMENT_FILES: FileType[] = ['doc', 'docx', 'pdf'];
export const IMAGE_FILES: FileType[] = ['heic', 'bmp', 'jpeg', 'jpg', 'png'];
export const VIDEO_FILES: FileType[] = ['avi', 'mov', 'mp4'];
export const IMAGE_FILES: FileType[] = [
'heic',
'bmp',
'jpeg',
'jpg',
'png',
'tiff',
'webp',
'svg'
];

export interface UploadedFile {
id: string;
Expand All @@ -31,7 +47,7 @@ export interface UploadedFile {
showLoadingSpinner?: boolean;
}

export type AcceptType = "document" | "image" | Accept;
export type AcceptType = "document" | "image" | "video" | Accept;

export interface TextOverrides {
currentlyUploadingText?: string;
Expand All @@ -41,6 +57,9 @@ export interface TextOverrides {
sizeUpToText?: string;
supportsText?: string;
supportsTextShort?: string;
supportsTextDocument?: string;
supportsTextImage?: string;
supportsTextVideo?: string;
tooManyFilesError?: string;
}
export interface ErrorMessage {
Expand Down
15 changes: 9 additions & 6 deletions src/lib/components/multiDropzone/utils/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import {

const documentsAccept = {
'application/msword': ['.doc'],
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
'application/pdf': ['.pdf']
'application/pdf': ['.pdf'],
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx']
};

const imagesAccept = {
'image/heic': [".heic"],
'image/bmp': [".bmp"],
'image/jpeg': [".jpeg"],
'image/jpg': [".jpg"],
'image/png': [".png"]
'image/png': [".png"],
'image/svg+xml': [".svg"],
'image/tiff': [".tiff"],
'image/webp': [".webp"]
};

describe('getUploadStatus', () => {
Expand Down Expand Up @@ -56,11 +59,11 @@ describe('formatAcceptFileList', () => {
});

it('Should return documents list if documents accept is passed', () => {
expect(formatAcceptFileList(documentsAccept)).toEqual("DOC, DOCX, PDF");
expect(formatAcceptFileList(documentsAccept)).toEqual("DOC, PDF, DOCX");
});

it('Should return images list if images accept is passed', () => {
expect(formatAcceptFileList(imagesAccept)).toEqual("HEIC, BMP, JPEG, JPG, PNG");
expect(formatAcceptFileList(imagesAccept)).toEqual("HEIC, BMP, JPEG, JPG, PNG, SVG, TIFF, WEBP");
});

it('Should return extension based on accept passed', () => {
Expand Down Expand Up @@ -95,7 +98,7 @@ describe('getErrorMessage', () => {
code: ErrorCode.FileInvalidType,
message: ""
}, { fileList })
).toEqual(`File type must be one of ${fileList}`);
).toEqual(`File type must be ${fileList}`);
});

it('Should return FileInvalidType with textOverride message', () => {
Expand Down
40 changes: 37 additions & 3 deletions src/lib/components/multiDropzone/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
FileType,
IMAGE_FILES,
TextOverrides,
UploadStatus
UploadStatus,
VIDEO_FILES
} from "../types";

export const getUploadStatus = (progress: number, error?: string): UploadStatus => {
Expand All @@ -34,6 +35,7 @@ const formatMimeType = (values: FileType[]): Accept => {

export const DOCUMENT_FILES_ACCEPT = formatMimeType(DOCUMENT_FILES);
export const IMAGE_FILES_ACCEPT = formatMimeType(IMAGE_FILES);
export const VIDEO_FILES_ACCEPT = formatMimeType(VIDEO_FILES);

export const getFormattedAcceptObject = (accept: AcceptType = {}): Accept => {
if (accept === "document") {
Expand All @@ -44,7 +46,19 @@ export const getFormattedAcceptObject = (accept: AcceptType = {}): Accept => {
return IMAGE_FILES_ACCEPT;
};

return accept;
if (accept === "video") {
return VIDEO_FILES_ACCEPT;
}

if (accept) {
return accept;
}

return {
...DOCUMENT_FILES_ACCEPT,
...IMAGE_FILES_ACCEPT,
...VIDEO_FILES_ACCEPT
};
}

export const formatAcceptFileList = (accept: Accept): string => (
Expand All @@ -55,14 +69,34 @@ export const formatAcceptFileList = (accept: Accept): string => (
.toUpperCase()
);

export const getPlaceholder = (
textOverrides?: TextOverrides,
accept?: AcceptType,
maxSize?: number
) => {
const maxSizePlaceholder =
maxSize && maxSize > 0
? `${textOverrides?.sizeUpToText || 'up to'} ${formatBytes(maxSize)}`
: '';

const isAcceptString =
typeof accept === 'string' &&
['video', 'image', 'document'].includes(accept)

const defaultPlaceholder = `${textOverrides?.supportsTextShort || 'Supports images, videos and documents'} ${maxSizePlaceholder}`;
const acceptPlaceholder = `${textOverrides?.supportsTextShort || `Supports ${accept}s ${maxSizePlaceholder}`}`;

return isAcceptString ? acceptPlaceholder : defaultPlaceholder;
}

export const getErrorMessage = (
{ code, message }: FileError,
{ fileList = "", maxSize }: { fileList?: string, maxSize?: number },
textOverrides?: TextOverrides,
): string => {
switch (code) {
case ErrorCode.FileInvalidType:
return `${textOverrides?.fileTypeError || "File type must be one of"} ${fileList}`;
return `${textOverrides?.fileTypeError || "File type must be"} ${fileList}`;
case ErrorCode.FileTooLarge:
return `${textOverrides?.fileTooLargeError || "File is too large. It must be less than"} ${formatBytes(maxSize || 0)}.`;
default:
Expand Down
Loading