I have two components. One is parent that has simple form with description and titke, etc. Another one is a modal that updates a picture. Now everytime I update a picture, the unsaved data from form(parent component) disappears. It seems the page reloads. How can I avoid that?
CourseInformation.tsx
import React, { useEffect, useState } from 'react';
import {
Alert,
Button,
DialogActions,
DialogContent,
FormControl,
InputLabel,
TextField,
Card,
CardContent, CardMedia, MenuItem, Snackbar,
} from '@mui/material';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import Box from '@mui/material/Box';
import EditIcon from '@mui/icons-material/Edit';
import Headline from '@/Components/Ui/Headline';
import { Course, User } from '@/types';
import { __ } from 'matice';
import CourseDetailsHeader from '@/Pages/Courses/Partials/CourseDetailsHeader';
import CourseDetailsAside from '@/Pages/Courses/Partials/CourseDetailsAside';
import Select from '@mui/material/Select';
import { useInertiaForm } from 'use-inertia-form';
import route from '../../../../vendor/tightenco/ziggy';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import avatarPlaceholder from '../../../images/auth-bg.jpg';
import CourseInformationImageModal from '@/Pages/Courses/CourseInformationImageModal';
import RichTextEditor from '@/Components/Ui/RichTextEditor';
interface CourseInformationProps {
course: Course;
clientId: number;
authors: User[];
}
export default function CourseInformation({ course, clientId, authors }: CourseInformationProps) {
const [courseFormModalOpen, setCourseFormModalOpen] = useState(false);
const form = useInertiaForm({
course: {
title: '',
short_description: '',
description: '',
course_goal: '',
client_id: clientId,
author_id: '',
},
});
useEffect(() => {
if (course) {
form.setData('course.title', course.title);
form.setData('course.short_description', course.short_description);
form.setData('course.description', course.description);
form.setData('course.course_goal', course.course_goal);
form.setData('course.author_id', course.author_id);
}
}, [course]);
const updateCourseInfo = (e: React.FormEvent) => {
e.preventDefault();
form.patch(route('courses.update', course.id), {
onSuccess: () => {
},
onError: (errors) => {
console.log(errors);
},
});
};
function openImageForm(course: Course | null = null) {
setCourseFormModalOpen(true);
}
function closeImageForm() {
setCourseFormModalOpen(false);
}
return (
<>
<Snackbar
open={form.recentlySuccessful}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Alert
severity="success"
variant="filled"
sx={{ width: '100%' }}
icon={<FontAwesomeIcon icon={['fas', 'check']} fontSize={'inherit'} />}
>
Course information successfully updated
</Alert>
</Snackbar>
<Box>
{courseFormModalOpen && (<CourseInformationImageModal course={{...course}} open={openImageForm} closeModal={closeImageForm} />
)}
<CourseDetailsHeader course={course} />
<Grid container spacing={4} sx={{ mt: 2.5 }}>
<Grid xs={12} xl={8}>
<Headline
variant="h2"
title={__('courses.information')}
sx={{ mb: 2.5 }}
/>
<form onSubmit={updateCourseInfo}>
<Card>
<CardContent>
<DialogContent>
<Grid container >
<Grid container>
<Grid xs={12} md={12}>
<Box>
<Grid container spacing={2}>
<Grid
xs={12}
sm={3}
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
position: 'relative',
}}
>
<CardMedia
component="img"
image={course.thumbnail_url ?? avatarPlaceholder}
sx={{
width: '100%',
height: '100%',
borderRadius: '5px',
}}
/>
<Button
onClick={(event) => {
event.preventDefault();
openImageForm(course);
}}
component="label"
role={undefined}
variant="contained"
tabIndex={-1}
size="xs"
sx={{
position: 'absolute',
top: '12px',
right: '12px',
backgroundColor: 'black',
borderRadius: '4px',
}}
>
<EditIcon sx={{ fontSize: 16 }} />
</Button>
</Grid>
<Grid xs={12} sm={9} sx={{ display: 'flex', flexDirection: 'column', mt: '20px' }}>
<TextField
fullWidth
id='courseTitle'
size="small"
sx={{ mb: 2 }}
type="text"
label={__('courses.title')}
value={form.data.course.title}
onChange={e => form.setData('course.title', e.currentTarget.value)}
error={!!form.getError('course.title')}
helperText={form.getError('course.title')}
/>
<TextField
fullWidth
size="small"
sx={{ mb: 2 }}
type="text"
label={__('courses.short_description')}
value={form.data.course.short_description}
onChange={e => form.setData('course.short_description', e.currentTarget.value)}
error={!!form.getError('course.short_description')}
helperText={form.getError('course.short_description')}
InputLabelProps={{ shrink: !!form.data.course.short_description }}
/>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
</Grid>
</DialogContent>
</CardContent>
</Card>
<Card sx={{ mt: 2.5 }}>
<CardContent>
<Box>
<Typography
fontWeight={700}
fontFamily={'Assistant'}
fontSize={'20px'}
sx={{ whiteSpace: 'nowrap' }}
>
{__('courses.author')} / {__('courses.course_instructor')}
</Typography>
<FormControl fullWidth sx={{ mt: '20px' }}>
<InputLabel id="demo-simple-select-label">{__('courses.select_member')}</InputLabel>
<TextField
select
id="demo-simple-select"
label={__('courses.select_member')}
onChange={e => form.setData('course.author_id', e.target.value)}
value={form.data.course.author_id}
error={!!form.getError('course.author_id')}
helperText={form.getError('course.author_id')}
fullWidth
>
{authors.map(author => (
<MenuItem key={author.id} value={author.id}>{author.first_name}</MenuItem>
))
}
</TextField>
</FormControl>
</Box>
</CardContent>
</Card>
<Card sx={{ mt: 2.5 }}>
<CardContent>
<Box>
<Typography
fontWeight={700}
fontFamily={'Assistant'}
fontSize={'20px'}
sx={{ whiteSpace: 'nowrap' }}
>
{__('courses.description')}
</Typography>
<RichTextEditor
value={form.data.course.description}
onChange={(value: any) => form.setData('course.description', value)}
error={!!form.getError('course.description')}
helperText={form.getError('course.description')}
/>
</Box>
</CardContent>
</Card>
<Card sx={{ mt: 2.5}}>
<CardContent>
<Box>
<Typography
fontWeight={700}
fontFamily={'Assistant'}
fontSize={'20px'}
sx={{ whiteSpace: 'nowrap' }}
>
{__('courses.course_goal')}
</Typography>
<RichTextEditor
value={form.data.course.course_goal}
onChange={(value: any) => form.setData('course.course_goal', value)}
error={!!form.getError('course.course_goal')}
helperText={form.getError('course.course_goal')}
/>
</Box>
</CardContent>
<DialogActions>
<Button
variant="contained"
color="secondary"
disabled={form.processing}
type="submit"
>
{__('default.save')}
</Button>
</DialogActions>
</Card>
</form>
</Grid>
<CourseDetailsAside course={course} />
</Grid>
</Box>
</>
);
};
CourseInformationImageModal.tsx
import Dialog from '@mui/material/Dialog';
import { Alert, Button, CardMedia, DialogActions, DialogContent, DialogTitle, Snackbar, Stack } from '@mui/material';
import { __ } from 'matice';
import Typography from '@mui/material/Typography';
import React from 'react';
import Box from '@mui/material/Box';
import UploadFileIcon from '@mui/icons-material/UploadFile';
import { useDropzone } from 'react-dropzone';
import { useInertiaForm } from 'use-inertia-form';
import { Course } from '@/types';
import route from '../../../../vendor/tightenco/ziggy';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
type ImageFormProps = {
course: Course
open: any;
closeModal: () => void;
}
export default function CourseInformationImageModal({ course, open, closeModal}: ImageFormProps){
const [previewUrl, setPreviewUrl] = React.useState<string | null>(course?.thumbnail_url || null);
const [showSuccessSnackbar, setShowSuccessSnackbar] = React.useState(false);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
accept: { 'image/*': [] },
onDrop: (acceptedFiles) => {
form_thumbnail.setData('course.thumbnail', acceptedFiles[0]);
setPreviewUrl(URL.createObjectURL(acceptedFiles[0]));
},
});
const form_thumbnail = useInertiaForm({
_method:'PUT',
course: {
thumbnail: null as File | null,
},
});
function onSubmit(e: React.FormEvent) {
e.preventDefault();
form_thumbnail.post(route('courses.updateImage', { course: course.id }), {
onSuccess: () => {
setShowSuccessSnackbar(true);
closeModal();
},
onError: (errors) => {
form_thumbnail.setError(errors);
},
});
}
return (
<>
<Snackbar
open={showSuccessSnackbar}
autoHideDuration={6000}
onClose={() => setShowSuccessSnackbar(false)}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
<Alert
severity="success"
variant="filled"
sx={{ width: '100%' }}
icon={<FontAwesomeIcon icon={['fas', 'check']} fontSize={'inherit'} />}
>
Course image updated successfully!
</Alert>
</Snackbar>
<Dialog open={open} onClose={closeModal} fullWidth={true} maxWidth={'xs'}>
<form onSubmit={onSubmit}>
<DialogTitle>
<Typography
fontWeight={700}
fontFamily={'Assistant'}
fontSize={'20px'}
>
{__('courses.edit_course_image')}
</Typography>
</DialogTitle>
<DialogContent>
<Box {...getRootProps()}
sx={{
mt: 3,
height: 200,
border: '1px dashed var(--divider, rgba(0, 0, 0, 0.12))',
borderRadius: '4px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<input {...getInputProps()} />
{
isDragActive ?
<Typography>{__('courses.drop_here')}</Typography> :
<>
<Box
sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
<Stack sx={{ mb: 2 }}>
{
previewUrl ? (
<CardMedia
component='img'
image={previewUrl}
alt="Preview"
sx={{
maxWidth: '100%',
maxHeight: '70px',
}}
/>
) : (
<UploadFileIcon style={{ color: 'rgba(33, 150, 243, 1)', width: '30px', height: '34px' }} />
)
}
</Stack>
<Typography
sx={{
fontFamily: 'Roboto',
fontSize: '16px',
fontWeight: 400,
lineHeight: '28px',
letterSpacing: '0.15000000596046448px',
textAlign: 'left',
}}
>
{__('courses.upload_drag')}
</Typography>
<Typography
sx={{
fontFamily: 'Roboto',
fontSize: '14px',
fontWeight: 400,
lineHeight: '20.02px',
letterSpacing: '0.17000000178813934px',
textAlign: 'center',
marginBottom: '5px',
}}
>
{__('courses.type_size')}
</Typography>
</Box>
</>
}
</Box>
</DialogContent>
<DialogActions>
<Button
onClick={closeModal}
sx={{ color: 'black' }}
>
{__('courses.back')}
</Button>
<Button
variant="contained"
color="secondary"
disabled={form_thumbnail.processing}
type="submit"
>
{__('courses.save')}
</Button>
</DialogActions>
</form>
</Dialog>
</>
)
}
I tried different techniques such as using copy of the original object. I tried using onClick instead of onSubmit.