Skip to content

Commit 96f79fd

Browse files
authored
Merge pull request #1726 from Northeastern-Electric-Racing/#1578-receipt-upload-button
#1578: Nicer looking upload button and multiple file selection for RR Form
2 parents 8b816a2 + a23d3d4 commit 96f79fd

2 files changed

Lines changed: 72 additions & 38 deletions

File tree

src/frontend/src/pages/FinancePage/ReimbursementRequestForm/ReimbursementFormView.tsx

Lines changed: 70 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import {
1111
TextField,
1212
Typography,
1313
Snackbar,
14-
Alert
14+
Alert,
15+
Button,
16+
useTheme
1517
} from '@mui/material';
1618
import { Box, Stack } from '@mui/system';
1719
import { Control, Controller, FieldErrors, UseFormHandleSubmit, UseFormSetValue, UseFormWatch } from 'react-hook-form';
@@ -37,6 +39,7 @@ import { routes } from '../../../utils/routes';
3739
import { wbsNumComparator } from 'shared/src/validate-wbs';
3840
import { codeAndRefundSourceName, expenseTypePipe } from '../../../utils/pipes';
3941
import NERAutocomplete from '../../../components/NERAutocomplete';
42+
import FileUploadIcon from '@mui/icons-material/FileUpload';
4043

