126 lines
3.8 KiB
TypeScript
126 lines
3.8 KiB
TypeScript
import { Box, Button, CircularProgress, LinearProgress, TextField } from '@mui/material';
|
|
import { useForm } from '@tanstack/react-form';
|
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import { FC, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import Api from '../../../api/Api';
|
|
import { PostUpdate } from '../../../types/Post';
|
|
import ErrorComponent from '../../Error/ErrorComponent';
|
|
|
|
const PostForm: FC = () => {
|
|
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const [error, setError] = useState<any>();
|
|
const [characterCount, setCharacterCount] = useState(0);
|
|
|
|
const { t } = useTranslation();
|
|
const queryClient = useQueryClient();
|
|
|
|
const newMutation = useMutation({
|
|
mutationFn: ({ data }: { data: PostUpdate }) => {
|
|
return Api.newPost(data);
|
|
},
|
|
});
|
|
|
|
const form = useForm<PostUpdate>({
|
|
defaultValues: {
|
|
content: '',
|
|
},
|
|
onSubmit: async ({ value }) => {
|
|
try {
|
|
newMutation.mutate(
|
|
{ data: value },
|
|
{
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['posts'] });
|
|
},
|
|
onError: setError,
|
|
}
|
|
);
|
|
|
|
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} catch (error: any) {
|
|
setError(error);
|
|
}
|
|
},
|
|
});
|
|
|
|
return (
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
form.handleSubmit();
|
|
}}
|
|
onKeyDown={(event) => {
|
|
if (event.key === 'Tab') {
|
|
event.stopPropagation();
|
|
}
|
|
}}
|
|
noValidate
|
|
>
|
|
<Box sx={{ display: 'grid', gap: 2, padding: 1 }}>
|
|
<form.Field
|
|
name="content"
|
|
validators={{
|
|
onChange: ({ value }) => (!value ? t('Content required') : undefined),
|
|
onChangeAsyncDebounceMs: 250,
|
|
onChangeAsync: async ({ value }) => {
|
|
return !value && t('Content required');
|
|
},
|
|
}}
|
|
children={(field) => {
|
|
return (
|
|
<>
|
|
<TextField
|
|
variant="outlined"
|
|
multiline
|
|
minRows={3}
|
|
name={field.name}
|
|
value={field.state.value}
|
|
onBlur={field.handleBlur}
|
|
onChange={(e) => {
|
|
if (e.target.value.length <= 250) {
|
|
setCharacterCount(e.target.value.length);
|
|
field.handleChange(e.target.value);
|
|
}
|
|
}}
|
|
size="small"
|
|
label={t('Comment')}
|
|
required
|
|
error={field.state.meta.isTouched && field.state.meta.errors.length > 0}
|
|
helperText={field.state.meta.isTouched ? field.state.meta.errors.join(',') : ''}
|
|
autoComplete="off"
|
|
fullWidth
|
|
/>
|
|
<LinearProgress
|
|
variant="determinate"
|
|
value={(characterCount / 250) * 100}
|
|
color={characterCount === 250 ? 'error' : characterCount >= 200 ? 'warning' : 'primary'}
|
|
/>
|
|
</>
|
|
);
|
|
}}
|
|
/>
|
|
<form.Subscribe
|
|
selector={(state) => [state.canSubmit, state.isSubmitting]}
|
|
children={([canSubmit]) => (
|
|
<>
|
|
<Button
|
|
type="submit"
|
|
disabled={!canSubmit || newMutation.isPending}
|
|
variant="contained"
|
|
endIcon={newMutation.isPending && <CircularProgress color="inherit" size="20px" />}
|
|
>
|
|
{t('Post comment')}
|
|
</Button>
|
|
</>
|
|
)}
|
|
/>
|
|
{error && <ErrorComponent error={error} context="newPost" />}
|
|
</Box>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
export default PostForm;
|