mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
#58 made dialogs as routes
This commit is contained in:
parent
d9af895558
commit
4dc8bea040
21 changed files with 230 additions and 172 deletions
|
@ -1,58 +1,44 @@
|
|||
import React, { FC, useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import React, { FC, useCallback, useState } from 'react';
|
||||
import { Icon } from '~/components/input/Icon';
|
||||
import { nodeCreate } from '~/redux/node/actions';
|
||||
|
||||
import styles from './styles.module.scss';
|
||||
import { NODE_TYPES } from '~/redux/node/constants';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import { useRouteMatch } from 'react-router';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
interface Props {
|
||||
isLab?: boolean;
|
||||
}
|
||||
|
||||
const SubmitBar: FC<Props> = ({ isLab }) => {
|
||||
const dispatch = useDispatch();
|
||||
const { url } = useRouteMatch();
|
||||
const [focused, setFocused] = useState(false);
|
||||
|
||||
const onOpenImageEditor = useCallback(() => dispatch(nodeCreate(NODE_TYPES.IMAGE, isLab)), [
|
||||
dispatch,
|
||||
]);
|
||||
|
||||
const onOpenTextEditor = useCallback(() => dispatch(nodeCreate(NODE_TYPES.TEXT, isLab)), [
|
||||
dispatch,
|
||||
]);
|
||||
|
||||
const onOpenVideoEditor = useCallback(() => dispatch(nodeCreate(NODE_TYPES.VIDEO, isLab)), [
|
||||
dispatch,
|
||||
]);
|
||||
|
||||
const onOpenAudioEditor = useCallback(() => dispatch(nodeCreate(NODE_TYPES.AUDIO, isLab)), [
|
||||
dispatch,
|
||||
]);
|
||||
const onFocus = useCallback(() => setFocused(true), [setFocused]);
|
||||
const onBlur = useCallback(() => setFocused(false), [setFocused]);
|
||||
|
||||
return (
|
||||
<div className={classNames(styles.wrap, { [styles.lab]: isLab })}>
|
||||
<div className={styles.panel}>
|
||||
<div onClick={onOpenImageEditor}>
|
||||
<Icon icon="image" />
|
||||
<div className={classNames(styles.panel, { [styles.active]: focused })}>
|
||||
<Link to={`${url}/create/image`} className={styles.link}>
|
||||
<Icon icon="image" size={32} />
|
||||
</Link>
|
||||
|
||||
<Link to={`${url}/create/text`} className={styles.link}>
|
||||
<Icon icon="text" size={32} />
|
||||
</Link>
|
||||
|
||||
<Link to={`${url}/create/video`} className={styles.link}>
|
||||
<Icon icon="video" size={32} />
|
||||
</Link>
|
||||
|
||||
<Link to={`${url}/create/audio`} className={styles.link}>
|
||||
<Icon icon="audio" size={32} />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div onClick={onOpenTextEditor}>
|
||||
<Icon icon="text" />
|
||||
</div>
|
||||
|
||||
<div onClick={onOpenVideoEditor}>
|
||||
<Icon icon="video" />
|
||||
</div>
|
||||
|
||||
<div onClick={onOpenAudioEditor}>
|
||||
<Icon icon="audio" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.button}>
|
||||
<button className={styles.button} onFocus={onFocus} onBlur={onBlur} type="button">
|
||||
<Icon icon="plus" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,13 +5,7 @@
|
|||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate($content_width / 2 + $gap, 0);
|
||||
z-index: 4;
|
||||
|
||||
&:hover {
|
||||
.panel {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
}
|
||||
z-index: 14;
|
||||
|
||||
@media (max-width: $content_width + ($bar_height + $gap) * 2) {
|
||||
left: 100%;
|
||||
|
@ -31,6 +25,8 @@
|
|||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
svg {
|
||||
width: 32px;
|
||||
|
@ -50,16 +46,25 @@
|
|||
padding-bottom: $bar_height;
|
||||
border-radius: $radius $radius 0 0;
|
||||
transform: translate(0, 100%);
|
||||
transition: transform 250ms;
|
||||
transition: transform 250ms 250ms;
|
||||
|
||||
div {
|
||||
&.active {
|
||||
transform: translate(0, 0);
|
||||
transition: transform 250ms;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
@include outer_shadow;
|
||||
|
||||
height: $bar_height;
|
||||
width: $bar_height;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
fill: white;
|
||||
color: white;
|
||||
|
||||
svg {
|
||||
width: 32px;
|
||||
|
@ -70,4 +75,3 @@
|
|||
border-radius: $radius $radius 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
src/components/dialogs/ModalWrapper/index.tsx
Normal file
19
src/components/dialogs/ModalWrapper/index.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React, { FC, MouseEventHandler } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
type IProps = {
|
||||
onOverlayClick: MouseEventHandler;
|
||||
};
|
||||
|
||||
const ModalWrapper: FC<IProps> = ({ children, onOverlayClick }) => {
|
||||
return ReactDOM.createPortal(
|
||||
<div className={styles.fixed}>
|
||||
<div className={styles.overlay} onClick={onOverlayClick} />
|
||||
<div className={styles.content}>{children}</div>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
};
|
||||
|
||||
export { ModalWrapper };
|
|
@ -5,6 +5,8 @@ import { INode } from '~/redux/types';
|
|||
import classNames from 'classnames';
|
||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||
import { getPrettyDate } from '~/utils/dom';
|
||||
import { URLS } from '~/constants/urls';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
interface IProps {
|
||||
node: Partial<INode>;
|
||||
|
@ -24,7 +26,7 @@ interface IProps {
|
|||
|
||||
const NodePanelInner: FC<IProps> = memo(
|
||||
({
|
||||
node: { title, user, is_liked, is_heroic, deleted_at, created_at, like_count },
|
||||
node: { id, title, user, is_liked, is_heroic, deleted_at, created_at, like_count },
|
||||
stack,
|
||||
|
||||
canStar,
|
||||
|
@ -78,9 +80,9 @@ const NodePanelInner: FC<IProps> = memo(
|
|||
<Icon icon={deleted_at ? 'locked' : 'unlocked'} size={24} onClick={onLock} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link to={URLS.NODE_EDIT_URL(id)}>
|
||||
<Icon icon="edit" size={24} onClick={onEdit} />
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import { NODE_TYPES } from '~/redux/node/constants';
|
||||
import { EditorDialogImage } from '~/containers/editors/EditorDialogImage';
|
||||
import { EditorDialogText } from '~/containers/editors/EditorDialogText';
|
||||
import { EditorDialogVideo } from '~/containers/editors/EditorDialogVideo';
|
||||
import { EditorDialogAudio } from '~/containers/editors/EditorDialogAudio';
|
||||
import { LoginDialog } from '~/containers/dialogs/LoginDialog';
|
||||
import { LoadingDialog } from '~/containers/dialogs/LoadingDialog';
|
||||
import { TestDialog } from '~/containers/dialogs/TestDialog';
|
||||
|
@ -16,10 +12,6 @@ import { IDialogProps } from '~/redux/types';
|
|||
import { FC } from 'react';
|
||||
|
||||
export const DIALOG_CONTENT: Record<string, FC<IDialogProps>> = {
|
||||
[DIALOGS.EDITOR_IMAGE]: EditorDialogImage,
|
||||
[DIALOGS.EDITOR_TEXT]: EditorDialogText,
|
||||
[DIALOGS.EDITOR_VIDEO]: EditorDialogVideo,
|
||||
[DIALOGS.EDITOR_AUDIO]: EditorDialogAudio,
|
||||
[DIALOGS.LOGIN]: LoginDialog,
|
||||
[DIALOGS.LOGIN_SOCIAL_REGISTER]: LoginSocialRegisterDialog,
|
||||
[DIALOGS.LOADING]: LoadingDialog,
|
||||
|
|
|
@ -16,6 +16,8 @@ export const URLS = {
|
|||
BACKEND_DOWN: '/oopsie',
|
||||
},
|
||||
NODE_URL: (id: INode['id'] | string) => `/post${id}`,
|
||||
NODE_EDIT_URL: (id: INode['id'] | string) => `/post${id}/edit`,
|
||||
NODE_CREATE_URL: (type: string) => `/`,
|
||||
NODE_TAG_URL: (id: number, tagName: string) => `/post${id}/tag/${tagName}`,
|
||||
PROFILE: (username: string) => `/~${username}`,
|
||||
PROFILE_PAGE: (username: string) => `/profile/${username}`,
|
||||
|
|
38
src/containers/dialogs/EditorCreateDialog/index.tsx
Normal file
38
src/containers/dialogs/EditorCreateDialog/index.tsx
Normal 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 };
|
|
@ -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;
|
||||
|
|
57
src/containers/dialogs/EditorEditDialog/index.tsx
Normal file
57
src/containers/dialogs/EditorEditDialog/index.tsx
Normal 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 };
|
|
@ -0,0 +1,4 @@
|
|||
.loader {
|
||||
fill: white;
|
||||
color: white;
|
||||
}
|
|
@ -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}>
|
||||
return (
|
||||
<ModalWrapper onOverlayClick={onRequestClose}>
|
||||
{React.createElement(DIALOG_CONTENT[dialog], {
|
||||
onRequestClose,
|
||||
onDialogChange: modalShowDialog,
|
||||
onDialogChange,
|
||||
})}
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
</ModalWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const Modal = connect(mapStateToProps, mapDispatchToProps)(ModalUnconnected);
|
||||
|
||||
export { ModalUnconnected, Modal };
|
||||
|
||||
/*
|
||||
|
||||
<div className={styles.content_scroller}>
|
||||
<div className={styles.content_padder}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
*/
|
||||
export { Modal };
|
||||
|
|
|
@ -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 };
|
|
@ -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 };
|
|
@ -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 };
|
|
@ -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 };
|
|
@ -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>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { FC, memo } from 'react';
|
||||
import { RouteComponentProps } from 'react-router';
|
||||
import { Route, RouteComponentProps } from 'react-router';
|
||||
import { selectNode } from '~/redux/node/selectors';
|
||||
import { Card } from '~/components/containers/Card';
|
||||
|
||||
|
@ -15,6 +15,8 @@ import { NodeBottomBlock } from '~/components/node/NodeBottomBlock';
|
|||
import { useNodeCoverImage } from '~/utils/hooks/node/useNodeCoverImage';
|
||||
import { useScrollToTop } from '~/utils/hooks/useScrollToTop';
|
||||
import { useLoadNode } from '~/utils/hooks/node/useLoadNode';
|
||||
import { URLS } from '~/constants/urls';
|
||||
import { EditorEditDialog } from '~/containers/dialogs/EditorEditDialog';
|
||||
|
||||
type IProps = RouteComponentProps<{ id: string }> & {};
|
||||
|
||||
|
@ -64,6 +66,8 @@ const NodeLayout: FC<IProps> = memo(
|
|||
</Container>
|
||||
|
||||
<SidebarRouter prefix="/post:id" />
|
||||
|
||||
<Route path={URLS.NODE_EDIT_URL(':id')} component={EditorEditDialog} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,5 +27,5 @@ export const MODAL_ACTIONS = {
|
|||
|
||||
export interface IDialogProps {
|
||||
onRequestClose: () => void;
|
||||
onDialogChange: (dialog: ValueOf<typeof DIALOGS>) => void;
|
||||
onDialogChange?: (dialog: ValueOf<typeof DIALOGS>) => void;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { api, cleanResult, configWithToken, errorMiddleware, resultMiddleware } from '~/utils/api';
|
||||
import { IComment, INode, IResultWithStatus } from '../types';
|
||||
import { api, cleanResult } from '~/utils/api';
|
||||
import { IComment, INode } from '../types';
|
||||
import { API } from '~/constants/api';
|
||||
import { COMMENTS_DISPLAY } from './constants';
|
||||
import {
|
||||
|
@ -22,6 +22,7 @@ import {
|
|||
GetNodeDiffRequest,
|
||||
GetNodeDiffResult,
|
||||
} from '~/redux/node/types';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
|
||||
export type ApiPostNodeRequest = { node: INode };
|
||||
export type ApiPostNodeResult = {
|
||||
|
@ -62,8 +63,20 @@ export const getNodeDiff = ({
|
|||
})
|
||||
.then(cleanResult);
|
||||
|
||||
export const apiGetNode = ({ id }: ApiGetNodeRequest) =>
|
||||
api.get<ApiGetNodeResult>(API.NODE.GET_NODE(id)).then(cleanResult);
|
||||
export const apiGetNode = ({ id }: ApiGetNodeRequest, config?: AxiosRequestConfig) =>
|
||||
api.get<ApiGetNodeResult>(API.NODE.GET_NODE(id), config).then(cleanResult);
|
||||
|
||||
export const apiGetNodeWithCancel = ({ id }: ApiGetNodeRequest) => {
|
||||
const cancelToken = axios.CancelToken.source();
|
||||
return {
|
||||
request: api
|
||||
.get<ApiGetNodeResult>(API.NODE.GET_NODE(id), {
|
||||
cancelToken: cancelToken.token,
|
||||
})
|
||||
.then(cleanResult),
|
||||
cancel: cancelToken.cancel,
|
||||
};
|
||||
};
|
||||
|
||||
export const apiPostComment = ({ id, data }: ApiPostCommentRequest) =>
|
||||
api.post<ApiPostCommentResult>(API.NODE.COMMENT(id), data).then(cleanResult);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue