1
0
Fork 0
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:
muerwre 2019-08-25 16:34:42 +07:00
parent f121dea3ea
commit da9ac62584
9 changed files with 79 additions and 41 deletions

View file

@ -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,

View file

@ -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

View file

@ -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 }) => (

View file

@ -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 };

View file

@ -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 />

View file

@ -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,
});

View file

@ -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,
},
}; };

View file

@ -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,
}; };

View file

@ -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);