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

#58 made dialogs as routes

This commit is contained in:
Fedor Katurov 2021-03-29 14:11:39 +07:00
parent d9af895558
commit 4dc8bea040
21 changed files with 230 additions and 172 deletions

View file

@ -0,0 +1,38 @@
import React, { FC, useCallback, useMemo, useRef } from 'react';
import { EMPTY_NODE, NODE_TYPES } from '~/redux/node/constants';
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
import { useHistory, useRouteMatch } from 'react-router';
import { values } from 'ramda';
import { ModalWrapper } from '~/components/dialogs/ModalWrapper';
const EditorCreateDialog: FC = () => {
const history = useHistory();
const {
params: { type },
url,
} = useRouteMatch<{ type: string }>();
const backUrl = useMemo(() => {
return url.replace(/\/create\/(.*)$/, '');
}, [url]);
const goBack = useCallback(() => {
history.replace(backUrl);
}, [backUrl, history]);
const isExist = useMemo(() => values(NODE_TYPES).some(el => el === type), [type]);
const data = useRef({ ...EMPTY_NODE, type });
if (!type || !isExist) {
return null;
}
return (
<ModalWrapper onOverlayClick={goBack}>
<EditorDialog node={data.current} onRequestClose={goBack} />
</ModalWrapper>
);
};
export { EditorCreateDialog };

View file

