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:
parent
319e66616c
commit
8faf22dbbf
9 changed files with 80 additions and 11 deletions
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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,
|
||||||
|
});
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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`,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue