1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 04:46:40 +07:00

#34 made error handling and resetting

This commit is contained in:
Fedor Katurov 2021-02-27 18:29:05 +07:00
parent dad416e6e2
commit 29e5aef01b
6 changed files with 136 additions and 43 deletions

View file

@ -1,9 +1,10 @@
@import "~/styles/variables.scss"; @import '~/styles/variables.scss';
.wrap { .wrap {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
height: 32px; height: 32px;
flex: 1;
@media(max-width: 480px) { @media(max-width: 480px) {
display: none; display: none;

View file

@ -1,4 +1,4 @@
import React, { FC, useState } from 'react'; import React, { FC, useCallback, useState } from 'react';
import { useCommentFormFormik } from '~/utils/hooks/useCommentFormFormik'; import { useCommentFormFormik } from '~/utils/hooks/useCommentFormFormik';
import { FormikProvider } from 'formik'; import { FormikProvider } from 'formik';
import { LocalCommentFormTextarea } from '~/components/comment/LocalCommentFormTextarea'; import { LocalCommentFormTextarea } from '~/components/comment/LocalCommentFormTextarea';
@ -11,6 +11,10 @@ import { LocalCommentFormAttaches } from '~/components/comment/LocalCommentFormA
import { LoaderCircle } from '~/components/input/LoaderCircle'; import { LoaderCircle } from '~/components/input/LoaderCircle';
import { IComment, INode } from '~/redux/types'; import { IComment, INode } from '~/redux/types';
import { EMPTY_COMMENT } from '~/redux/node/constants'; import { EMPTY_COMMENT } from '~/redux/node/constants';
import { CommentFormDropzone } from '~/components/comment/CommentFormDropzone';
import styles from './styles.module.scss';
import { ERROR_LITERAL } from '~/constants/errors';
import { Group } from '~/components/containers/Group';
interface IProps { interface IProps {
comment?: IComment; comment?: IComment;
@ -20,41 +24,73 @@ interface IProps {
const LocalCommentForm: FC<IProps> = ({ comment, nodeId, onCancelEdit }) => { const LocalCommentForm: FC<IProps> = ({ comment, nodeId, onCancelEdit }) => {
const [textarea, setTextarea] = useState<HTMLTextAreaElement>(); const [textarea, setTextarea] = useState<HTMLTextAreaElement>();
const uploader = useFileUploader(UPLOAD_SUBJECTS.COMMENT, UPLOAD_TARGETS.COMMENTS); const uploader = useFileUploader(
UPLOAD_SUBJECTS.COMMENT,
UPLOAD_TARGETS.COMMENTS,
comment?.files
);
const formik = useCommentFormFormik(comment || EMPTY_COMMENT, nodeId, uploader, onCancelEdit); const formik = useCommentFormFormik(comment || EMPTY_COMMENT, nodeId, uploader, onCancelEdit);
const isLoading = formik.isSubmitting || uploader.isUploading; const isLoading = formik.isSubmitting || uploader.isUploading;
const isEditing = !!comment?.id; const isEditing = !!comment?.id;
const clearError = useCallback(() => {
if (formik.status) {
formik.setStatus('');
}
if (formik.errors.text) {
formik.setErrors({
...formik.errors,
text: '',
});
}
}, [formik]);
const error = formik.status || formik.errors.text;
return ( return (
<form onSubmit={formik.handleSubmit}> <CommentFormDropzone onUpload={uploader.uploadFiles}>
<FormikProvider value={formik}> <form onSubmit={formik.handleSubmit} className={styles.wrap}>
<FileUploaderProvider value={uploader}> <FormikProvider value={formik}>
<LocalCommentFormTextarea setRef={setTextarea} /> <FileUploaderProvider value={uploader}>
<div className={styles.input}>
<LocalCommentFormTextarea setRef={setTextarea} />
<CommentFormAttachButtons onUpload={uploader.uploadFiles} /> {!!error && (
<CommentFormFormatButtons element={textarea} handler={formik.handleChange('text')} /> <div className={styles.error} onClick={clearError}>
<LocalCommentFormAttaches /> {ERROR_LITERAL[error] || error}
</div>
)}
</div>
{isLoading && <LoaderCircle size={20} />} <LocalCommentFormAttaches />
{isEditing && ( <Group horizontal className={styles.buttons}>
<Button size="small" color="link" type="button" onClick={onCancelEdit}> <CommentFormAttachButtons onUpload={uploader.uploadFiles} />
Отмена <CommentFormFormatButtons element={textarea} handler={formik.handleChange('text')} />
</Button>
)}
<Button {isLoading && <LoaderCircle size={20} />}
type="submit"
size="small" {isEditing && (
color="gray" <Button size="small" color="link" type="button" onClick={onCancelEdit}>
iconRight={!isEditing ? 'enter' : 'check'} Отмена
disabled={isLoading} </Button>
> )}
{!isEditing ? 'Сказать' : 'Сохранить'}
</Button> <Button
</FileUploaderProvider> type="submit"
</FormikProvider> size="small"
</form> color="gray"
iconRight={!isEditing ? 'enter' : 'check'}
disabled={isLoading}
>
{!isEditing ? 'Сказать' : 'Сохранить'}
</Button>
</Group>
</FileUploaderProvider>
</FormikProvider>
</form>
</CommentFormDropzone>
); );
}; };

View file

@ -0,0 +1,57 @@
@import "src/styles/variables";
.wrap {
display: flex;
flex-direction: column;
textarea {
min-height: 62px !important;
}
}
.input {
@include outer_shadow();
position: relative;
flex: 1;
padding: ($gap / 2) ($gap / 2 + 1px);
}
.buttons {
@include outer_shadow();
position: relative;
z-index: 1;
display: flex;
flex-direction: row;
background: transparentize(black, 0.8);
padding: $gap / 2;
border-radius: 0 0 $radius $radius;
flex-wrap: wrap;
}
.uploads {
padding: ($gap / 2);
display: grid;
grid-column-gap: $gap / 2;
grid-row-gap: $gap / 2;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
}
.attaches {
@include outer_shadow();
}
.error {
position: absolute;
bottom: 0;
left: 50%;
background: $red;
z-index: 10;
font: $font_12_regular;
box-sizing: border-box;
padding: 0 $gap;
border-radius: 4px 4px 0 0;
transform: translate(-50%, 0);
cursor: pointer;
}

View file

@ -178,17 +178,6 @@
fill: white; fill: white;
} }
} }
> * {
margin: 0 5px;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
}
} }
.micro { .micro {

View file

@ -10,12 +10,13 @@ import { selectUploads } from '~/redux/uploads/selectors';
export const useFileUploader = ( export const useFileUploader = (
subject: typeof UPLOAD_SUBJECTS[keyof typeof UPLOAD_SUBJECTS], subject: typeof UPLOAD_SUBJECTS[keyof typeof UPLOAD_SUBJECTS],
target: typeof UPLOAD_TARGETS[keyof typeof UPLOAD_TARGETS] target: typeof UPLOAD_TARGETS[keyof typeof UPLOAD_TARGETS],
initialFiles?: IFile[]
) => { ) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { files: uploadedFiles, statuses } = useShallowSelect(selectUploads); const { files: uploadedFiles, statuses } = useShallowSelect(selectUploads);
const [files, setFiles] = useState<IFile[]>([]); const [files, setFiles] = useState<IFile[]>(initialFiles || []);
const [pendingIDs, setPendingIDs] = useState<string[]>([]); const [pendingIDs, setPendingIDs] = useState<string[]>([]);
const uploadFiles = useCallback( const uploadFiles = useCallback(

View file

@ -1,5 +1,5 @@
import { IComment, INode } from '~/redux/types'; import { IComment, INode } from '~/redux/types';
import { useCallback, useRef } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import { FormikHelpers, useFormik, useFormikContext } from 'formik'; import { FormikHelpers, useFormik, useFormikContext } from 'formik';
import { array, object, string } from 'yup'; import { array, object, string } from 'yup';
import { FileUploader } from '~/utils/hooks/fileUploader'; import { FileUploader } from '~/utils/hooks/fileUploader';
@ -58,13 +58,22 @@ export const useCommentFormFormik = (
if (stopEditing) stopEditing(); if (stopEditing) stopEditing();
}, [uploader, stopEditing]); }, [uploader, stopEditing]);
return useFormik({ const formik = useFormik({
initialValues, initialValues,
validationSchema, validationSchema,
onSubmit, onSubmit,
initialStatus: '', initialStatus: '',
onReset, onReset,
validateOnChange: true,
}); });
useEffect(() => {
if (formik.status) {
formik.setStatus('');
}
}, [formik.values.text]);
return formik;
}; };
export const useCommentFormContext = () => useFormikContext<IComment>(); export const useCommentFormContext = () => useFormikContext<IComment>();