mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-24 20:36:40 +07:00
hooks to show node loader
This commit is contained in:
parent
f121dea3ea
commit
da9ac62584
9 changed files with 79 additions and 41 deletions
|
@ -52,7 +52,8 @@ module.exports = {
|
||||||
"exports": "always-multiline",
|
"exports": "always-multiline",
|
||||||
"functions": "never"
|
"functions": "never"
|
||||||
}],
|
}],
|
||||||
indent: "off"
|
indent: "off",
|
||||||
|
"import/order": "off"
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
document: false,
|
document: false,
|
||||||
|
|
|
@ -14,18 +14,18 @@ interface IProps {
|
||||||
// title?: string;
|
// title?: string;
|
||||||
// is_hero?: boolean;
|
// is_hero?: boolean;
|
||||||
// is_stamp?: boolean;
|
// is_stamp?: boolean;
|
||||||
onSelect: (id: INode['id']) => void;
|
onSelect: (id: INode['id'], type: INode['type']) => void;
|
||||||
is_text?: boolean;
|
is_text?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cell: FC<IProps> = ({ node: { id, title, brief }, onSelect, is_text = false }) => {
|
const Cell: FC<IProps> = ({ node: { id, title, brief, type }, onSelect, is_text = false }) => {
|
||||||
const [is_loaded, setIsLoaded] = useState(false);
|
const [is_loaded, setIsLoaded] = useState(false);
|
||||||
|
|
||||||
const onImageLoad = useCallback(() => {
|
const onImageLoad = useCallback(() => {
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
}, [setIsLoaded]);
|
}, [setIsLoaded]);
|
||||||
|
|
||||||
const onClick = useCallback(() => onSelect(id), [onSelect, id]);
|
const onClick = useCallback(() => onSelect(id, type), [onSelect, id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { IFlowState } from '~/redux/flow/reducer';
|
||||||
import { INode } from '~/redux/types';
|
import { INode } from '~/redux/types';
|
||||||
|
|
||||||
type IProps = Partial<IFlowState> & {
|
type IProps = Partial<IFlowState> & {
|
||||||
onSelect: (id: INode['id']) => void;
|
onSelect: (id: INode['id'], type: INode['type']) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FlowGrid: FC<IProps> = ({ nodes, onSelect }) => (
|
export const FlowGrid: FC<IProps> = ({ nodes, onSelect }) => (
|
||||||
|
|
|
@ -1,21 +1,41 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC, useMemo } from 'react';
|
||||||
import { ImageSwitcher } from '../ImageSwitcher';
|
import { ImageSwitcher } from '../ImageSwitcher';
|
||||||
import * as styles from './styles.scss';
|
import * as styles from './styles.scss';
|
||||||
|
import { INode } from '~/redux/types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { getImageSize } from '~/utils/dom';
|
||||||
|
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
|
||||||
|
|
||||||
interface IProps {}
|
interface IProps {
|
||||||
|
is_loading: boolean;
|
||||||
|
node: INode;
|
||||||
|
}
|
||||||
|
|
||||||
const NodeImageBlock: FC<IProps> = ({}) => (
|
const NodeImageBlock: FC<IProps> = ({ node, is_loading }) => {
|
||||||
<div>
|
const images = useMemo(() => node.files.filter(({ type }) => type === UPLOAD_TYPES.IMAGE), [
|
||||||
<ImageSwitcher total={5} current={2} />
|
node,
|
||||||
|
]);
|
||||||
|
|
||||||
<div className={styles.image_container}>
|
return (
|
||||||
<img
|
<div className={classNames(styles.wrap, { is_loading })}>
|
||||||
className={styles.image}
|
{!is_loading && (
|
||||||
src="http://37.192.131.144/full/attached/2019/08/e4fb2a1d0a2e20d499aaa1f5f83a7115.jpg"
|
<div>
|
||||||
alt=""
|
<ImageSwitcher total={5} current={2} />
|
||||||
/>
|
|
||||||
|
<div className={styles.image_container}>
|
||||||
|
{images.map(file => (
|
||||||
|
<img
|
||||||
|
className={styles.image}
|
||||||
|
src={getImageSize(file.url, 'node')}
|
||||||
|
alt=""
|
||||||
|
key={file.id}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
export { NodeImageBlock };
|
export { NodeImageBlock };
|
||||||
|
|
|
@ -14,9 +14,12 @@ import * as styles from './styles.scss';
|
||||||
import { NodeComments } from '~/components/node/NodeComments';
|
import { NodeComments } from '~/components/node/NodeComments';
|
||||||
import { NodeTags } from '~/components/node/NodeTags';
|
import { NodeTags } from '~/components/node/NodeTags';
|
||||||
import { NODE_COMPONENTS } from '~/redux/node/constants';
|
import { NODE_COMPONENTS } from '~/redux/node/constants';
|
||||||
|
import * as NODE_ACTIONS from '~/redux/node/actions';
|
||||||
|
|
||||||
const mapStateToProps = selectNode;
|
const mapStateToProps = selectNode;
|
||||||
const mapDispatchToProps = {};
|
const mapDispatchToProps = {
|
||||||
|
nodeLoadNode: NODE_ACTIONS.nodeLoadNode,
|
||||||
|
};
|
||||||
|
|
||||||
type IProps = ReturnType<typeof mapStateToProps> &
|
type IProps = ReturnType<typeof mapStateToProps> &
|
||||||
typeof mapDispatchToProps &
|
typeof mapDispatchToProps &
|
||||||
|
@ -28,22 +31,23 @@ const NodeLayoutUnconnected: FC<IProps> = ({
|
||||||
},
|
},
|
||||||
is_loading,
|
is_loading,
|
||||||
current: node,
|
current: node,
|
||||||
|
nodeLoadNode,
|
||||||
}) => {
|
}) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// if (is_loading) return;
|
if (is_loading) return;
|
||||||
|
nodeLoadNode(id, null);
|
||||||
// todo: if node not loading, load it!
|
// todo: if node not loading, load it!
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => console.log({ is_loading }), [is_loading]);
|
useEffect(() => console.log({ is_loading }), [is_loading]);
|
||||||
|
|
||||||
const block = node && node.type && NODE_COMPONENTS[node.type] && NODE_COMPONENTS[node.type];
|
const block = node && node.type && NODE_COMPONENTS[node.type] && NODE_COMPONENTS[node.type];
|
||||||
const view = block && block[is_loading ? 'placeholder' : 'component'];
|
// const view = block && block[is_loading ? 'placeholder' : 'component'];
|
||||||
|
// console.log({ block, view });
|
||||||
console.log({ block, view });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={styles.node} seamless>
|
<Card className={styles.node} seamless>
|
||||||
{view && createElement(view, { node })}
|
{block && createElement(block, { node, is_loading })}
|
||||||
|
|
||||||
<NodePanel />
|
<NodePanel />
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,9 @@ export const nodeSetSaveErrors = (errors: IValidationErrors) => ({
|
||||||
type: NODE_ACTIONS.SET_SAVE_ERRORS,
|
type: NODE_ACTIONS.SET_SAVE_ERRORS,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const nodeLoadNode = (id: string | number) => ({
|
export const nodeLoadNode = (id: string | number, node_type: INode['type']) => ({
|
||||||
id,
|
id,
|
||||||
|
node_type,
|
||||||
type: NODE_ACTIONS.LOAD_NODE,
|
type: NODE_ACTIONS.LOAD_NODE,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,3 +22,8 @@ export const nodeSetLoading = (is_loading: INodeState['is_loading']) => ({
|
||||||
is_loading,
|
is_loading,
|
||||||
type: NODE_ACTIONS.SET_LOADING,
|
type: NODE_ACTIONS.SET_LOADING,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const nodeSetCurrent = (current: INodeState['current']) => ({
|
||||||
|
current,
|
||||||
|
type: NODE_ACTIONS.SET_CURRENT,
|
||||||
|
});
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
|
import { FC } from 'react';
|
||||||
import { IBlock, INode, ValueOf } from '../types';
|
import { IBlock, INode, ValueOf } from '../types';
|
||||||
import { NodeImageBlock } from '~/components/node/NodeImageBlock';
|
import { NodeImageBlock } from '~/components/node/NodeImageBlock';
|
||||||
import { NodeImageBlockPlaceholder } from '~/components/node/NodeImageBlockPlaceholder';
|
import { NodeImageBlockPlaceholder } from '~/components/node/NodeImageBlockPlaceholder';
|
||||||
import { ReactElement, FC } from 'react';
|
|
||||||
|
|
||||||
const prefix = 'NODE.';
|
const prefix = 'NODE.';
|
||||||
export const NODE_ACTIONS = {
|
export const NODE_ACTIONS = {
|
||||||
SAVE: `${prefix}NODE.SAVE`,
|
SAVE: `${prefix}SAVE`,
|
||||||
LOAD_NODE: `${prefix}LOAD_NODE`,
|
LOAD_NODE: `${prefix}LOAD_NODE`,
|
||||||
|
|
||||||
SET_SAVE_ERRORS: `${prefix}NODE.SET_SAVE_ERRORS`,
|
SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`,
|
||||||
SET_LOADING: `${prefix}NODE.SET_LOADING`,
|
SET_LOADING: `${prefix}SET_LOADING`,
|
||||||
|
SET_CURRENT: `${prefix}SET_CURRENT`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EMPTY_BLOCK: IBlock = {
|
export const EMPTY_BLOCK: IBlock = {
|
||||||
|
@ -47,14 +48,8 @@ export const NODE_TYPES = {
|
||||||
TEXT: 'text',
|
TEXT: 'text',
|
||||||
};
|
};
|
||||||
|
|
||||||
type INodeComponents = Record<
|
type INodeComponents = Record<ValueOf<typeof NODE_TYPES>, FC<{ node: INode; is_loading: boolean }>>;
|
||||||
ValueOf<typeof NODE_TYPES>,
|
|
||||||
Record<'component' | 'placeholder', FC<{ node: INode }>>
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const NODE_COMPONENTS: INodeComponents = {
|
export const NODE_COMPONENTS: INodeComponents = {
|
||||||
[NODE_TYPES.IMAGE]: {
|
[NODE_TYPES.IMAGE]: NodeImageBlock,
|
||||||
component: NodeImageBlock,
|
|
||||||
placeholder: NodeImageBlockPlaceholder,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import assocPath from 'ramda/es/assocPath';
|
import assocPath from 'ramda/es/assocPath';
|
||||||
import { NODE_ACTIONS } from './constants';
|
import { NODE_ACTIONS } from './constants';
|
||||||
import { nodeSetSaveErrors, nodeSetLoading } from './actions';
|
import { nodeSetSaveErrors, nodeSetLoading, nodeSetCurrent } from './actions';
|
||||||
import { INodeState } from './reducer';
|
import { INodeState } from './reducer';
|
||||||
|
|
||||||
const setSaveErrors = (state: INodeState, { errors }: ReturnType<typeof nodeSetSaveErrors>) =>
|
const setSaveErrors = (state: INodeState, { errors }: ReturnType<typeof nodeSetSaveErrors>) =>
|
||||||
|
@ -9,7 +9,11 @@ const setSaveErrors = (state: INodeState, { errors }: ReturnType<typeof nodeSetS
|
||||||
const setLoading = (state: INodeState, { is_loading }: ReturnType<typeof nodeSetLoading>) =>
|
const setLoading = (state: INodeState, { is_loading }: ReturnType<typeof nodeSetLoading>) =>
|
||||||
assocPath(['is_loading'], is_loading, state);
|
assocPath(['is_loading'], is_loading, state);
|
||||||
|
|
||||||
|
const setCurrent = (state: INodeState, { current }: ReturnType<typeof nodeSetCurrent>) =>
|
||||||
|
assocPath(['current'], current, state);
|
||||||
|
|
||||||
export const NODE_HANDLERS = {
|
export const NODE_HANDLERS = {
|
||||||
[NODE_ACTIONS.SAVE]: setSaveErrors,
|
[NODE_ACTIONS.SAVE]: setSaveErrors,
|
||||||
[NODE_ACTIONS.SET_LOADING]: setLoading,
|
[NODE_ACTIONS.SET_LOADING]: setLoading,
|
||||||
|
[NODE_ACTIONS.SET_CURRENT]: setCurrent,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import { takeLatest, call, put, select, delay } from 'redux-saga/effects';
|
import { takeLatest, call, put, select, delay } from 'redux-saga/effects';
|
||||||
import { push } from 'connected-react-router';
|
import { push } from 'connected-react-router';
|
||||||
|
|
||||||
import { NODE_ACTIONS } from './constants';
|
import { NODE_ACTIONS, EMPTY_NODE } from './constants';
|
||||||
import { nodeSave, nodeSetSaveErrors, nodeLoadNode, nodeSetLoading } from './actions';
|
import {
|
||||||
|
nodeSave,
|
||||||
|
nodeSetSaveErrors,
|
||||||
|
nodeLoadNode,
|
||||||
|
nodeSetLoading,
|
||||||
|
nodeSetCurrent,
|
||||||
|
} from './actions';
|
||||||
import { postNode } from './api';
|
import { postNode } from './api';
|
||||||
import { reqWrapper } from '../auth/sagas';
|
import { reqWrapper } from '../auth/sagas';
|
||||||
import { flowSetNodes } from '../flow/actions';
|
import { flowSetNodes } from '../flow/actions';
|
||||||
|
@ -31,10 +37,12 @@ function* onNodeSave({ node }: ReturnType<typeof nodeSave>) {
|
||||||
return yield put(modalSetShown(false));
|
return yield put(modalSetShown(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
function* onNodeLoad({ id }: ReturnType<typeof nodeLoadNode>) {
|
function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) {
|
||||||
yield put(nodeSetLoading(true));
|
yield put(nodeSetLoading(true));
|
||||||
yield put(nodeSetSaveErrors({}));
|
yield put(nodeSetSaveErrors({}));
|
||||||
|
|
||||||
|
if (node_type) yield put(nodeSetCurrent({ ...EMPTY_NODE, type: node_type }));
|
||||||
|
|
||||||
yield put(push(URLS.NODE_URL(id)));
|
yield put(push(URLS.NODE_URL(id)));
|
||||||
|
|
||||||
yield delay(1000);
|
yield delay(1000);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue