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

boris comment more properly showing

This commit is contained in:
Fedor Katurov 2020-04-09 14:18:52 +07:00
parent 319e66616c
commit 8faf22dbbf
9 changed files with 80 additions and 11 deletions

View file

@ -7,7 +7,7 @@ import { ICommentGroup, IComment } from '~/redux/types';
import { groupCommentsByUser } from '~/utils/fn'; import { groupCommentsByUser } from '~/utils/fn';
import { IUser } from '~/redux/auth/types'; import { IUser } from '~/redux/auth/types';
import { canEditComment } from '~/utils/node'; import { canEditComment } from '~/utils/node';
import { nodeLockComment, nodeEditComment } from '~/redux/node/actions'; import { nodeLockComment, nodeEditComment, nodeLoadMoreComments } from '~/redux/node/actions';
import { INodeState } from '~/redux/node/reducer'; import { INodeState } from '~/redux/node/reducer';
import { COMMENTS_DISPLAY } from '~/redux/node/constants'; import { COMMENTS_DISPLAY } from '~/redux/node/constants';
import { plural } from '~/utils/dom'; import { plural } from '~/utils/dom';
@ -19,11 +19,21 @@ interface IProps {
user: IUser; user: IUser;
onDelete: typeof nodeLockComment; onDelete: typeof nodeLockComment;
onEdit: typeof nodeEditComment; onEdit: typeof nodeEditComment;
onLoadMore: typeof nodeLoadMoreComments;
order?: 'ASC' | 'DESC'; order?: 'ASC' | 'DESC';
} }
const NodeComments: FC<IProps> = memo( const NodeComments: FC<IProps> = memo(
({ comments, comment_data, user, onDelete, onEdit, comment_count = 0, order = 'DESC' }) => { ({
comments,
comment_data,
user,
onDelete,
onEdit,
onLoadMore,
comment_count = 0,
order = 'DESC',
}) => {
const comments_left = useMemo(() => Math.max(0, comment_count - comments.length), [ const comments_left = useMemo(() => Math.max(0, comment_count - comments.length), [
comments, comments,
comment_count, comment_count,
@ -34,10 +44,10 @@ const NodeComments: FC<IProps> = memo(
[comments, order] [comments, order]
); );
return ( const more = useMemo(
<div className={styles.wrap}> () =>
{comment_count > 0 && ( comments_left > 0 && (
<div className={styles.more}> <div className={styles.more} onClick={onLoadMore}>
Показать ещё{' '} Показать ещё{' '}
{plural( {plural(
Math.min(comments_left, COMMENTS_DISPLAY), Math.min(comments_left, COMMENTS_DISPLAY),
@ -47,7 +57,13 @@ const NodeComments: FC<IProps> = memo(
)} )}
{comments_left > COMMENTS_DISPLAY ? ` из ${comments_left} оставшихся` : ''} {comments_left > COMMENTS_DISPLAY ? ` из ${comments_left} оставшихся` : ''}
</div> </div>
)} ),
[comments_left, onLoadMore, COMMENTS_DISPLAY]
);
return (
<div className={styles.wrap}>
{order === 'DESC' && more}
{groupped.map(group => ( {groupped.map(group => (
<Comment <Comment
@ -59,6 +75,8 @@ const NodeComments: FC<IProps> = memo(
onEdit={onEdit} onEdit={onEdit}
/> />
))} ))}
{order === 'ASC' && more}
</div> </div>
); );
} }

View file

@ -20,4 +20,11 @@
text-transform: uppercase; text-transform: uppercase;
color: darken(white, 50%); color: darken(white, 50%);
font: $font_14_regular; font: $font_14_regular;
cursor: pointer;
transition: background-color 0.25s;
user-select: none;
&:hover {
background-color: lighten($comment_bg, 4%);
}
} }

View file

@ -22,6 +22,7 @@ const mapDispatchToProps = {
nodeLoadNode: NODE_ACTIONS.nodeLoadNode, nodeLoadNode: NODE_ACTIONS.nodeLoadNode,
nodeLockComment: NODE_ACTIONS.nodeLockComment, nodeLockComment: NODE_ACTIONS.nodeLockComment,
nodeEditComment: NODE_ACTIONS.nodeEditComment, nodeEditComment: NODE_ACTIONS.nodeEditComment,
nodeLoadMoreComments: NODE_ACTIONS.nodeLoadMoreComments,
}; };
type IProps = ReturnType<typeof mapStateToProps> & type IProps = ReturnType<typeof mapStateToProps> &
@ -37,6 +38,7 @@ const BorisLayoutUnconnected: FC<IProps> = ({
nodeLoadNode, nodeLoadNode,
nodeLockComment, nodeLockComment,
nodeEditComment, nodeEditComment,
nodeLoadMoreComments,
}) => { }) => {
const title = getRandomPhrase('BORIS_TITLE'); const title = getRandomPhrase('BORIS_TITLE');
@ -92,6 +94,8 @@ const BorisLayoutUnconnected: FC<IProps> = ({
user={user} user={user}
onDelete={nodeLockComment} onDelete={nodeLockComment}
onEdit={nodeEditComment} onEdit={nodeEditComment}
onLoadMore={nodeLoadMoreComments}
order="ASC"
/> />
)} )}
</Group> </Group>

View file

@ -15,7 +15,6 @@ import { NodeComments } from '~/components/node/NodeComments';
import { NodeTags } from '~/components/node/NodeTags'; import { NodeTags } from '~/components/node/NodeTags';
import { NODE_COMPONENTS, NODE_INLINES } from '~/redux/node/constants'; import { NODE_COMPONENTS, NODE_INLINES } from '~/redux/node/constants';
import * as NODE_ACTIONS from '~/redux/node/actions'; import * as NODE_ACTIONS from '~/redux/node/actions';
import { CommentForm } from '~/components/node/CommentForm';
import { selectUser } from '~/redux/auth/selectors'; import { selectUser } from '~/redux/auth/selectors';
import pick from 'ramda/es/pick'; import pick from 'ramda/es/pick';
import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder'; import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder';
@ -37,6 +36,7 @@ const mapDispatchToProps = {
nodeLock: NODE_ACTIONS.nodeLock, nodeLock: NODE_ACTIONS.nodeLock,
nodeLockComment: NODE_ACTIONS.nodeLockComment, nodeLockComment: NODE_ACTIONS.nodeLockComment,
nodeEditComment: NODE_ACTIONS.nodeEditComment, nodeEditComment: NODE_ACTIONS.nodeEditComment,
nodeLoadMoreComments: NODE_ACTIONS.nodeLoadMoreComments,
}; };
type IProps = ReturnType<typeof mapStateToProps> & type IProps = ReturnType<typeof mapStateToProps> &
@ -68,6 +68,7 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
nodeSetCoverImage, nodeSetCoverImage,
nodeLockComment, nodeLockComment,
nodeEditComment, nodeEditComment,
nodeLoadMoreComments,
}) => { }) => {
const [layout, setLayout] = useState({}); const [layout, setLayout] = useState({});
@ -148,6 +149,7 @@ const NodeLayoutUnconnected: FC<IProps> = memo(
user={user} user={user}
onDelete={nodeLockComment} onDelete={nodeLockComment}
onEdit={nodeEditComment} onEdit={nodeEditComment}
onLoadMore={nodeLoadMoreComments}
order="DESC" order="DESC"
/> />
)} )}

