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

#34 made local comment form uploads

This commit is contained in:
Fedor Katurov 2021-02-27 17:51:12 +07:00
parent f45e34f330
commit 051b199d5d
14 changed files with 422 additions and 189 deletions

View file

@ -0,0 +1,77 @@
import React, { createContext, FC, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { IFile, IFileWithUUID } from '~/redux/types';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS } from '~/redux/uploads/constants';
import { getFileType } from '~/utils/uploader';
import uuid from 'uuid4';
import { useDispatch } from 'react-redux';
import { uploadUploadFiles } from '~/redux/uploads/actions';
import { useShallowSelect } from '~/utils/hooks/useShallowSelect';
import { selectUploads } from '~/redux/uploads/selectors';
export const useFileUploader = (
subject: typeof UPLOAD_SUBJECTS[keyof typeof UPLOAD_SUBJECTS],
target: typeof UPLOAD_TARGETS[keyof typeof UPLOAD_TARGETS]
) => {
const dispatch = useDispatch();
const { files: uploadedFiles, statuses } = useShallowSelect(selectUploads);
const [files, setFiles] = useState<IFile[]>([]);
const [pendingIDs, setPendingIDs] = useState<string[]>([]);
const uploadFiles = useCallback(
(files: File[]) => {
const items: IFileWithUUID[] = files.map(
(file: File): IFileWithUUID => ({
file,
temp_id: uuid(),
subject,
target,
type: getFileType(file),
})
);
const temps = items.map(file => file.temp_id);
setPendingIDs([...pendingIDs, ...temps]);
dispatch(uploadUploadFiles(items));
},
[pendingIDs, setPendingIDs, dispatch, subject, target]
);
useEffect(() => {
const added = pendingIDs
.map(temp_uuid => statuses[temp_uuid] && statuses[temp_uuid].uuid)
.map(el => !!el && uploadedFiles[el])
.filter(el => !!el && !files.some(file => file && file.id === el.id));
const newPending = pendingIDs.filter(
temp_id =>
statuses[temp_id] &&
(!statuses[temp_id].uuid || !added.some(file => file.id === statuses[temp_id].uuid))
);
if (added.length) {
setPendingIDs(newPending);
setFiles([...files, ...added]);
}
}, [statuses, files, pendingIDs, uploadedFiles]);
const pending = useMemo(() => pendingIDs.map(id => statuses[id]).filter(el => !!el), [
statuses,
pendingIDs,
]);
const isLoading = pending.length > 0;
return { uploadFiles, pending, files, setFiles, isUploading: isLoading };
};
export type FileUploader = ReturnType<typeof useFileUploader>;
const FileUploaderContext = createContext<FileUploader>(null);
export const FileUploaderProvider: FC<{ value: FileUploader; children }> = ({
value,
children,
}) => <FileUploaderContext.Provider value={value}>{children}</FileUploaderContext.Provider>;
export const useFileUploaderContext = () => useContext(FileUploaderContext);

View file

@ -1,64 +1,77 @@
import { IComment, IFile } from '~/redux/types';
import { IComment, INode } from '~/redux/types';
import { useCallback, useRef } from 'react';
import { FormikHelpers, useFormik, useFormikContext } from 'formik';
import { array, object, string } from 'yup';
export interface CommentFormValues {
text: string;
images: IFile[];
songs: IFile[];
}
import { FileUploader } from '~/utils/hooks/fileUploader';
const validationSchema = object().shape({
text: string(),
images: array(),
songs: array(),
files: array(),
});
const submitComment = async (
id: IComment['id'],
values: CommentFormValues,
callback: (e: string) => void
const submitComment = (
id: INode['id'],
values: IComment,
isBefore: boolean,
callback: (e?: string) => void
) => {
await new Promise(resolve => setTimeout(resolve, 500));
callback('wrong');
console.log('Submitting', id, values);
new Promise(resolve => setTimeout(resolve, 500)).then(() => callback());
};
export const useCommentFormFormik = (values: CommentFormValues) => {
const onSuccess = ({ resetForm, setStatus, setSubmitting }: FormikHelpers<IComment>) => (
e: string
) => {
setSubmitting(false);
if (e) {
setStatus(e);
return;
}
if (resetForm) {
resetForm();
}
};
export const useCommentFormFormik = (
values: IComment,
nodeId: INode['id'],
uploader: FileUploader,
stopEditing?: () => void,
isBefore: boolean = false
) => {
const { current: initialValues } = useRef(values);
const onSuccess = useCallback(
({ resetForm, setStatus, setSubmitting }: FormikHelpers<CommentFormValues>) => (e: string) => {
setSubmitting(false);
if (e) {
setStatus(e);
return;
}
if (resetForm) {
resetForm();
}
},
[]
);
const onSubmit = useCallback(
(values: CommentFormValues, helpers: FormikHelpers<CommentFormValues>) => {
(values: IComment, helpers: FormikHelpers<IComment>) => {
helpers.setSubmitting(true);
submitComment(0, values, onSuccess(helpers));
submitComment(
nodeId,
{
...values,
files: uploader.files,
},
isBefore,
onSuccess(helpers)
);
},
[values, onSuccess]
[isBefore, nodeId, uploader.files]
);
const formik = useFormik({
const onReset = useCallback(() => {
uploader.setFiles([]);
if (stopEditing) stopEditing();
}, [uploader, stopEditing]);
return useFormik({
initialValues,
validationSchema,
onSubmit,
initialStatus: '',
onReset,
});
return { formik };
};
export const useCommentFormContext = () => useFormikContext<CommentFormValues>();
export const useCommentFormContext = () => useFormikContext<IComment>();

View file

@ -0,0 +1,5 @@
import { shallowEqual, useSelector } from 'react-redux';
import { IState } from '~/redux/store';
export const useShallowSelect = <T extends (state: IState) => any>(selector: T): ReturnType<T> =>
useSelector(selector, shallowEqual);