Skip to content

Commit bbb4b4f

Browse files
authored
Merge pull request #162 from scientist-softserv/152-remove-add-attachments
152 Add attachments
2 parents 6ebf285 + 80d0ad2 commit bbb4b4f

File tree

5 files changed

+104
-17
lines changed

5 files changed

+104
-17
lines changed

src/assets/fontawesome.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'
22
import {
33
faArrowDown,
44
faArrowUp,
5+
faDownload,
56
faEnvelope,
67
faFileLines,
78
faListCheck,
@@ -19,6 +20,7 @@ import {
1920
library.add(
2021
faArrowDown,
2122
faArrowUp,
23+
faDownload,
2224
faEnvelope,
2325
faFileLines,
2426
faListCheck,

src/components/FilesTable/FilesTable.jsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import React from 'react'
22
import PropTypes from 'prop-types'
3-
import {
4-
// Button,
5-
Table,
6-
} from 'react-bootstrap'
3+
import { Table } from 'react-bootstrap'
4+
import Link from '../Link/Link'
75
import { allowNull } from '../../resources/utilityFunctions'
86

97
const FilesTable = ({ addClass, files }) => {
@@ -21,17 +19,25 @@ const FilesTable = ({ addClass, files }) => {
2119
<th>Uploaded By</th>
2220
<th>Size</th>
2321
<th>Created At</th>
22+
<th aria-label='actions' />
2423
</tr>
2524
</thead>
2625
<tbody>
2726
{files.map((file) => {
28-
const { uuid, fileName, uploadedBy, contentLength, createdAt } = file
27+
const { contentLength, createdAt, fileName, href, uploadedBy, uuid } = file
2928
return (
3029
<tr key={uuid} className='small'>
3130
<td>{fileName}</td>
3231
<td>{uploadedBy}</td>
3332
<td>{contentLength}</td>
3433
<td>{createdAt}</td>
34+
<td className='text-center'>
35+
<Link
36+
icon='fa-download'
37+
href={href}
38+
aria-label='download'
39+
/>
40+
</td>
3541
</tr>
3642
)
3743
})}

src/components/Link/Link.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const Link = ({ addClass, href, icon, label, style, ...props }) => (
1111
{...props}
1212
>
1313
{icon && (
14-
<FontAwesomeIcon icon={icon} className='me-2 small' />
14+
<FontAwesomeIcon icon={icon} className={`small ${label.length > 0 && 'me-2'}`} />
1515
)}
1616
{label}
1717
</a>
@@ -21,13 +21,14 @@ Link.propTypes = {
2121
addClass: PropTypes.string,
2222
href: PropTypes.string.isRequired,
2323
icon: PropTypes.string,
24-
label: PropTypes.string.isRequired,
24+
label: PropTypes.string,
2525
style: PropTypes.shape({}),
2626
}
2727

2828
Link.defaultProps = {
2929
addClass: '',
3030
icon: '',
31+
label: '',
3132
style: {},
3233
}
3334

src/compounds/ActionsGroup/ActionsGroup.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import ViewFiles from './actions/ViewFiles'
77
import { allowNull } from '../../resources/utilityFunctions'
88
import './actions-group.scss'
99

10-
const ActionsGroup = ({ backgroundColor, handleSendingMessagesOrFiles, initialFiles }) => {
10+
const ActionsGroup = ({ backgroundColor, handleSendingMessagesOrFiles, files }) => {
1111
const [show, setShow] = useState(false)
1212
const [action, setAction] = useState(null)
1313

@@ -55,7 +55,7 @@ const ActionsGroup = ({ backgroundColor, handleSendingMessagesOrFiles, initialFi
5555
<ViewFiles
5656
backgroundColor={backgroundColor}
5757
handleClose={handleClose}
58-
initialFiles={initialFiles}
58+
files={files}
5959
onSubmit={handleSendingMessagesOrFiles}
6060
/>
6161
)}
@@ -66,7 +66,7 @@ const ActionsGroup = ({ backgroundColor, handleSendingMessagesOrFiles, initialFi
6666
ActionsGroup.propTypes = {
6767
backgroundColor: PropTypes.string,
6868
handleSendingMessagesOrFiles: PropTypes.func.isRequired,
69-
initialFiles: PropTypes.arrayOf(
69+
files: PropTypes.arrayOf(
7070
PropTypes.shape({
7171
contentLength: PropTypes.string.isRequired,
7272
contentType: PropTypes.string.isRequired,

src/compounds/ActionsGroup/actions/ViewFiles.jsx

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
1-
import React
2-
from 'react'
1+
import React, { useState, useRef } from 'react'
32
import PropTypes from 'prop-types'
3+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
44
import {
5+
Alert,
6+
Button,
7+
CloseButton,
8+
Form,
9+
InputGroup,
10+
ListGroup,
511
Offcanvas,
612
Tab,
713
Tabs,
814
} from 'react-bootstrap'
915
import FilesTable from '../../../components/FilesTable/FilesTable'
10-
import { allowNull } from '../../../resources/utilityFunctions'
16+
import { allowNull, apiV2CompatibleStrings, convertToBase64 } from '../../../resources/utilityFunctions'
1117

12-
const ViewFiles = ({ backgroundColor, initialFiles, handleClose }) => {
18+
const ViewFiles = ({ backgroundColor, files, handleClose, onSubmit }) => {
19+
const fileRef = useRef(null)
20+
const [tempFiles, setTempFiles] = useState([])
21+
const [showSuccessAlert, setShowSuccessAlert] = useState(false)
1322
const documentTabs = [
1423
{
1524
eventKey: 'files',
@@ -23,16 +32,83 @@ const ViewFiles = ({ backgroundColor, initialFiles, handleClose }) => {
2332
},
2433
]
2534

35+
const handleAddFile = async (event) => {
36+
event.preventDefault()
37+
try {
38+
// "event.target.files" returns a FileList, which looks like an array but does not respond to array methods
39+
// except "length". we are using the spread syntax to set "files" to be an iterable array
40+
const fileArray = [...event.target.files]
41+
const newBase64Files = await Promise.all(convertToBase64(fileArray))
42+
const newFiles = fileArray.map((file, index) => ({ [file.name]: newBase64Files[index] }))
43+
setTempFiles([...tempFiles, ...newFiles])
44+
if (showSuccessAlert) {
45+
setShowSuccessAlert(false)
46+
}
47+
fileRef.current.value = ''
48+
} catch (error) {
49+
throw new Error(error)
50+
}
51+
}
52+
53+
const handleSubmit = async (event) => {
54+
event.preventDefault()
55+
await onSubmit({ files: apiV2CompatibleStrings([...tempFiles]) })
56+
if (tempFiles.length > 0) {
57+
setShowSuccessAlert(true)
58+
setTempFiles([])
59+
}
60+
}
61+
62+
const handleDeleteTempFile = (file) => {
63+
const remainingFiles = tempFiles.filter((obj) => obj !== file)
64+
setTempFiles(remainingFiles)
65+
}
66+
2667
return (
2768
<Offcanvas show onHide={handleClose} placement='end' scroll='true'>
2869
<Offcanvas.Header className={`d-flex border-bottom px-3 py-2 bg-${backgroundColor}-8`} closeButton>
2970
<Offcanvas.Title>Documents</Offcanvas.Title>
3071
</Offcanvas.Header>
3172
<Offcanvas.Body className='border rounded p-2 m-3'>
73+
<Form>
74+
<h6 className='mt-3'>Upload Additional Documents</h6>
75+
<InputGroup controlId='attachments' className='mb-3'>
76+
<Form.Control
77+
multiple
78+
type='file'
79+
onChange={handleAddFile}
80+
ref={fileRef}
81+
/>
82+
<Button
83+
variant='outline-primary'
84+
onClick={handleSubmit}
85+
type='submit'
86+
>
87+
<FontAwesomeIcon icon='fa-upload' />
88+
</Button>
89+
</InputGroup>
90+
</Form>
91+
<ListGroup variant='flush'>
92+
{tempFiles.map((file) => {
93+
const fileName = Object.keys(file)[0]
94+
return (
95+
<ListGroup.Item key={fileName} className='d-flex align-items-center'>
96+
<span>{fileName}</span>
97+
<CloseButton onClick={() => handleDeleteTempFile(file)} className='ms-auto' />
98+
</ListGroup.Item>
99+
)
100+
})}
101+
{showSuccessAlert
102+
&& (
103+
<Alert variant='success' onClose={() => setShowSuccessAlert(false)} dismissible>
104+
Your files have been uploaded successfully. It may take some time for them to appear below.
105+
</Alert>
106+
)}
107+
</ListGroup>
32108
<Tabs defaultActiveKey='files' id='document-tabs' justify fill>
33109
{documentTabs && documentTabs.map((tab) => {
34110
const { eventKey, title, status } = tab
35-
const filteredFiles = initialFiles.filter((f) => (status === f.status) || (status === 'Other File' && f.status === null))
111+
const filteredFiles = files.filter((f) => (status === f.status) || (status === 'Other File' && f.status === null))
36112
return (
37113
<Tab
38114
eventKey={eventKey}
@@ -43,6 +119,7 @@ const ViewFiles = ({ backgroundColor, initialFiles, handleClose }) => {
43119
<FilesTable
44120
files={filteredFiles}
45121
status={status}
122+
handleDeleteFile={handleDeleteTempFile}
46123
/>
47124
</Tab>
48125
)
@@ -55,7 +132,7 @@ const ViewFiles = ({ backgroundColor, initialFiles, handleClose }) => {
55132

56133
ViewFiles.propTypes = {
57134
backgroundColor: PropTypes.string,
58-
initialFiles: PropTypes.arrayOf(
135+
files: PropTypes.arrayOf(
59136
PropTypes.shape({
60137
contentLength: PropTypes.string.isRequired,
61138
contentType: PropTypes.string.isRequired,
@@ -69,10 +146,11 @@ ViewFiles.propTypes = {
69146
}),
70147
).isRequired,
71148
handleClose: PropTypes.func.isRequired,
149+
onSubmit: PropTypes.func.isRequired,
72150
}
73151

74152
ViewFiles.defaultProps = {
75-
backgroundColor: 'secondary'
153+
backgroundColor: 'secondary',
76154
}
77155

78156
export default ViewFiles

0 commit comments

Comments
 (0)