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

node edit and like buttons + actions

This commit is contained in:
Fedor Katurov 2019-10-22 12:17:45 +07:00
parent f4c337b255
commit 249a9b368c
7 changed files with 117 additions and 28 deletions

View file

@ -7,9 +7,14 @@ import { NodePanelInner } from '~/components/node/NodePanelInner';
interface IProps {
node: INode;
layout: {};
can_edit: boolean;
can_like: boolean;
onEdit: () => void;
onLike: () => void;
}
const NodePanel: FC<IProps> = ({ node, layout }) => {
const NodePanel: FC<IProps> = ({ node, layout, can_edit, can_like, onEdit, onLike }) => {
const [stack, setStack] = useState(false);
const ref = useRef(null);
@ -37,9 +42,25 @@ const NodePanel: FC<IProps> = ({ node, layout }) => {
return (
<div className={styles.place} ref={ref}>
{stack ? (
createPortal(<NodePanelInner node={node} stack />, document.body)
createPortal(
<NodePanelInner
node={node}
stack
onEdit={onEdit}
onLike={onLike}
can_edit={can_edit}
can_like={can_like}
/>,
document.body
)
) : (
<NodePanelInner node={node} />
<NodePanelInner
node={node}
onEdit={onEdit}
onLike={onLike}
can_edit={can_edit}
can_like={can_like}
/>
)}
</div>
);

View file

@ -9,9 +9,21 @@ import classNames from 'classnames';
interface IProps {
node: INode;
stack?: boolean;
can_edit: boolean;
can_like: boolean;
onEdit: () => void;
onLike: () => void;
}
const NodePanelInner: FC<IProps> = ({ node: { title, user }, stack }) => {
const NodePanelInner: FC<IProps> = ({
node: { title, user },
stack,
can_edit,
can_like,
onEdit,
onLike,
}) => {
return (
<div className={classNames(styles.wrap, { stack })}>
<div className={styles.content}>
@ -23,11 +35,16 @@ const NodePanelInner: FC<IProps> = ({ node: { title, user }, stack }) => {
</Group>
<div className={styles.buttons}>
<Icon icon="edit" size={24} />
<div className={styles.sep} />
<Icon icon="heart" size={24} />
{can_edit && (
<div>
<Icon icon="edit" size={24} onClick={onEdit} />
</div>
)}
{can_like && (
<div>
<Icon icon="heart" size={24} onClick={onLike} />
</div>
)}
</div>
</div>
</div>

View file

@ -66,22 +66,43 @@
& > * {
margin: 0 $gap;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
svg {
fill: darken(white, 50%);
transition: fill 0.25s;
}
&:hover {
svg {
fill: $red;
}
}
&::after {
content: ' ';
flex: 0 0 6px;
height: $gap;
width: 6px;
border-radius: 4px;
background: transparentize(black, 0.7);
margin-left: $gap * 2;
}
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
&::after {
display: none;
}
}
}
//height: 54px;
//border-radius: $radius $radius 0 0;
//background: linear-gradient(176deg, #f42a00, #5c1085);
//position: absolute;
//bottom: 0;
//right: 10px;
//width: 270px;
//display: flex;
}
.mark {
@ -102,9 +123,4 @@
}
.sep {
flex: 0 0 6px;
height: 6px;
width: 6px;
border-radius: 4px;
background: transparentize(black, 0.7);
}

View file

@ -1,7 +1,7 @@
import React, { FC, createElement, useEffect, useCallback, useState } from 'react';
import React, { FC, createElement, useEffect, useCallback, useState, useMemo } from 'react';
import { RouteComponentProps } from 'react-router';
import { connect } from 'react-redux';
import { canEditNode, canLikeNode } from '~/utils/node';
import { selectNode } from '~/redux/node/selectors';
import { Card } from '~/components/containers/Card';
@ -26,6 +26,8 @@ const mapStateToProps = state => ({
const mapDispatchToProps = {
nodeLoadNode: NODE_ACTIONS.nodeLoadNode,
nodeUpdateTags: NODE_ACTIONS.nodeUpdateTags,
nodeEdit: NODE_ACTIONS.nodeEdit,
nodeLike: NODE_ACTIONS.nodeLike,
};
type IProps = ReturnType<typeof mapStateToProps> &
@ -37,9 +39,12 @@ const NodeLayoutUnconnected: FC<IProps> = ({
params: { id },
},
node: { is_loading, is_loading_comments, comments = [], current: node },
user: { is_user },
user,
user: { is_user, role },
nodeLoadNode,
nodeUpdateTags,
nodeEdit,
nodeLike,
}) => {
const [layout, setLayout] = useState({});
@ -57,14 +62,27 @@ const NodeLayoutUnconnected: FC<IProps> = ({
[node, nodeUpdateTags]
);
const can_edit = useMemo(() => canEditNode(node, user), [node, user]);
const can_like = useMemo(() => canLikeNode(node, user), [node, user]);
const block = node && node.type && NODE_COMPONENTS[node.type];
const inline_block = node && node.type && NODE_INLINES[node.type];
const onEdit = useCallback(() => nodeEdit(node.id), [nodeEdit, node]);
const onLike = useCallback(() => nodeLike(node.id), [nodeLike, node]);
return (
<Card className={styles.node} seamless>
{block && createElement(block, { node, is_loading, updateLayout, layout })}
<NodePanel node={node} layout={layout} />
<NodePanel
node={node}
layout={layout}
can_edit={can_edit}
can_like={can_like}
onEdit={onEdit}
onLike={onLike}
/>
<Group>
<Padder>

View file

@ -71,7 +71,12 @@ export const nodeCreate = (node_type: INode['type']) => ({
});
export const nodeEdit = (id: INode['id']) => ({
type: NODE_ACTIONS.CREATE,
type: NODE_ACTIONS.EDIT,
id,
});
export const nodeLike = (id: INode['id']) => ({
type: NODE_ACTIONS.LIKE,
id,
});

View file

@ -18,6 +18,7 @@ export const NODE_ACTIONS = {
LOAD_NODE: `${prefix}LOAD_NODE`,
EDIT: `${prefix}EDIT`,
LIKE: `${prefix}LIKE`,
CREATE: `${prefix}CREATE`,
SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`,

11
src/utils/node.ts Normal file
View file

@ -0,0 +1,11 @@
import { USER_ROLES } from '~/redux/auth/constants';
import { INode } from '~/redux/types';
import { IUser } from '~/redux/auth/types';
import path from 'ramda/es/path';
export const canEditNode = (node: Partial<INode>, user: Partial<IUser>): boolean =>
path(['role'], user) === USER_ROLES.ADMIN ||
(path(['user', 'id'], node) && path(['user', 'id'], node) === path(['id'], user));
export const canLikeNode = (node: Partial<INode>, user: Partial<IUser>): boolean =>
path(['role'], user) && path(['role'], user) !== USER_ROLES.GUEST;