4144
interface ReimbursementRequestFormViewProps {
4245
allVendors: Vendor[];
@@ -48,7 +51,7 @@ interface ReimbursementRequestFormViewProps {
4851
}[];
4952
control: Control<ReimbursementRequestFormInput, any>;
5053
reimbursementProducts: ReimbursementProductFormArgs[];
51-
receiptAppend: (args: ReimbursementReceiptUploadArgs) => void;
54+
receiptPrepend: (args: ReimbursementReceiptUploadArgs) => void;
5255
receiptRemove: (index: number) => void;
5356
reimbursementProductAppend: (args: ReimbursementProductFormArgs) => void;
5457
reimbursementProductRemove: (index: number) => void;
@@ -69,7 +72,7 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
6972
receiptFiles,
7073
reimbursementProducts,
7174
control,
72-
receiptAppend,
75+
receiptPrepend,
7376
receiptRemove,
7477
reimbursementProductAppend,
7578
reimbursementProductRemove,
@@ -84,6 +87,7 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
8487
}) => {
8588
const [datePickerOpen, setDatePickerOpen] = useState(false);
8689
const toast = useToast();
90+
const theme = useTheme();
8791
const products = watch(`reimbursementProducts`);
8892
const expenseTypeId = watch('expenseTypeId');
8993
const selectedExpenseType = allExpenseTypes.find((expenseType) => expenseType.expenseTypeId === expenseTypeId);
@@ -100,7 +104,6 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
100104

101105
const ReceiptFileInput = () => (
102106
<FormControl>
103-
<FormLabel>Receipts</FormLabel>
104107
<ul>
105108
{receiptFiles.map((receiptFile, index) => (
106109
<li key={index}>
@@ -126,6 +129,7 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
126129
e.stopPropagation();
127130
handleSubmit(onSubmit)(e);
128131
}}
132+
style={{ minHeight: 'calc(100vh - 161px)', display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}
129133
>
130134
{!hasSecureSettingsSet && (
131135
<Snackbar anchorOrigin={{ vertical: 'top', horizontal: 'center' }} open={true}>
@@ -140,7 +144,7 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
140144
</Snackbar>
141145
)}
142146
<Grid container spacing={2}>
143-
<Grid item container maxHeight={375} spacing={2} md={6} xs={12}>
147+
<Grid item container spacing={2} md={6} xs={12} sx={{ '&.MuiGrid-item': { height: 'fit-content' } }}>
144148
<Grid item xs={12}>
145149
<FormControl fullWidth>
146150
<FormLabel>Purchased From</FormLabel>
@@ -250,35 +254,48 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
250254
</Grid>
251255
<Grid item xs={6}>
252256
<FormControl fullWidth>
253-
<ReceiptFileInput />
254-
<input
255-
onChange={(e) => {
256-
if (e.target.files) {
257-
const file = e.target.files[0];
258-
if (file.size < 1000000) {
259-
receiptAppend({
260-
file: e.target.files[0],
261-
name: e.target.files[0].name,
262-
googleFileId: ''
257+
<FormLabel>Receipts</FormLabel>
258+
<Button
259+
variant="contained"
260+
color="success"
261+
component="label"
262+
startIcon={<FileUploadIcon />}
263+
sx={{
264+
width: 'fit-content',
265+
textTransform: 'none',
266+
mt: '9.75px'
267+
}}
268+
>
269+
Upload
270+
<input
271+
onChange={(e) => {
272+
if (e.target.files) {
273+
[...e.target.files].forEach((file) => {
274+
if (file.size < 1000000) {
275+
receiptPrepend({
276+
file: file,
277+
name: file.name,
278+
googleFileId: ''
279+
});
280+
} else {
281+
toast.error(`Error uploading ${file.name}; file must be less than 1 MB`, 5000);
282+
document.getElementById('receipt-image')!.innerHTML = '';
283+
}
263284
});
264-
} else {
265-
toast.error('File must be less than 1 MB', 5000);
266-
document.getElementById('receipt-image')!.innerHTML = '';
267285
}
268-
}
269-
}}
270-
type="file"
271-
id="receipt-image"
272-
accept="image/png, image/jpeg, .pdf"
273-
name="receiptFiles"
274-
/>
286+
}}
287+
type="file"
288+
id="receipt-image"
289+
accept="image/png, image/jpeg, .pdf"
290+
name="receiptFiles"
291+
multiple
292+
hidden
293+
/>
294+
</Button>
295+
<ReceiptFileInput />
275296
<FormHelperText error>{errors.receiptFiles?.message}</FormHelperText>
276297
</FormControl>
277298
</Grid>
278-
<Grid item xs={12}>
279-
<FormLabel>Total Cost</FormLabel>
280-
<Typography variant="h6">${calculatedTotalCost}</Typography>
281-
</Grid>
282299
</Grid>
283300
<Grid item md={6} xs={12} sx={{ '&.MuiGrid-item': { paddingTop: '4px' } }}>
284301
<FormControl fullWidth>
@@ -295,13 +312,30 @@ const ReimbursementRequestFormView: React.FC<ReimbursementRequestFormViewProps>
295312
</FormControl>
296313
</Grid>
297314
</Grid>
298-
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 2 }}>
299-
<NERFailButton variant="contained" href={previousPage} sx={{ mx: 1 }}>
300-
Cancel
301-
</NERFailButton>
302-
<NERSuccessButton variant="contained" type="submit" disabled={!hasSecureSettingsSet}>
303-
{submitText}
304-
</NERSuccessButton>
315+
<Box
316+
sx={{
317+
position: 'sticky',
318+
bottom: 0,
319+
background: theme.palette.background.default,
320+
p: 1,
321+
borderTop: `solid 1px ${theme.palette.divider}`,
322+
zIndex: 1,
323+
display: 'flex',
324+
justifyContent: 'space-between'
325+
}}
326+
>
327+
<Box>
328+
<FormLabel>Total Cost</FormLabel>
329+
<Typography variant="h6">${calculatedTotalCost}</Typography>
330+
</Box>
331+
<Box sx={{ display: 'flex', alignSelf: 'center' }}>
332+
<NERFailButton variant="contained" href={previousPage} sx={{ mx: 1 }}>
333+
Cancel
334+
</NERFailButton>
335+
<NERSuccessButton variant="contained" type="submit" disabled={!hasSecureSettingsSet}>
336+
{submitText}
337+
</NERSuccessButton>
338+
</Box>
305339
</Box>
306340
</form>
307341
);

src/frontend/src/pages/FinancePage/ReimbursementRequestForm/ReimbursementRequestForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const ReimbursementRequestForm: React.FC<ReimbursementRequestFormProps> = ({
100100

101101
const {
102102
fields: receiptFiles,
103-
append: receiptAppend,
103+
prepend: receiptPrepend,
104104
remove: receiptRemove
105105
} = useFieldArray({
106106
control,
@@ -216,7 +216,7 @@ const ReimbursementRequestForm: React.FC<ReimbursementRequestFormProps> = ({
216216
receiptFiles={receiptFiles}
217217
control={control}
218218
reimbursementProducts={reimbursementProducts}
219-
receiptAppend={receiptAppend}
219+
receiptPrepend={receiptPrepend}
220220
receiptRemove={receiptRemove}
221221
reimbursementProductAppend={reimbursementProductAppend}
222222
reimbursementProductRemove={reimbursementProductRemove}

0 commit comments

Comments
 (0)