View file

@ -133,3 +133,7 @@ export const nodeSetCoverImage = (current_cover_image: IFile) => ({
type: NODE_ACTIONS.SET_COVER_IMAGE, type: NODE_ACTIONS.SET_COVER_IMAGE,
current_cover_image, current_cover_image,
}); });
export const nodeLoadMoreComments = () => ({
type: NODE_ACTIONS.LOAD_MORE_COMMENTS,
});

View file

@ -103,7 +103,7 @@ export const getNodeComments = ({
access: string; access: string;
take?: number; take?: number;
skip?: number; skip?: number;
}): Promise<IResultWithStatus<{ comments: Comment[] }>> => }): Promise<IResultWithStatus<{ comments: IComment[]; comment_count: number }>> =>
api api
.get(API.NODE.COMMENT(id), configWithToken(access, { params: { take, skip } })) .get(API.NODE.COMMENT(id), configWithToken(access, { params: { take, skip } }))
.then(resultMiddleware) .then(resultMiddleware)

View file

@ -29,6 +29,7 @@ export const NODE_ACTIONS = {
EDIT_COMMENT: `${prefix}EDIT_COMMENT`, EDIT_COMMENT: `${prefix}EDIT_COMMENT`,
CANCEL_COMMENT_EDIT: `${prefix}CANCEL_COMMENT_EDIT`, CANCEL_COMMENT_EDIT: `${prefix}CANCEL_COMMENT_EDIT`,
CREATE: `${prefix}CREATE`, CREATE: `${prefix}CREATE`,
LOAD_MORE_COMMENTS: `${prefix}LOAD_MORE_COMMENTS`,
SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`, SET_SAVE_ERRORS: `${prefix}SET_SAVE_ERRORS`,
SET_LOADING: `${prefix}SET_LOADING`, SET_LOADING: `${prefix}SET_LOADING`,

View file

@ -1,4 +1,4 @@
import { takeLatest, call, put, select, delay, all } from 'redux-saga/effects'; import { takeLatest, call, put, select, delay, all, takeLeading } from 'redux-saga/effects';
import { push } from 'connected-react-router'; import { push } from 'connected-react-router';
import omit from 'ramda/es/omit'; import omit from 'ramda/es/omit';
@ -53,7 +53,7 @@ import { modalSetShown, modalShowDialog } from '../modal/actions';
import { selectFlowNodes, selectFlow } from '../flow/selectors'; import { selectFlowNodes, selectFlow } from '../flow/selectors';
import { URLS } from '~/constants/urls'; import { URLS } from '~/constants/urls';
import { selectNode } from './selectors'; import { selectNode } from './selectors';
import { IResultWithStatus, INode } from '../types'; import { IResultWithStatus, INode, Unwrap } from '../types';
import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs'; import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs';
import { DIALOGS } from '~/redux/modal/constants'; import { DIALOGS } from '~/redux/modal/constants';
import { INodeState } from './reducer'; import { INodeState } from './reducer';
@ -119,6 +119,36 @@ function* onNodeGoto({ id, node_type }: ReturnType<typeof nodeGotoNode>) {
yield put(push(URLS.NODE_URL(id))); yield put(push(URLS.NODE_URL(id)));
} }
function* onNodeLoadMoreComments() {
const {
current: { id },
comments,
}: ReturnType<typeof selectNode> = yield select(selectNode);
const { data, error }: Unwrap<ReturnType<typeof getNodeComments>> = yield call(
reqWrapper,
getNodeComments,
{
id,
take: COMMENTS_DISPLAY,
skip: comments.length,
}
);
const current: ReturnType<typeof selectNode> = yield select(selectNode);
if (!data || error || current.current.id != id) {
return;
}
yield put(
nodeSet({
comments: [...comments, ...data.comments],
comment_count: data.comment_count,
})
);
}
function* onNodeLoad({ id, order = 'ASC' }: ReturnType<typeof nodeLoadNode>) { function* onNodeLoad({ id, order = 'ASC' }: ReturnType<typeof nodeLoadNode>) {
yield put(nodeSetLoading(true)); yield put(nodeSetLoading(true));
yield put(nodeSetLoadingComments(true)); yield put(nodeSetLoadingComments(true));
@ -338,4 +368,5 @@ export default function* nodeSaga() {
yield takeLatest(NODE_ACTIONS.LOCK, onLockSaga); yield takeLatest(NODE_ACTIONS.LOCK, onLockSaga);
yield takeLatest(NODE_ACTIONS.LOCK_COMMENT, onLockCommentSaga); yield takeLatest(NODE_ACTIONS.LOCK_COMMENT, onLockCommentSaga);
yield takeLatest(NODE_ACTIONS.EDIT_COMMENT, onEditCommentSaga); yield takeLatest(NODE_ACTIONS.EDIT_COMMENT, onEditCommentSaga);
yield takeLeading(NODE_ACTIONS.LOAD_MORE_COMMENTS, onNodeLoadMoreComments);
} }

View file

@ -191,3 +191,5 @@ export type INodeNotification = {
}; };
export type INotification = IMessageNotification | ICommentNotification; export type INotification = IMessageNotification | ICommentNotification;
export type Unwrap<T> = T extends Promise<infer U> ? U : T;