-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* OM-316: upload init * OM-316: add downloading file with errors, overall improvements * OM-316: condition fix * OM-316: add memo for urls * OM-316: get rid of useless refetch
- Loading branch information
1 parent
1a4de3c
commit 1d82ffa
Showing
6 changed files
with
555 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,297 @@ | ||
import React, { useRef, useState } from 'react'; | ||
import { useSelector } from 'react-redux'; | ||
|
||
import { | ||
Box, | ||
Button, | ||
ButtonBase, | ||
CircularProgress, | ||
Dialog, | ||
DialogActions, | ||
DialogContent, | ||
DialogTitle, | ||
Grid, | ||
TextField, | ||
Typography, | ||
} from '@material-ui/core'; | ||
import { alpha } from '@material-ui/core/styles/colorManipulator'; | ||
import CheckCircleIcon from '@material-ui/icons/CheckCircle'; | ||
import CloudUploadIcon from '@material-ui/icons/CloudUpload'; | ||
import DescriptionIcon from '@material-ui/icons/Description'; | ||
import ErrorIcon from '@material-ui/icons/Error'; | ||
import WarningIcon from '@material-ui/icons/Warning'; | ||
import { makeStyles } from '@material-ui/styles'; | ||
|
||
import { useModulesManager, useTranslations } from '@openimis/fe-core'; | ||
import { MODULE_NAME, RIGHT_WORKER_UPLOAD, UPLOAD_STAGE } from '../constants'; | ||
import { useUploadWorkerContext } from '../context/UploadWorkerContext'; | ||
|
||
const useStyles = makeStyles((theme) => ({ | ||
primaryButton: theme.dialog.primaryButton, | ||
secondaryButton: theme.dialog.secondaryButton, | ||
errorButton: { | ||
...theme.dialog.primaryButton, | ||
backgroundColor: theme.palette.error.main, | ||
'&:hover': { | ||
backgroundColor: alpha(theme.palette.error.main, 0.5), | ||
color: theme.palette.error.main, | ||
}, | ||
}, | ||
wrapper: { | ||
width: '400px', | ||
display: 'flex', | ||
flexDirection: 'column', | ||
}, | ||
uploadBox: { | ||
width: '100%', | ||
minHeight: '140px', | ||
backgroundColor: theme.palette.background.default, | ||
border: `1px solid ${theme.palette.divider}`, | ||
borderRadius: theme.shape.borderRadius, | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
gap: theme.spacing(0.5), | ||
flexDirection: 'column', | ||
padding: theme.spacing(2), | ||
}, | ||
input: { | ||
display: 'none', | ||
}, | ||
statusBox: { | ||
padding: theme.spacing(2), | ||
border: `1px solid ${theme.palette.divider}`, | ||
borderRadius: theme.shape.borderRadius, | ||
display: 'flex', | ||
justifyContent: 'start', | ||
alignItems: 'center', | ||
gap: theme.spacing(0.5), | ||
flexDirection: 'row', | ||
marginBottom: theme.spacing(1), | ||
}, | ||
successBox: { | ||
backgroundColor: '#e0f7fa', | ||
border: '1px solid #009688', | ||
color: '#00796b', | ||
}, | ||
warningBox: { | ||
backgroundColor: '#fff3e0', | ||
border: '1px solid #ff9800', | ||
color: '#e65100', | ||
}, | ||
errorBox: { | ||
backgroundColor: '#ffebee', | ||
border: '1px solid #f44336', | ||
color: '#c62828', | ||
}, | ||
summaryTextField: { | ||
width: '100%', | ||
}, | ||
})); | ||
|
||
function UploadWorkerModal({ open, onClose }) { | ||
const classes = useStyles(); | ||
const modulesManager = useModulesManager(); | ||
const { formatMessage, formatMessageWithValues } = useTranslations(MODULE_NAME, modulesManager); | ||
const rights = useSelector((state) => state.core?.user?.i_user?.rights ?? []); | ||
const fileInputRef = useRef(null); | ||
const [fileUploadError, setFileUploadError] = useState(null); | ||
const maxSizeInMB = 10; | ||
|
||
const { | ||
file, | ||
isUploading, | ||
uploadStage, | ||
validationError, | ||
validationSuccess, | ||
validationWarning, | ||
onFileUpload, | ||
isUploaded, | ||
onWorkersUpload, | ||
uploadSummary, | ||
resetFile, | ||
workersWithError, | ||
downloadWorkersWithError, | ||
} = useUploadWorkerContext(); | ||
|
||
const isFileUploadStage = uploadStage === UPLOAD_STAGE.FILE_UPLOAD; | ||
const isWorkerUploadStage = uploadStage === UPLOAD_STAGE.WORKER_UPLOAD; | ||
const isWorkerWithErrorAvailable = Object.keys(workersWithError).length > 0; | ||
|
||
const handleFileChange = (e) => { | ||
setFileUploadError(null); | ||
|
||
const uploadedFile = e.target.files[0]; | ||
|
||
if (!uploadedFile) { | ||
setFileUploadError(formatMessage('UploadWorkerModal.fileRequired')); | ||
return; | ||
} | ||
|
||
if (uploadedFile.size > maxSizeInMB * 1024 * 1024) { | ||
setFileUploadError( | ||
formatMessageWithValues('UploadWorkerModal.fileSizeError', { | ||
fileSize: maxSizeInMB, | ||
}), | ||
); | ||
return; | ||
} | ||
|
||
onFileUpload(uploadedFile); | ||
}; | ||
|
||
const handleDeleteFile = () => { | ||
resetFile(); | ||
fileInputRef.current.value = null; | ||
}; | ||
|
||
if (!rights.includes(RIGHT_WORKER_UPLOAD)) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Dialog open={open} onClose={onClose} disableBackdropClick> | ||
<DialogTitle>{formatMessage('UploadWorkerModal.dialogTitle')}</DialogTitle> | ||
<DialogContent className={classes.wrapper}> | ||
{isFileUploadStage && ( | ||
<> | ||
<input | ||
type="file" | ||
ref={fileInputRef} | ||
className={classes.input} | ||
disabled={isUploading} | ||
onChange={handleFileChange} | ||
accept=".csv, .xlsx" | ||
/> | ||
|
||
<ButtonBase className={classes.uploadBox} onClick={() => fileInputRef.current.click()}> | ||
{isUploading && <CircularProgress />} | ||
|
||
{!isUploading && fileUploadError && ( | ||
<Box className={`${classes.statusBox} ${classes.errorBox}`}> | ||
<ErrorIcon /> | ||
<Typography variant="subtitle1">{fileUploadError}</Typography> | ||
</Box> | ||
)} | ||
|
||
{!isUploading && !fileUploadError && !isUploaded && ( | ||
<> | ||
<CloudUploadIcon fontSize="large" /> | ||
<Typography variant="subtitle1">{formatMessage('UploadWorkerModal.uploadPrompt')}</Typography> | ||
<Typography variant="caption">{formatMessage('UploadWorkerModal.uploadCaption')}</Typography> | ||
</> | ||
)} | ||
|
||
{!isUploading && !fileUploadError && isUploaded && file && ( | ||
<> | ||
<DescriptionIcon fontSize="large" /> | ||
<Typography variant="subtitle1"> | ||
{formatMessageWithValues('UploadWorkerModal.uploadSuccess', { | ||
button: <strong>{formatMessage('UploadWorkerModal.upload')}</strong>, | ||
})} | ||
</Typography> | ||
<Typography variant="caption"> | ||
{formatMessageWithValues('UploadWorkerModal.uploadSuccessCaption', { | ||
fileName: <strong>{file.name}</strong>, | ||
fileSize: <strong>{(file.size / 1024 / 1024).toFixed(2)}</strong>, | ||
})} | ||
</Typography> | ||
</> | ||
)} | ||
</ButtonBase> | ||
</> | ||
)} | ||
{isWorkerUploadStage && ( | ||
<> | ||
{!isUploading && ( | ||
<Grid item xs={12}> | ||
{validationError && ( | ||
<Box className={`${classes.statusBox} ${classes.errorBox}`}> | ||
<ErrorIcon /> | ||
<Typography variant="subtitle1">{validationError}</Typography> | ||
</Box> | ||
)} | ||
{validationSuccess && ( | ||
<Box className={`${classes.statusBox} ${classes.successBox}`}> | ||
<CheckCircleIcon /> | ||
<Typography variant="subtitle1">{validationSuccess}</Typography> | ||
</Box> | ||
)} | ||
{validationWarning && ( | ||
<Box className={`${classes.statusBox} ${classes.warningBox}`}> | ||
<WarningIcon /> | ||
<Typography variant="subtitle1">{validationWarning}</Typography> | ||
</Box> | ||
)} | ||
</Grid> | ||
)} | ||
|
||
<div className={classes.uploadBox} style={{ gap: '16px' }}> | ||
{isUploading ? ( | ||
<CircularProgress /> | ||
) : ( | ||
Object.entries(uploadSummary).map(([key, value]) => ( | ||
<TextField | ||
key={key} | ||
className={classes.summaryTextField} | ||
label={formatMessage(`UploadWorkerModal.${key}`)} | ||
value={value} | ||
disabled | ||
/> | ||
)) | ||
)} | ||
</div> | ||
</> | ||
)} | ||
</DialogContent> | ||
<DialogActions> | ||
{isFileUploadStage && ( | ||
<> | ||
<Button disabled={isUploading} onClick={onClose} className={classes.secondaryButton}> | ||
{formatMessage('UploadWorkerModal.close')} | ||
</Button> | ||
{isUploaded && !fileUploadError && file && ( | ||
<> | ||
<Button disabled={isUploading} onClick={handleDeleteFile} className={classes.errorButton}> | ||
{formatMessage('UploadWorkerModal.clearFile')} | ||
</Button> | ||
<Button disabled={isUploading} onClick={onWorkersUpload} className={classes.primaryButton}> | ||
{formatMessage('UploadWorkerModal.upload')} | ||
</Button> | ||
</> | ||
)} | ||
</> | ||
)} | ||
{isWorkerUploadStage && ( | ||
<> | ||
<Button | ||
onClick={() => { | ||
resetFile(); | ||
onClose(); | ||
}} | ||
disabled={isUploading} | ||
className={classes.secondaryButton} | ||
> | ||
{formatMessage('UploadWorkerModal.close')} | ||
</Button> | ||
{isWorkerWithErrorAvailable && ( | ||
<Button | ||
onClick={() => { | ||
downloadWorkersWithError(); | ||
resetFile(); | ||
onClose(); | ||
}} | ||
disabled={isUploading} | ||
className={classes.errorButton} | ||
> | ||
{formatMessage('UploadWorkerModal.downloadWorkersWithError')} | ||
</Button> | ||
)} | ||
</> | ||
)} | ||
</DialogActions> | ||
</Dialog> | ||
); | ||
} | ||
|
||
export default UploadWorkerModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.