diff --git a/src/assets/icons/i-upload-blue.svg b/src/assets/icons/i-upload-blue.svg new file mode 100644 index 0000000..ee4b368 --- /dev/null +++ b/src/assets/icons/i-upload-blue.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icons/Document.tsx b/src/components/Icons/Document.tsx new file mode 100644 index 0000000..b3d354e --- /dev/null +++ b/src/components/Icons/Document.tsx @@ -0,0 +1,17 @@ +import React from 'react'; + +const Document = () => ( + + + +); + +export default Document; diff --git a/src/components/UploadFiles/UploadFiles.tsx b/src/components/UploadFiles/UploadFiles.tsx new file mode 100644 index 0000000..d6988b4 --- /dev/null +++ b/src/components/UploadFiles/UploadFiles.tsx @@ -0,0 +1,85 @@ +import React, { FC } from 'react'; +import Button from '../Button/Button'; +import { IFile, IUploadFilesProps } from './interfaces/IUploadFiles'; +import DocumentIcon from '../Icons/Document'; +import { Colors, Sizes, Variants } from '../../constants/general'; +import styles from './sass/UploadFiles.module.scss'; + +const UploadFiles: FC = ({ + files = [], + title = 'Upload Files', + onChange = () => {}, + isShowUploadBtn = true, + className = '', + onDelete = () => {}, + isMultiple = false, + accept = undefined, +}) => { + const handleChange = async (event: React.ChangeEvent) => { + const { files: uploadedFiles } = event.target; + const selectedFiles = uploadedFiles as FileList; + const tempFiles = [...Array.from(selectedFiles)].map((file) => { + const reader = new FileReader(); + return new Promise((resolve) => { + reader.onload = () => { + resolve({ file, src: reader.result, name: file.name }); + }; + reader.readAsDataURL(file); + }); + }); + const res = await Promise.all(tempFiles) as IFile[]; + + onChange(isMultiple ? [...files, ...res] : res[0], event); + }; + + const handleRemove = (removeIndex: number) => { + if (isMultiple) { + const tempFiles = [...files]; + + tempFiles.splice(removeIndex, 1); + onDelete(tempFiles); + } else { + onDelete(null); + } + }; + + return ( +
+ {files?.length > 0 && files[0] && ( +
    + {files.map(({ name }, index) => ( +
  • + + {name} + +
  • + ))} +
+ )} + {isShowUploadBtn && ( + <> + + + + )} +
+ ); +}; + +export default UploadFiles; diff --git a/src/components/UploadFiles/interfaces/IUploadFiles.ts b/src/components/UploadFiles/interfaces/IUploadFiles.ts new file mode 100644 index 0000000..5f4942d --- /dev/null +++ b/src/components/UploadFiles/interfaces/IUploadFiles.ts @@ -0,0 +1,18 @@ +import React from 'react'; + +export interface IFile { + file: File, + src: string, + name: string, +} + +export interface IUploadFilesProps { + files: IFile[], + title: string, + onChange: (files: IFile[] | IFile, event: React.ChangeEvent) => void, + isShowUploadBtn: boolean, + className: string, + onDelete: (files: IFile[] | null) => void, + isMultiple: boolean, + accept: string, +} diff --git a/src/components/UploadFiles/sass/UploadFiles.module.scss b/src/components/UploadFiles/sass/UploadFiles.module.scss new file mode 100644 index 0000000..e5a97d1 --- /dev/null +++ b/src/components/UploadFiles/sass/UploadFiles.module.scss @@ -0,0 +1,57 @@ +@import '../../../sass/colors'; + +.wrapper { + display: flex; + flex-direction: column; + + input { + display: none; + } + + .file { + display: flex; + align-items: center; + + .icon { + display: inline-flex; + font-size: 22px; + color: $lightGray; + } + + .fileName { + font-size: 12px; + color: $primary; + margin: 0 16px 0 6px; + max-width: 215px; + line-break: anywhere; + } + } + + .uploadBtn { + position: relative; + cursor: pointer; + padding: 8px 12px 8px 38px; + width: max-content; + border: 1px solid $light-gray; + border-radius: 4px; + background-color: $white; + color: $primary; + font-size: 12px; + line-height: 15px; + transition: .3s; + + &:before { + position: absolute; + content: ""; + width: 16px; + height: 16px; + left: 12px; + background: url("../../../assets/icons/i-upload-blue.svg") no-repeat center; + } + + &:hover { + background-color: #E5F0FF; + border: 1px solid #E5F0FF; + } + } +} diff --git a/src/components/index.ts b/src/components/index.ts index 15ba83a..529878f 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,2 +1,3 @@ export { default as Button } from './Button/Button'; export { default as Bell } from './Bell/Bell'; +export { default as UploadFiles } from './UploadFiles/UploadFiles'; diff --git a/src/sass/colors.scss b/src/sass/colors.scss index b929c6d..b5af7f1 100644 --- a/src/sass/colors.scss +++ b/src/sass/colors.scss @@ -2,6 +2,7 @@ $white: #FFF; $red: #FF2E2E; $primary: #0072FF; $primary-hover: #2988FF; +$lightGray: #B7C1D4; $outlined-hover: #F2F8FF; $light-blue: #E5F0FF; $success: #36B37E; diff --git a/src/stories/UploadFiles.stories.tsx b/src/stories/UploadFiles.stories.tsx new file mode 100644 index 0000000..7c71a09 --- /dev/null +++ b/src/stories/UploadFiles.stories.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import UploadFiles from '../components/UploadFiles/UploadFiles'; + +export default { + title: 'Example/UploadFiles', + component: UploadFiles, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + files: [], +};