UNPKG

@scientist-softserv/webstore-component-library

Version:

A React component library intended for use with WebStore applications

157 lines (148 loc) 5.13 kB
import React, { useState, useRef } from 'react' import PropTypes from 'prop-types' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Alert, Button, CloseButton, Form, InputGroup, ListGroup, Offcanvas, Tab, Tabs, } from 'react-bootstrap' import FilesTable from '../../../components/FilesTable/FilesTable' import { allowNull, apiV2CompatibleStrings, convertToBase64 } from '../../../resources/utilityFunctions' const ViewFiles = ({ backgroundColor, files, handleClose, onSubmit }) => { const fileRef = useRef(null) const [tempFiles, setTempFiles] = useState([]) const [showSuccessAlert, setShowSuccessAlert] = useState(false) const documentTabs = [ { eventKey: 'files', title: 'Attachments', status: 'Other File', }, { eventKey: 'status-updates', title: 'Status Updates', status: 'Status Update', }, ] const handleAddFile = async (event) => { event.preventDefault() try { // "event.target.files" returns a FileList, which looks like an array but does not respond to array methods // except "length". we are using the spread syntax to set "files" to be an iterable array const fileArray = [...event.target.files] const newBase64Files = await Promise.all(convertToBase64(fileArray)) const newFiles = fileArray.map((file, index) => ({ [file.name]: newBase64Files[index] })) setTempFiles([...tempFiles, ...newFiles]) if (showSuccessAlert) { setShowSuccessAlert(false) } fileRef.current.value = '' } catch (error) { throw new Error(error) } } const handleSubmit = async (event) => { event.preventDefault() await onSubmit({ files: apiV2CompatibleStrings([...tempFiles]) }) if (tempFiles.length > 0) { setShowSuccessAlert(true) setTempFiles([]) } } const handleDeleteTempFile = (file) => { const remainingFiles = tempFiles.filter((obj) => obj !== file) setTempFiles(remainingFiles) } return ( <Offcanvas show onHide={handleClose} placement='end' scroll='true'> <Offcanvas.Header className={`d-flex border-bottom px-3 py-2 bg-${backgroundColor}-8`} closeButton> <Offcanvas.Title>Documents</Offcanvas.Title> </Offcanvas.Header> <Offcanvas.Body className='border rounded p-2 m-3'> <Form> <h6 className='mt-3'>Upload Additional Documents</h6> <InputGroup controlId='attachments' className='mb-3'> <Form.Control multiple type='file' onChange={handleAddFile} ref={fileRef} /> <Button variant='outline-primary' onClick={handleSubmit} type='submit' > <FontAwesomeIcon icon='fa-upload' /> </Button> </InputGroup> </Form> <ListGroup variant='flush'> {tempFiles.map((file) => { const fileName = Object.keys(file)[0] return ( <ListGroup.Item key={fileName} className='d-flex align-items-center'> <span>{fileName}</span> <CloseButton onClick={() => handleDeleteTempFile(file)} className='ms-auto' /> </ListGroup.Item> ) })} {showSuccessAlert && ( <Alert variant='success' onClose={() => setShowSuccessAlert(false)} dismissible> Your files have been uploaded successfully. It may take some time for them to appear below. </Alert> )} </ListGroup> <Tabs defaultActiveKey='files' id='document-tabs' justify fill> {documentTabs && documentTabs.map((tab) => { const { eventKey, title, status } = tab const filteredFiles = files.filter((f) => (status === f.status) || (status === 'Other File' && f.status === null)) return ( <Tab eventKey={eventKey} title={title} className='p-2' key={eventKey} > <FilesTable files={filteredFiles} status={status} handleDeleteFile={handleDeleteTempFile} /> </Tab> ) })} </Tabs> </Offcanvas.Body> </Offcanvas> ) } ViewFiles.propTypes = { backgroundColor: PropTypes.string, files: PropTypes.arrayOf( PropTypes.shape({ contentLength: PropTypes.string.isRequired, contentType: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired, download: PropTypes.string.isRequired, fileName: PropTypes.string.isRequired, href: PropTypes.string.isRequired, status: allowNull(PropTypes.string.isRequired), uploadedBy: PropTypes.string.isRequired, uuid: PropTypes.string.isRequired, }), ).isRequired, handleClose: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired, } ViewFiles.defaultProps = { backgroundColor: 'secondary', } export default ViewFiles