I am having a strange problem in my application. The desired behavior I am trying to achieve is submitting a form in the browser (I am using react-hook-form), in the submitted form will be some data and there is an option to add files, after submitting the form to the server I am getting a response which contains PDF file. Till now everything was good and I had multiple forms working perfectly (in those forms I still didn't added the option to add files). However, I tried to add react-dropzone to my app for the file upload. Now there might be a few different scenarios:
Few notes about the error:
Here is my FilesUploadStep in which I am using the dropzone, since it's only the step, I am having a parent component which I will show later ( I removed the styles from the code here, to make it shorter if there is need to add them, please tell me)
const FilesUploadStep = ({ files, handleSetFiles, stepNumber, handleRemoveFile, onSubmit }) => {
const classes = useStyles();
const { control, handleSubmit, formState: { errors } } = useForm({});
const onDropAccepted = useCallback((files) => {
handleSetFiles(files)
}, [])
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
accept: 'image/jpeg, image/png, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/pdf',
multiple: true,
onDropAccepted
});
const style = useMemo(() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {})
}), [
isDragActive,
isDragReject,
isDragAccept
]);
return (
<form id={`form-step-${stepNumber}`} onSubmit={handleSubmit(onSubmit)}>
<div className={classes.formStepContainer}>
<div className="container">
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<BackupIcon fontSize="large" />
{!isDragActive && <p>"Drag here"</p>}
{isDragAccept && <p>"Accept"</p>}
{isDragReject && <p>"Reject"</p>}
</div>
<div>
{files.length > 0 &&
<Typography variant="h6" className={classes.title}>
{t('form114.filesUpload.subtitle')}
</Typography>}
<div className={classes.demo}>
<List >
{files.map((file) =>
<ListItem key={`${file.path}`} >
<ListItemAvatar>
<Avatar>
{file.type === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" && <DescriptionIcon />}
{file.type === "application/pdf" && <DescriptionIcon />}
{file.type.startsWith('image') && <ImageIcon />}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={file.name}
/>
<ListItemSecondaryAction>
<IconButton edge="end" aria-label="delete" onClick={() => handleRemoveFile(file)}>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
)}
</List>
</div>
</div>
</div>
</div >
</form>
)}
Here is my parent component with the submit method (since it's pretty big component I tried only to include the relevant code):
const myForm = (props) => {
const classes = useStyles();
const [activeStep, setActiveStep] = useState(0);
const [formValues, setFormValues] = useState(defaultValues);
const [files, setFiles] = useState([])
const handleSetFiles = (files) => {
console.log("enter", files)
setFiles(prev => [...prev, ...files])
}
const handleRemoveFile = (file) => {
setFiles(prev => prev.filter(f => f.path !== file.path))
}
const onSubmit = (data) => {
console.log("data", data)
console.log("formValues" + JSON.stringify(formValues))
if (activeStep === 4) {
const finalData = {
...formValues.step1, ...formValues.step2, ...formValues.step3, paying_company: formValues.paying_company.id,
known_relationship: convertStringToBoolean(formValues.step3.known_relationship),
previous_payments_in_tax_year: convertStringToBoolean(formValues.step3.previous_payments_in_tax_year),
payment_date: convertDateToString(formValues.step3.payment_date),
previous_payment_date: convertDateToString(formValues.step3.previous_payment_date),
}
axios
.post(process.env.REACT_APP_DJANGO_URL + "/form114/", finalData, {
contentType: "multipart/form-data",
responseType: "blob"
}
)
.then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `Form 114 - ${formValues.paying_company.id}.pdf`); //or any other extension
document.body.appendChild(link);
link.click();
})
.catch((error) => console.log(error));
}
handleNext();
}
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
function getStepFormPart(step) {
switch (step) {
case 4:
return (
<FilesUploadStep stepNumber={4} onSubmit={onSubmit} files={files} handleSetFiles={handleSetFiles} handleRemoveFile={handleRemoveFile} />
);
default:
return;
}
}
return (
<div className={classes.root}>
<h2 className="title">Form</h2>
<Divider style={{
height: "2px",
backgroundColor: "#FFD400",
marginTop: "5px"
}} />
<BackToOptionsButton />
<div className={classes.stepperContainer}>
<Stepper className={classes.stepper} activeStep={activeStep} orientation="vertical">
{steps.map((label) => (
<Step key={label}>
<StepLabel classes={{ label: classes.step_label_root }}>
{label}
</StepLabel>
<StepContent>
<div className={classes.actionsContainer}>
<div>
{activeStep !== 0 &&
<Button
onClick={handleBack}
className={clsx(classes.button, classes.buttonOutlined)}
variant="outlined"
>
{t('buttons.back')}
</Button>
}
<Button
variant="contained"
color="primary"
className={classes.button}
type="submit"
form={`form-step-${activeStep}`}
>
{activeStep === steps.length - 1 ? t('buttons.finish') : t('buttons.next')}
</Button>
</div>
</div>
</StepContent>
</Step>
))}
</Stepper>
<div className={classes.formContainer}>
{getStepFormPart(activeStep)}
</div>
</div>
{
activeStep === steps.length && (
<Paper square elevation={0} className={classes.resetContainer}>
<Typography>All steps completed - you're finished</Typography>
</Paper>
)
}
</div >
)
}
This problem was only solved after I switched computer. Seems to be something in the operating system or maybe some process that didn't worked as it should have been.