@ -11,22 +11,20 @@ import { EditorButtons } from '~/components/editors/EditorButtons';
import { FileUploaderProvider, useFileUploader } from '~/utils/hooks/fileUploader';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS } from '~/redux/uploads/constants';
import { FormikProvider } from 'formik';
import { useShallowSelect } from '~/utils/hooks/useShallowSelect';
import { selectNodeEditor } from '~/redux/node/selectors';
import { INode } from '~/redux/types';
interface Props extends IDialogProps {
type: string;
node: INode;
}
const EditorDialog: FC<Props> = ({ type, onRequestClose }) => {
const editor = useShallowSelect(selectNodeEditor);
const EditorDialog: FC<Props> = ({ node, onRequestClose }) => {
const uploader = useFileUploader(UPLOAD_SUBJECTS.EDITOR, UPLOAD_TARGETS.NODES, []);
const formik = useNodeFormFormik({ ...editor, type }, uploader, onRequestClose);
const formik = useNodeFormFormik(node, uploader, onRequestClose);
const { values, handleSubmit } = formik;
useCloseOnEscape(onRequestClose);
const component = useMemo(() => prop(type, NODE_EDITORS), [type]);
const component = useMemo(() => node.type && prop(node.type, NODE_EDITORS), [node.type]);
if (!component) {
return null;

View file

@ -0,0 +1,57 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { EMPTY_NODE } from '~/redux/node/constants';
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
import { useHistory, useRouteMatch } from 'react-router';
import { ModalWrapper } from '~/components/dialogs/ModalWrapper';
import { apiGetNodeWithCancel } from '~/redux/node/api';
import { LoaderCircle } from '~/components/input/LoaderCircle';
import styles from './styles.module.scss';
const EditorEditDialog: FC = () => {
const [data, setData] = useState(EMPTY_NODE);
const [isLoading, setLoading] = useState(false);
const history = useHistory();
const {
params: { id },
url,
} = useRouteMatch<{ id: string }>();
const backUrl = useMemo(() => {
return url.replace(/\/edit$/, '');
}, [url]);
const goBack = useCallback(() => {
history.replace(backUrl);
}, [backUrl, history]);
useEffect(() => {
if (!id) {
return;
}
const { request, cancel } = apiGetNodeWithCancel({ id });
setLoading(true);
request
.then(data => setData(data.node))
.then(() => setLoading(false))
.catch(console.log);
return () => cancel();
}, [id]);
return (
<ModalWrapper onOverlayClick={console.log}>
{isLoading ? (
<div className={styles.loader}>
<LoaderCircle size={64} />
</div>
) : (
<EditorDialog node={data} onRequestClose={goBack} />
)}
</ModalWrapper>
);
};
export { EditorEditDialog };

View file

@ -0,0 +1,4 @@
.loader {
fill: white;
color: white;
}

View file

@ -1,57 +1,34 @@
import React, { Attributes, FC, useCallback } from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import styles from './styles.module.scss';
import { IState } from '~/redux/store';
import * as ACTIONS from '~/redux/modal/actions';
import React, { FC, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { DIALOG_CONTENT } from '~/constants/dialogs';
import { useShallowSelect } from '~/utils/hooks/useShallowSelect';
import { selectModal } from '~/redux/modal/selectors';
import { modalSetDialog, modalSetShown, modalShowDialog } from '~/redux/modal/actions';
import { ModalWrapper } from '~/components/dialogs/ModalWrapper';
const mapStateToProps = ({ modal }: IState) => ({ ...modal });
const mapDispatchToProps = {
modalSetShown: ACTIONS.modalSetShown,
modalSetDialog: ACTIONS.modalSetDialog,
modalShowDialog: ACTIONS.modalShowDialog,
};
type IProps = {};
type IProps = typeof mapDispatchToProps & ReturnType<typeof mapStateToProps> & {};
const Modal: FC<IProps> = ({}) => {
const { is_shown, dialog } = useShallowSelect(selectModal);
const dispatch = useDispatch();
const ModalUnconnected: FC<IProps> = ({
modalSetShown,
modalSetDialog,
modalShowDialog,
is_shown,
dialog,
}) => {
const onRequestClose = useCallback(() => {
modalSetShown(false);
modalSetDialog('');
}, [modalSetShown, modalSetDialog]);
dispatch(modalSetShown(false));
dispatch(modalSetDialog(''));
}, [dispatch]);
const onDialogChange = useCallback((val: string) => dispatch(modalShowDialog(val)), [dispatch]);
if (!dialog || !DIALOG_CONTENT[dialog] || !is_shown) return null;
return ReactDOM.createPortal(
<div className={styles.fixed}>
<div className={styles.overlay} onClick={onRequestClose} />
<div className={styles.content}>
{React.createElement(DIALOG_CONTENT[dialog], {
onRequestClose,
onDialogChange: modalShowDialog,
})}
</div>
</div>,
document.body
return (
<ModalWrapper onOverlayClick={onRequestClose}>
{React.createElement(DIALOG_CONTENT[dialog], {
onRequestClose,
onDialogChange,
})}
</ModalWrapper>
);
};
const Modal = connect(mapStateToProps, mapDispatchToProps)(ModalUnconnected);
export { ModalUnconnected, Modal };
/*
<div className={styles.content_scroller}>
<div className={styles.content_padder}>
</div>
</div>
*/
export { Modal };

View file

@ -1,61 +0,0 @@
@import "src/styles/variables";
.fixed {
position: fixed;
z-index: 30;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
@keyframes appear {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.content {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
opacity: 0;
animation: appear 0.25s forwards;
}
.content_scroller {
width: 100%;
max-width: 100vw;
max-height: 100vh;
overflow: auto;
}
.content_padder {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparentize($color: #000000, $amount: 0.9);
cursor: pointer;
animation: appear 0.25s forwards;
@include can_backdrop {
backdrop-filter: blur(15px);
}
}

View file

@ -1,10 +0,0 @@
import React, { FC } from 'react';
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
import { IDialogProps } from '~/redux/types';
import { NODE_TYPES } from '~/redux/node/constants';
type IProps = IDialogProps & {};
const EditorDialogAudio: FC<IProps> = props => <EditorDialog type={NODE_TYPES.AUDIO} {...props} />;
export { EditorDialogAudio };

View file

@ -1,10 +0,0 @@
import React, { FC } from 'react';
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
import { IDialogProps } from '~/redux/types';
import { NODE_TYPES } from '~/redux/node/constants';
type IProps = IDialogProps & {};
const EditorDialogImage: FC<IProps> = props => <EditorDialog type={NODE_TYPES.IMAGE} {...props} />;
export { EditorDialogImage };

View file

@ -1,10 +0,0 @@
import React, { FC } from 'react';
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
import { IDialogProps } from '~/redux/types';
import { NODE_TYPES } from '~/redux/node/constants';
type IProps = IDialogProps & {};
const EditorDialogText: FC<IProps> = props => <EditorDialog type={NODE_TYPES.TEXT} {...props} />;
export { EditorDialogText };

View file

@ -1,10 +0,0 @@
import React, { FC } from 'react';
import { EditorDialog } from '~/containers/dialogs/EditorDialog';
import { IDialogProps } from '~/redux/types';
import { NODE_TYPES } from '~/redux/node/constants';
type IProps = IDialogProps & {};
const EditorDialogVideo: FC<IProps> = props => <EditorDialog type={NODE_TYPES.VIDEO} {...props} />;
export { EditorDialogVideo };

View file

@ -5,6 +5,7 @@ import { TagSidebar } from '~/containers/sidebars/TagSidebar';
import { ProfileSidebar } from '~/containers/sidebars/ProfileSidebar';
import { Authorized } from '~/components/containers/Authorized';
import { SubmitBar } from '~/components/bars/SubmitBar';
import { EditorCreateDialog } from '~/containers/dialogs/EditorCreateDialog';
interface IProps {
prefix?: string;
@ -15,6 +16,7 @@ const SidebarRouter: FC<IProps> = ({ prefix = '', isLab }) => {
return createPortal(
<>
<Switch>
<Route path={`${prefix}/create/:type`} component={EditorCreateDialog} />
<Route path={`${prefix}/tag/:tag`} component={TagSidebar} />
<Route path={`${prefix}/~:username`} component={ProfileSidebar} />
</Switch>