PostPage.jsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import React, { useState } from 'react'
  2. import { Button, Divider, Dropdown, Menu } from 'antd';
  3. import { connect } from 'react-redux'
  4. import PostImage from '../components/main/postsFeed/PostImage'
  5. import { PostDescription } from './MainPostsFeed';
  6. import Text from 'antd/lib/typography/Text';
  7. import { CFieldCommentSend, CFieldSubCommentSend, CFieldUpsertCommentSend } from '../components/main/postsFeed/FieldComment';
  8. import { CPostUserPanel } from '../components/main/postsFeed/PostUserPanel';
  9. import { Comment, Tooltip } from 'antd';
  10. import moment from 'moment';
  11. import { Link } from 'react-router-dom';
  12. import { DeleteOutlined, EditOutlined, LikeFilled, LikeOutlined, MoreOutlined } from '@ant-design/icons';
  13. import { actionLikeComment, actionDelLikeComment, actionSubComment } from '../actions';
  14. import { CPostTitle } from '../components/main/post/PostTitle';
  15. import { UserAvatar } from '../components/header/UserAvatar';
  16. import { CPreloader } from './Preloader';
  17. import Paragraph from 'antd/lib/typography/Paragraph';
  18. const PostPageTitle = ({ data: { owner }, postId }) =>
  19. <CPostTitle owner={owner} postId={postId} />
  20. const CPostPageTitle = connect(state => ({ data: state?.postsFeed?.posts || {}, postId: state?.postsFeed?.posts?._id }))(PostPageTitle)
  21. const PostCommentAuthor = ({ owner }) =>
  22. <>
  23. <Link className='PostCommentAuthor' to={`/profile/${owner?._id}`} >
  24. {owner?.nick ? owner.nick : owner?.login ? owner.login : 'Null'}
  25. </Link>
  26. </>
  27. const EditMenu = ({ setEditComment }) =>
  28. <Menu>
  29. <Menu.Item key="1" onClick={() => setEditComment(true)}><EditOutlined /> Edit</Menu.Item>
  30. </Menu>
  31. const PostCommentText = ({ myID, commentId, owner, text }) => {
  32. const [editComment, setEditComment] = useState(false)
  33. return (
  34. <>
  35. {owner?._id === myID && <Dropdown overlay={<EditMenu setEditComment={setEditComment} />} placement="bottomRight">
  36. <span className='PostOne__comment-edit'
  37. >
  38. <MoreOutlined />
  39. </span >
  40. </Dropdown>}
  41. {!editComment
  42. ? <Dropdown overlay={owner?._id === myID && <EditMenu setEditComment={setEditComment} />} trigger={['contextMenu']}>
  43. <Paragraph ellipsis={{ rows: 2, expandable: true, symbol: 'more' }} >
  44. {text}
  45. </ Paragraph>
  46. </Dropdown>
  47. : <CFieldUpsertCommentSend value={text} id={commentId} autoFocus={true} setOpen={setEditComment} rows={4} bordered={true} />}
  48. </>)
  49. }
  50. const CPostCommentText = connect(state => ({ myID: state.auth.payload.sub.id || '' }))(PostCommentText)
  51. const PostCommentDate = ({ createdAt }) =>
  52. <Tooltip title={moment(new Date(+createdAt)).format('DD-MM-YYYY HH:mm:ss')} >
  53. {moment(new Date(+createdAt)).startOf().fromNow()}
  54. </ Tooltip>
  55. const PostCommentAction = ({ myID, commentId, likes, delLikeComment, addLikeComment }) => {
  56. const [open, setOpen] = useState(false);
  57. const likeId = likes.find(l => l?.owner?._id === myID)?._id
  58. const changeLike = () => likeId ? delLikeComment(likeId, commentId) : addLikeComment(commentId)
  59. return (
  60. <>
  61. <span onClick={changeLike}>
  62. {likeId ? <LikeFilled /> : <LikeOutlined />}
  63. <span style={{ paddingLeft: 8, cursor: 'auto' }}>{likes.length ? likes.length : ''}</span>
  64. </span>
  65. <span onClick={() => setOpen(!open)}>Reply to</span>
  66. {open && <CFieldSubCommentSend autoFocus={true} id={commentId} setOpen={setOpen} />}
  67. </>
  68. )
  69. }
  70. const CPostCommentAction = connect(state => ({
  71. myID: state.auth.payload.sub.id || ''
  72. }), {
  73. addLikeComment: actionLikeComment,
  74. delLikeComment: actionDelLikeComment
  75. })(PostCommentAction)
  76. const PostComments = ({ comments, findSubComment, parentId, }) => {
  77. return (<>
  78. {comments?.length && Object.keys(comments[0]).length > 1
  79. ? comments.map(c => {
  80. return (
  81. <Comment
  82. key={c._id}
  83. author={<PostCommentAuthor owner={c.owner} />}
  84. avatar={< UserAvatar avatar={c?.owner?.avatar} avatarSize={'35px'} />}
  85. datetime={<PostCommentDate createdAt={c.createdAt} />}
  86. content={<CPostCommentText text={c.text} commentId={c._id} owner={c.owner} />}
  87. actions={[<CPostCommentAction likes={c.likes} commentId={c._id} />]}
  88. >
  89. {
  90. c.answers && c.answers?.length
  91. ? <>
  92. <PostComments comments={c?.answers} parentId={c._id} findSubComment={findSubComment} />
  93. </>
  94. : null
  95. }
  96. </Comment>
  97. )
  98. })
  99. :
  100. !!comments.length && <Divider plain>
  101. <Text type='secodary' onClick={() => findSubComment(parentId)} >
  102. View answers {comments.length}
  103. </Text>
  104. </Divider>
  105. }
  106. </>)
  107. }
  108. const CPostComments = connect(state => ({
  109. comments: state?.postsFeed?.posts?.comments || [],
  110. }), { findSubComment: actionSubComment })(PostComments)
  111. const PostPageDescrption = ({ data: { _id, likes, text, title, createdAt, } }) =>
  112. <div className='PostOne__description-inner'>
  113. <div className='PostOne__description-top'>
  114. <PostDescription title={title} description={text} date={createdAt} />
  115. <Divider plain><Text type='secodary'>Comments</Text></Divider>
  116. <CPostComments />
  117. </div>
  118. <div className='PostOne__description-bottom'>
  119. <Divider />
  120. <CPostUserPanel likes={likes} postId={_id}
  121. styleFontSize='1.3em' />
  122. <CFieldCommentSend setOpen={() => { }} /> {/* setOpen - функция заглушка для пропса компонента*/}
  123. </div>
  124. </div>
  125. const CPostPageDescrption = connect(state => ({ data: state?.postsFeed?.posts || {} }))(PostPageDescrption)
  126. const PostPage = ({ data: { images } }) =>
  127. <div className='PostOne'>
  128. <CPreloader promiseName='postOne' />
  129. <div className='PostOne__inner'>
  130. <div className='PostOne__image'>
  131. <PostImage images={images} />
  132. </div>
  133. <div className='PostOne__title'>
  134. <CPostPageTitle />
  135. </div>
  136. <div className='PostOne__description'>
  137. <CPostPageDescrption />
  138. </div>
  139. </div>
  140. </div>
  141. export const CPostPage = connect(state => ({ data: state?.postsFeed?.posts || {} }))(PostPage)