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

node no comments

This commit is contained in:
muerwre 2019-08-25 21:56:32 +07:00
parent b4d7bd2c8a
commit 96bdbb0e04
11 changed files with 103 additions and 61 deletions

View file

@ -1,16 +1,25 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { Comment } from '~/components/node/Comment';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import { Group } from '~/components/containers/Group'; import { Group } from '~/components/containers/Group';
import classNames from 'classnames';
import { Filler } from '~/components/containers/Filler';
import { ERRORS } from '~/constants/errors';
import { t } from '~/utils/trans';
interface IProps {} interface IProps {
is_loading: boolean;
}
const NodeNoComments: FC<IProps> = () => ( const NodeNoComments: FC<IProps> = ({ is_loading = false }) => (
<Group className={styles.wrap}> <>
<Comment is_empty is_loading={false} style={{ height: 94 }} /> <Group className={classNames(styles.wrap, { is_loading })}>
<Comment is_empty is_loading={false} style={{ height: 104 }} /> <div className={styles.card} />
<Comment is_empty is_loading={false} style={{ height: 100 }} /> <div className={styles.card}>{!is_loading && t(ERRORS.NO_COMMENTS)}</div>
</Group> <div className={styles.card} />
</Group>
<Filler />
</>
); );
export { NodeNoComments }; export { NodeNoComments };

View file

@ -1,6 +1,43 @@
@keyframes fade {
0% {
opacity: 0.25;
}
100% {
opacity: 0.1;
}
}
.wrap { .wrap {
height: 300px; height: 300px;
overflow: hidden; overflow: hidden;
position: relative;
@include after_shade($node_bg); @include after_shade($node_bg);
&:global(.is_loading) {
.card {
animation: fade 0.5s infinite alternate;
}
}
}
.card {
opacity: 0.2;
border-radius: $radius;
height: 96px;
background: $comment_bg;
display: flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
font: $font_18_semibold;
color: transparentize(white, 0.5);
@include outer_shadow();
&:nth-child(2) {
// animation-delay: -300ms !important;
}
&:nth-child(3) {
// animation-delay: -600ms !important;
}
} }

View file

@ -2,4 +2,9 @@ export const ERRORS = {
NOT_AN_EMAIL: 'Not_An_Email', NOT_AN_EMAIL: 'Not_An_Email',
TOO_SHIRT: 'Is_Too_Shirt', TOO_SHIRT: 'Is_Too_Shirt',
EMPTY_RESPONSE: 'Empty_Response', EMPTY_RESPONSE: 'Empty_Response',
NO_COMMENTS: 'No_Comments',
};
export const ERROR_LITERAL = {
[ERRORS.NO_COMMENTS]: 'Комментариев пока нет',
}; };

View file

@ -13,53 +13,7 @@ import { ImageSwitcher } from '~/components/node/ImageSwitcher';
interface IProps {} interface IProps {}
const ImageExample: FC<IProps> = () => ( const ImageExample: FC<IProps> = () => <Card className={styles.node} seamless></Card>;
<Card className={styles.node} seamless>
<ImageSwitcher total={5} current={2} onChange={console.log} />
<div className={styles.image_container}>
<img
className={styles.image}
src="http://37.192.131.144/full/attached/2019/08/e4fb2a1d0a2e20d499aaa1f5f83a7115.jpg"
alt=""
/>
</div>
<NodePanel />
<Group>
<Padder>
<Group horizontal className={styles.content}>
<Group className={styles.comments}>
<NodeNoComments />
{range(1, 6).map(el => (
<Comment key={el} />
))}
</Group>
<div className={styles.panel}>
<Group style={{ flex: 1 }}>
<Tags
tags={[
{ title: 'Избранный', feature: 'red' },
{ title: 'Плейлист', feature: 'green' },
{ title: 'Просто' },
{ title: '+ фото', feature: 'black' },
{ title: '+ с музыкой', feature: 'black' },
]}
/>
<NodeRelated title="First album" />
<NodeRelated title="Second album" />
</Group>
</div>
</Group>
</Padder>
</Group>
</Card>
);
export { ImageExample }; export { ImageExample };

View file

