blob: a207ef566f14bacfaf343e8f436a8514ac0c132e [file] [log] [blame]
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +02001// Copyright 2021 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import React from 'react';
6import Button from '@material-ui/core/Button';
7import styles from './AttachmentUploader.css';
8
9type Props = {
10 files: Array<File>,
11 setFiles: Function,
12 setSubmitEnable: Function,
13}
14
15const isSameFile = (a: File, b: File) => {
16 // NOTE: This function could return a false positive if two files have the
17 // exact same name, lastModified time, size, and type but different
18 // content. This is extremely unlikely, however.
19 return a.name === b.name && a.lastModified === b.lastModified &&
20 a.size === b.size && a.type === b.type;
21}
22
23const getTotalSize = (files: Array<File>) => {
24 let size = 0;
25 files.forEach((f) => {
26 size += f.size;
27 });
28 return size;
29}
30
31const MAX_SIZE = 10 * 1000 * 1000;
32export default function AttachmentUploader(props: Props): React.ReactElement {
33
34 const {files, setFiles, setSubmitEnable} = props;
35 const [isOverSize, setIsOverSize] = React.useState(false);
36
37 const onSelectFile = (event: {currentTarget: any;}) => {
38 const input = event.currentTarget;
39 if (!input.files || input.files.length === 0) {
40 return;
41 }
42
43 const newFiles = [...input.files].filter((f1) => {
44 const fileExist = files.some((f2) => isSameFile(f1, f2));
45 return !fileExist;
46 })
47
48 const expendFiles = [...files].concat(newFiles);
49 const filesSize = getTotalSize(expendFiles);
50 setIsOverSize(filesSize > MAX_SIZE);
51 setSubmitEnable(filesSize <= MAX_SIZE);
52 setFiles(expendFiles);
53 }
54
55 const onRemoveFile = (index: number) => () => {
56 let remainingFiles = [...files];
57 remainingFiles.splice(index, 1);
58 const filesSize = getTotalSize(remainingFiles);
59 setIsOverSize(filesSize > MAX_SIZE);
60 setSubmitEnable(filesSize <= MAX_SIZE);
61 setFiles(remainingFiles);
62 }
63 return (
64 <>
65 <div className={styles.controls}>
66 <input className={styles.inputUpload} id="file-uploader" type="file" multiple onChange={onSelectFile}/>
67 <label className={styles.button} for="file-uploader">
68 <i className={styles.materialIcons} role="presentation">attach_file</i>Add attachments
69 </label>
70 You can include multiple attachments (Max: 10.0 MB per issue)
71 </div>
72 {files.length === 0 ? null :
73 (<ul>
74 {
75 files?.map((f, i) => (
76 <li>
77 {f.name}
78 <Button onClick={onRemoveFile(i)}> X</Button>
79 </li>
80 ))
81 }
82 </ul>)
83 }
84 {isOverSize ? <div className={styles.error}>Warning: Attachments are too big !</div> : null}
85 </>
86 );
87}