Skip to content

Commit 258d735

Browse files
authored
[CLNP-5476] Enhance getMimeTypesUIKitAccepts to support file extensions along with mime types (#1232)
Resolves https://sendbird.atlassian.net/browse/SBISSUE-17456 ## Changes - [x] Updated `getMimeTypesUIKitAccepts` to handle both MIME types and file extensions. - [x] Improved case-insensitive handling of category names (image, video, audio). - [x] Implemented duplicate removal in the returned string. - [x] Updated related test cases to cover new functionality. This change enhances the flexibility of file type handling in our application, allowing for both MIME types and file extensions to be processed. It also improves the robustness of the function by handling case-insensitivity and removing duplicates.
1 parent 5fbf631 commit 258d735

File tree

2 files changed

+157
-37
lines changed

2 files changed

+157
-37
lines changed
Lines changed: 117 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,121 @@
1-
import { getMimeTypesUIKitAccepts, SUPPORTED_MIMES } from '../index';
1+
import { getMimeTypesUIKitAccepts, SUPPORTED_MIMES, SUPPORTED_FILE_EXTENSIONS } from '../index';
22

33
describe('Global-utils/getMimeTypesUIKitAccepts', () => {
4-
it('when no input, should return all SUPPORTED_MIMES.', () => {
5-
const allMimeTypes: string[] = Object.values(SUPPORTED_MIMES)
6-
.reduce((accumulator: string[], mimes: string[]): string[] => {
7-
return accumulator.concat(mimes);
8-
});
9-
expect(getMimeTypesUIKitAccepts()).toBe(allMimeTypes.join());
10-
});
11-
it('when given [image], should return IMAGE mime types.', () => {
12-
expect(getMimeTypesUIKitAccepts(['image'])).toBe(SUPPORTED_MIMES.IMAGE.join());
13-
});
14-
it('when given [image, video], should return IMAGE and VIDEO mime types.', () => {
15-
expect(getMimeTypesUIKitAccepts(['image', 'video']))
16-
.toBe([SUPPORTED_MIMES.IMAGE.join(), SUPPORTED_MIMES.VIDEO.join()].join());
17-
});
18-
it('when given empty array, should return all SUPPORTED_MIMES.', () => {
19-
const allMimeTypes: string[] = Object.values(SUPPORTED_MIMES)
20-
.reduce((accumulator: string[], mimes: string[]): string[] => {
21-
return accumulator.concat(mimes);
22-
});
23-
expect(getMimeTypesUIKitAccepts([])).toBe(allMimeTypes.join());
24-
});
25-
it('when given mime types, should return mime types string.', () => {
26-
const accept = getMimeTypesUIKitAccepts(['image/png', 'image/heic']);
27-
const expected = 'image/png,image/heic';
28-
expect(accept).toBe(expected);
4+
const allTypesAndExtensions = [
5+
...Object.values(SUPPORTED_MIMES).flat(),
6+
...Object.values(SUPPORTED_FILE_EXTENSIONS).flat(),
7+
].join();
8+
9+
it('should return all supported MIME types and file extensions when no input is provided', () => {
10+
expect(getMimeTypesUIKitAccepts()).toBe(allTypesAndExtensions);
11+
});
12+
13+
it('should return all supported MIME types and file extensions when an empty array is provided', () => {
14+
expect(getMimeTypesUIKitAccepts([])).toBe(allTypesAndExtensions);
15+
});
16+
17+
it('should return IMAGE mime types and extensions when [image] is provided', () => {
18+
const expected = [...SUPPORTED_MIMES.IMAGE, ...SUPPORTED_FILE_EXTENSIONS.IMAGE].join();
19+
expect(getMimeTypesUIKitAccepts(['image'])).toBe(expected);
20+
});
21+
22+
it('should return VIDEO mime types and extensions when [video] is provided', () => {
23+
const expected = [...SUPPORTED_MIMES.VIDEO, ...SUPPORTED_FILE_EXTENSIONS.VIDEO].join();
24+
expect(getMimeTypesUIKitAccepts(['video'])).toBe(expected);
25+
});
26+
27+
it('should return AUDIO mime types and extensions when [audio] is provided', () => {
28+
const expected = [...SUPPORTED_MIMES.AUDIO, ...SUPPORTED_FILE_EXTENSIONS.AUDIO].join();
29+
expect(getMimeTypesUIKitAccepts(['audio'])).toBe(expected);
30+
});
31+
32+
it('should return ARCHIVE mime types and extensions when [archive] is provided', () => {
33+
const expected = [...SUPPORTED_MIMES.ARCHIVE, ...SUPPORTED_FILE_EXTENSIONS.ARCHIVE].join();
34+
expect(getMimeTypesUIKitAccepts(['archive'])).toBe(expected);
35+
});
36+
37+
it('should not include archive types when not specified', () => {
38+
const result = getMimeTypesUIKitAccepts(['image', 'video']);
39+
expect(result).not.toContain('application/zip');
40+
expect(result).not.toContain('.7z');
41+
});
42+
43+
it('should return combined IMAGE and VIDEO mime types and extensions when [image, video] is provided', () => {
44+
const expected = [
45+
...SUPPORTED_MIMES.IMAGE,
46+
...SUPPORTED_FILE_EXTENSIONS.IMAGE,
47+
...SUPPORTED_MIMES.VIDEO,
48+
...SUPPORTED_FILE_EXTENSIONS.VIDEO,
49+
].join();
50+
expect(getMimeTypesUIKitAccepts(['image', 'video'])).toBe(expected);
51+
});
52+
53+
it('should return exact mime types or extensions when specific ones are provided', () => {
54+
const input = ['image/png', '.pdf', 'audio/mp3'];
55+
expect(getMimeTypesUIKitAccepts(input)).toBe(input.join(','));
56+
});
57+
58+
it('should handle a mix of category names, specific mime types, and file extensions', () => {
59+
const input = ['image', 'application/pdf', '.txt'];
60+
const expected = [
61+
...SUPPORTED_MIMES.IMAGE,
62+
...SUPPORTED_FILE_EXTENSIONS.IMAGE,
63+
'application/pdf',
64+
'.txt',
65+
].join();
66+
expect(getMimeTypesUIKitAccepts(input)).toBe(expected);
67+
});
68+
69+
it('should ignore unsupported category names', () => {
70+
const input = ['image', 'video', 'unsupported'];
71+
const expected = [
72+
...SUPPORTED_MIMES.IMAGE,
73+
...SUPPORTED_FILE_EXTENSIONS.IMAGE,
74+
...SUPPORTED_MIMES.VIDEO,
75+
...SUPPORTED_FILE_EXTENSIONS.VIDEO,
76+
'unsupported',
77+
].join();
78+
expect(getMimeTypesUIKitAccepts(input)).toBe(expected);
79+
});
80+
81+
it('should handle duplicate inputs', () => {
82+
const input = ['image', 'image', 'video', 'image/png', '.jpg', '.jpg'];
83+
const expected = [
84+
...SUPPORTED_MIMES.IMAGE,
85+
...SUPPORTED_FILE_EXTENSIONS.IMAGE,
86+
...SUPPORTED_MIMES.VIDEO,
87+
...SUPPORTED_FILE_EXTENSIONS.VIDEO,
88+
].join();
89+
expect(getMimeTypesUIKitAccepts(input)).toBe(expected);
90+
});
91+
92+
it('should return all supported types and extensions for null input', () => {
93+
expect(getMimeTypesUIKitAccepts(null as any)).toBe(allTypesAndExtensions);
94+
});
95+
96+
it('should return all supported types and extensions for undefined input', () => {
97+
expect(getMimeTypesUIKitAccepts(undefined as any)).toBe(allTypesAndExtensions);
98+
});
99+
100+
it('should handle case-insensitive category names', () => {
101+
const result = getMimeTypesUIKitAccepts(['IMAGE', 'Video', 'AuDiO']);
102+
103+
SUPPORTED_MIMES.IMAGE.forEach(mime => expect(result).toContain(mime));
104+
SUPPORTED_FILE_EXTENSIONS.IMAGE.forEach(ext => expect(result).toContain(ext));
105+
106+
SUPPORTED_MIMES.VIDEO.forEach(mime => expect(result).toContain(mime));
107+
SUPPORTED_FILE_EXTENSIONS.VIDEO.forEach(ext => expect(result).toContain(ext));
108+
109+
SUPPORTED_MIMES.AUDIO.forEach(mime => expect(result).toContain(mime));
110+
SUPPORTED_FILE_EXTENSIONS.AUDIO.forEach(ext => expect(result).toContain(ext));
111+
112+
// assert if there are any duplicates
113+
const uniqueResult = new Set(result.split(','));
114+
expect(uniqueResult.size).toBe(result.split(',').length);
115+
116+
// assert if there are no other types
117+
expect(result).not.toContain('IMAGE');
118+
expect(result).not.toContain('Video');
119+
expect(result).not.toContain('AuDiO');
29120
});
30121
});

src/utils/index.ts

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export const SUPPORTED_MIMES = {
5959
'text/calendar',
6060
'text/javascript',
6161
'text/xml',
62+
'text/x-log',
6263
'video/quicktime', // NOTE: Assume this video is a normal file, not video
6364
],
6465
APPLICATION: [
@@ -100,37 +101,65 @@ export const SUPPORTED_MIMES = {
100101
'application/zip',
101102
'application/x-7z-compressed',
102103
],
104+
ARCHIVE: [
105+
'application/zip',
106+
'application/x-rar-compressed',
107+
'application/x-7z-compressed',
108+
'application/x-tar',
109+
'application/gzip',
110+
'application/x-bzip',
111+
'application/x-bzip2',
112+
'application/x-xz',
113+
'application/x-iso9660-image',
114+
],
103115
};
104116

105-
export const getMimeTypesUIKitAccepts = (acceptableMimeTypes?: string[]): string => {
106-
if (Array.isArray(acceptableMimeTypes) && acceptableMimeTypes.length > 0) {
107-
return acceptableMimeTypes
117+
export const SUPPORTED_FILE_EXTENSIONS = {
118+
IMAGE: ['.apng', '.avif', '.gif', '.jpg', '.jpeg', '.jfif', '.pjpeg', '.pjp', '.png', '.svg', '.webp', '.bmp', '.ico', '.cur', '.tif', '.tiff'],
119+
VIDEO: ['.mp4', '.webm', '.ogv', '.3gp', '.3g2', '.avi', '.mov', '.wmv', '.mpg', '.mpeg', '.m4v', '.mkv'],
120+
AUDIO: ['.aac', '.midi', '.mp3', '.oga', '.opus', '.wav', '.weba', '.3gp', '.3g2'],
121+
DOCUMENT: ['.txt', '.log', '.csv', '.rtf', '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx'],
122+
ARCHIVE: ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.xz', '.iso'],
123+
};
124+
125+
export const getMimeTypesUIKitAccepts = (acceptableTypes?: string[]): string => {
126+
if (Array.isArray(acceptableTypes) && acceptableTypes.length > 0) {
127+
const uniqueTypes = acceptableTypes
108128
.reduce((prev, curr) => {
109-
switch (curr) {
129+
const lowerCurr = curr.toLowerCase();
130+
switch (lowerCurr) {
110131
case 'image': {
111-
prev.push(...SUPPORTED_MIMES.IMAGE);
132+
prev.push(...SUPPORTED_MIMES.IMAGE, ...SUPPORTED_FILE_EXTENSIONS.IMAGE);
112133
break;
113134
}
114135
case 'video': {
115-
prev.push(...SUPPORTED_MIMES.VIDEO);
136+
prev.push(...SUPPORTED_MIMES.VIDEO, ...SUPPORTED_FILE_EXTENSIONS.VIDEO);
116137
break;
117138
}
118139
case 'audio': {
119-
prev.push(...SUPPORTED_MIMES.AUDIO);
140+
prev.push(...SUPPORTED_MIMES.AUDIO, ...SUPPORTED_FILE_EXTENSIONS.AUDIO);
141+
break;
142+
}
143+
case 'archive': {
144+
prev.push(...SUPPORTED_MIMES.ARCHIVE, ...SUPPORTED_FILE_EXTENSIONS.ARCHIVE);
120145
break;
121146
}
122147
default: {
123148
prev.push(curr);
124149
break;
125150
}
126151
}
127-
128152
return prev;
129-
}, [] as string[])
130-
.join();
153+
}, [] as string[]);
154+
155+
// To remove duplicates
156+
return Array.from(new Set(uniqueTypes)).join(',');
131157
}
132158

133-
return Object.values(SUPPORTED_MIMES).reduce((prev, curr) => (prev.concat(curr)), []).join();
159+
return [
160+
...Object.values(SUPPORTED_MIMES).flat(),
161+
...Object.values(SUPPORTED_FILE_EXTENSIONS).flat(),
162+
].join(',');
134163
};
135164

136165
/* eslint-disable no-redeclare */

0 commit comments

Comments
 (0)