@ -30,6 +30,8 @@ const NodeLayoutUnconnected: FC<IProps> = ({
params: { id }, params: { id },
}, },
is_loading, is_loading,
is_loading_comments,
comments = [],
current: node, current: node,
nodeLoadNode, nodeLoadNode,
}) => { }) => {
@ -50,8 +52,11 @@ const NodeLayoutUnconnected: FC<IProps> = ({
<Padder> <Padder>
<Group horizontal className={styles.content}> <Group horizontal className={styles.content}>
<Group className={styles.comments}> <Group className={styles.comments}>
<NodeNoComments /> {is_loading_comments || !comments.length || true ? (
<NodeComments /> <NodeNoComments is_loading={is_loading_comments} />
) : (
<NodeComments />
)}
</Group> </Group>
<div className={styles.panel}> <div className={styles.panel}>

View file

@ -23,6 +23,11 @@ export const nodeSetLoading = (is_loading: INodeState['is_loading']) => ({
type: NODE_ACTIONS.SET_LOADING, type: NODE_ACTIONS.SET_LOADING,
}); });
export const nodeSetLoadingComments = (is_loading_comments: INodeState['is_loading_comments']) => ({
is_loading_comments,
type: NODE_ACTIONS.SET_LOADING_COMMENTS,
});
export const nodeSetCurrent = (current: INodeState['current']) => ({ export const nodeSetCurrent = (current: INodeState['current']) => ({
current, current,
type: NODE_ACTIONS.SET_CURRENT, type: NODE_ACTIONS.SET_CURRENT,

View file

@ -10,6 +10,7 @@ export const NODE_ACTIONS = {
SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`, SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`,
SET_LOADING: `${prefix}SET_LOADING`, SET_LOADING: `${prefix}SET_LOADING`,
SET_LOADING_COMMENTS: `${prefix}SET_LOADING_COMMENTS`,
SET_CURRENT: `${prefix}SET_CURRENT`, SET_CURRENT: `${prefix}SET_CURRENT`,
}; };

View file

@ -1,6 +1,11 @@
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, nodeSetCurrent } from './actions'; import {
nodeSetSaveErrors,
nodeSetLoading,
nodeSetCurrent,
nodeSetLoadingComments,
} 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,11 +14,17 @@ 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 setLoadingComments = (
state: INodeState,
{ is_loading_comments }: ReturnType<typeof nodeSetLoadingComments>
) => assocPath(['is_loading_comments'], is_loading_comments, state);
const setCurrent = (state: INodeState, { current }: ReturnType<typeof nodeSetCurrent>) => const setCurrent = (state: INodeState, { current }: ReturnType<typeof nodeSetCurrent>) =>
assocPath(['current'], current, state); 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_LOADING_COMMENTS]: setLoadingComments,
[NODE_ACTIONS.SET_CURRENT]: setCurrent, [NODE_ACTIONS.SET_CURRENT]: setCurrent,
}; };

View file

@ -4,12 +4,15 @@ import { EMPTY_NODE } from './constants';
import { NODE_HANDLERS } from './handlers'; import { NODE_HANDLERS } from './handlers';
export type INodeState = Readonly<{ export type INodeState = Readonly<{
is_loading: boolean;
editor: INode; editor: INode;
current: Partial<INode>; current: INode;
comments: IComment[]; comments: IComment[];
error: string; error: string;
errors: Record<string, string>; errors: Record<string, string>;
is_loading: boolean;
is_loading_comments: boolean;
}>; }>;
const INITIAL_STATE: INodeState = { const INITIAL_STATE: INodeState = {
@ -19,9 +22,10 @@ const INITIAL_STATE: INodeState = {
blocks: [], blocks: [],
files: [], files: [],
}, },
current: {}, current: { ...EMPTY_NODE },
comments: [], comments: [],
is_loading: false, is_loading: false,
is_loading_comments: false,
error: null, error: null,
errors: {}, errors: {},
}; };

View file

@ -8,6 +8,7 @@ import {
nodeLoadNode, nodeLoadNode,
nodeSetLoading, nodeSetLoading,
nodeSetCurrent, nodeSetCurrent,
nodeSetLoadingComments,
} from './actions'; } from './actions';
import { postNode, getNode } from './api'; import { postNode, getNode } from './api';
import { reqWrapper } from '../auth/sagas'; import { reqWrapper } from '../auth/sagas';
@ -39,6 +40,7 @@ function* onNodeSave({ node }: ReturnType<typeof nodeSave>) {
function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) { function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) {
yield put(nodeSetLoading(true)); yield put(nodeSetLoading(true));
yield put(nodeSetLoadingComments(true));
yield put(nodeSetSaveErrors({})); yield put(nodeSetSaveErrors({}));
if (node_type) yield put(nodeSetCurrent({ ...EMPTY_NODE, type: node_type })); if (node_type) yield put(nodeSetCurrent({ ...EMPTY_NODE, type: node_type }));
@ -58,6 +60,10 @@ function* onNodeLoad({ id, node_type }: ReturnType<typeof nodeLoadNode>) {
yield put(nodeSetSaveErrors({})); yield put(nodeSetSaveErrors({}));
yield put(nodeSetCurrent(node)); yield put(nodeSetCurrent(node));
// todo: load comments
yield delay(500);
yield put(nodeSetLoadingComments(false));
return; return;
} }

5
src/utils/trans.ts Normal file
View file

@ -0,0 +1,5 @@
import { ERRORS, ERROR_LITERAL } from '~/constants/errors';
import { ValueOf } from '~/redux/types';
export const t = (string: ValueOf<typeof ERRORS>): ValueOf<typeof ERROR_LITERAL> =>
ERROR_LITERAL[string] || string;