1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-05-03 16:46:41 +07:00

removed upload redux store

This commit is contained in:
Fedor Katurov 2022-01-06 21:04:14 +07:00
parent 140e36b6b7
commit 95b92b643f
38 changed files with 398 additions and 691 deletions
src/containers
dialogs/EditorDialog
profile/ProfileAvatar

View file

@ -6,8 +6,7 @@ import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
import { prop } from 'ramda';
import { useNodeFormFormik } from '~/hooks/node/useNodeFormFormik';
import { EditorButtons } from '~/components/editors/EditorButtons';
import { FileUploaderProvider, useFileUploader } from '~/hooks/data/useFileUploader';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS } from '~/redux/uploads/constants';
import { UploadSubject, UploadTarget } from '~/constants/uploads';
import { FormikProvider } from 'formik';
import { INode } from '~/redux/types';
import { ModalWrapper } from '~/components/dialogs/ModalWrapper';
@ -15,16 +14,19 @@ import { useTranslatedError } from '~/hooks/data/useTranslatedError';
import { useCloseOnEscape } from '~/hooks';
import { EditorConfirmClose } from '~/components/editors/EditorConfirmClose';
import { IDialogProps } from '~/types/modal';
import { useUploader } from '~/hooks/data/useUploader';
import { UploaderContextProvider } from '~/utils/context/UploaderContextProvider';
import { observer } from 'mobx-react-lite';
interface Props extends IDialogProps {
node: INode;
onSubmit: (node: INode) => Promise<unknown>;
}
const EditorDialog: FC<Props> = ({ node, onRequestClose, onSubmit }) => {
const EditorDialog: FC<Props> = observer(({ node, onRequestClose, onSubmit }) => {
const [isConfirmModalShown, setConfirmModalShown] = useState(false);
const uploader = useFileUploader(UPLOAD_SUBJECTS.EDITOR, UPLOAD_TARGETS.NODES, node.files);
const uploader = useUploader(UploadSubject.Editor, UploadTarget.Nodes, node.files);
const formik = useNodeFormFormik(node, uploader, onRequestClose, onSubmit);
const { values, handleSubmit, dirty, status } = formik;
@ -58,7 +60,7 @@ const EditorDialog: FC<Props> = ({ node, onRequestClose, onSubmit }) => {
return (
<ModalWrapper onOverlayClick={onClose}>
<FileUploaderProvider value={uploader}>
<UploaderContextProvider value={uploader}>
<FormikProvider value={formik}>
<form onSubmit={handleSubmit} className={styles.form}>
<BetterScrollDialog
@ -78,9 +80,9 @@ const EditorDialog: FC<Props> = ({ node, onRequestClose, onSubmit }) => {
</BetterScrollDialog>
</form>
</FormikProvider>
</FileUploaderProvider>
</UploaderContextProvider>
</ModalWrapper>
);
};
});
export { EditorDialog };

View file

@ -1,104 +1,75 @@
import React, { FC, useCallback, useEffect, useState } from 'react';
import React, { ChangeEvent, FC, useCallback } from 'react';
import styles from './styles.module.scss';
import { connect } from 'react-redux';
import { getURL } from '~/utils/dom';
import { path, pick } from 'ramda';
import { pick } from 'ramda';
import { selectAuthProfile, selectAuthUser } from '~/redux/auth/selectors';
import { PRESETS } from '~/constants/urls';
import { selectUploads } from '~/redux/uploads/selectors';
import { IFileWithUUID } from '~/redux/types';
import uuid from 'uuid4';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS, UPLOAD_TYPES } from '~/redux/uploads/constants';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { UploadSubject, UploadTarget } from '~/constants/uploads';
import * as AUTH_ACTIONS from '~/redux/auth/actions';
import { Icon } from '~/components/input/Icon';
import { useUploader } from '~/hooks/data/useUploader';
import { observer } from 'mobx-react-lite';
import { showErrorToast } from '~/utils/errors/showToast';
const mapStateToProps = state => ({
user: pick(['id'], selectAuthUser(state)),
profile: pick(['is_loading', 'user'], selectAuthProfile(state)),
uploads: pick(['statuses', 'files'], selectUploads(state)),
});
const mapDispatchToProps = {
uploadUploadFiles: UPLOAD_ACTIONS.uploadUploadFiles,
authPatchUser: AUTH_ACTIONS.authPatchUser,
};
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const ProfileAvatarUnconnected: FC<IProps> = ({
user: { id },
profile: { is_loading, user },
uploads: { statuses, files },
uploadUploadFiles,
authPatchUser,
}) => {
const can_edit = !is_loading && id && id === user?.id;
const ProfileAvatarUnconnected: FC<IProps> = observer(
({ user: { id }, profile: { is_loading, user }, authPatchUser }) => {
const uploader = useUploader(
UploadSubject.Avatar,
UploadTarget.Profiles,
user?.photo ? [] : []
);
const [temp, setTemp] = useState<string>('');
const onInputChange = useCallback(
async (event: ChangeEvent<HTMLInputElement>) => {
try {
if (!event.target.files?.length) {
return;
}
useEffect(() => {
if (!can_edit) return;
const photo = await uploader.uploadFile(event.target.files[0]);
authPatchUser({ photo });
} catch (error) {
showErrorToast(error);
}
},
[uploader, authPatchUser]
);
Object.entries(statuses).forEach(([id, status]) => {
if (temp === id && !!status.uuid && files[status.uuid]) {
authPatchUser({ photo: files[status.uuid] });
setTemp('');
}
});
}, [statuses, files, temp, can_edit, authPatchUser]);
const can_edit = !is_loading && id && id === user?.id;
const onUpload = useCallback(
(uploads: File[]) => {
const items: IFileWithUUID[] = Array.from(uploads).map(
(file: File): IFileWithUUID => ({
file,
temp_id: uuid(),
subject: UPLOAD_SUBJECTS.AVATAR,
target: UPLOAD_TARGETS.PROFILES,
type: UPLOAD_TYPES.IMAGE,
})
);
const backgroundImage = is_loading
? undefined
: `url("${user && getURL(user.photo, PRESETS.avatar)}")`;
setTemp(path([0, 'temp_id'], items) || '');
uploadUploadFiles(items.slice(0, 1));
},
[uploadUploadFiles, setTemp]
);
const onInputChange = useCallback(
event => {
if (!can_edit) return;
event.preventDefault();
if (!event.target.files || !event.target.files.length) return;
onUpload(Array.from(event.target.files));
},
[onUpload, can_edit]
);
const backgroundImage = is_loading
? undefined
: `url("${user && getURL(user.photo, PRESETS.avatar)}")`;
return (
<div
className={styles.avatar}
style={{
backgroundImage,
}}
>
{can_edit && <input type="file" onInput={onInputChange} />}
{can_edit && (
<div className={styles.can_edit}>
<Icon icon="photo_add" />
</div>
)}
</div>
);
};
return (
<div
className={styles.avatar}
style={{
backgroundImage,
}}
>
{can_edit && <input type="file" onInput={onInputChange} />}
{can_edit && (
<div className={styles.can_edit}>
<Icon icon="photo_add" />
</div>
)}
</div>
);
}
);
const ProfileAvatar = connect(mapStateToProps, mapDispatchToProps)(ProfileAvatarUnconnected);