瀏覽代碼

24.03.2023 18:30

Volddemar4ik 1 年之前
父節點
當前提交
7618ac258f

+ 58 - 87
js/Project/project/src/components/post/card_post.js

@@ -13,23 +13,22 @@ import {
     Typography,
     Box,
     Divider,
-    TextField
 } from '@mui/material'
 import {
     FavoriteBorderRounded,
     Send,
     ChatBubbleOutline,
     TurnedInNot,
-    AccountCircle,
-    AddComment
 } from '@mui/icons-material/'
+
 import Grid from '@mui/material/Unstable_Grid2';
 
-import Comments from "./comments";
+import CCommentsFeed from "./comments_feed";
+import CommentField from "./comment_field";
 
 
 export function CardPost({ postData }) {
-    console.log('postData: ', postData)
+    // console.log('postData: ', postData)
 
     const history = useHistory()
 
@@ -46,7 +45,7 @@ export function CardPost({ postData }) {
         history.push(`/user/${postData?.owner?._id}`)
     }
 
-    function AddCommentFocus() {
+    function addCommentFocus() {
         document.getElementById('addCommentField').focus()
     }
 
@@ -99,10 +98,12 @@ export function CardPost({ postData }) {
                 <Grid
                     container
                     spacing={2}
+                    sx={{
+                        marginBottom: 3
+                    }}
                 >
                     <Grid
                         xs={2}
-
                         sx={{
                             flex: '0 0 45px'
                         }}
@@ -124,7 +125,8 @@ export function CardPost({ postData }) {
                             variant="subtitle2"
                             color="text.secondary"
                             sx={{
-                                cursor: 'pointer'
+                                cursor: 'pointer',
+                                width: 'fit-content'
                             }}
                             onClick={toAccount}
                         >
@@ -133,7 +135,7 @@ export function CardPost({ postData }) {
 
                         <Typography
                             variant="subtitle2"
-                            color="text.secondary"
+                            color="text.primary"
                         >
                             {postData?.title}
                         </Typography>
@@ -148,7 +150,8 @@ export function CardPost({ postData }) {
                 </Grid>
 
                 <Grid>
-                    <Comments data={postData?.comments} />
+                    {/* <CommentsFeed data={postData?.comments} /> */}
+                    <CCommentsFeed />
                 </Grid>
             </CardContent>
 
@@ -160,98 +163,66 @@ export function CardPost({ postData }) {
                         flexGrow: 1
                     }}>
                     <Grid
+                        xs={12}
                         container
+                        justifyContent="space-between"
+                        alignItems="center"
+                        sx={{
+                            fontSize: '12px'
+                        }}
                     >
-                        <Grid
-                            xs={12}
-                            container
-                            justifyContent="space-between"
-                            alignItems="center"
-                            sx={{
-                                fontSize: '12px'
-                            }}
-                        >
-                            <Grid
-                                container
-                                columnSpacing={1}
-                            >
-                                <Grid>
-                                    <IconButton
-                                        aria-label="add to favorites"
-                                        onClick={() => (console.log('click like main post'))}
-                                    >
-                                        <FavoriteBorderRounded />
-                                    </IconButton>
-                                </Grid>
-
-                                <Grid>
-                                    <IconButton
-                                        onClick={AddCommentFocus}
-                                    >
-                                        <ChatBubbleOutline />
-                                    </IconButton>
-                                </Grid>
+                        <Grid container>
+                            <Grid>
+                                <IconButton
+                                    aria-label="add to favorites"
+                                    onClick={() => (console.log('click like main post'))}
+                                >
+                                    <FavoriteBorderRounded />
+                                </IconButton>
+                            </Grid>
 
-                                <Grid>
-                                    <IconButton
-                                        aria-label="share"
-                                    >
-                                        <Send />
-                                    </IconButton>
-                                </Grid>
+                            <Grid>
+                                <IconButton
+                                    onClick={addCommentFocus}
+                                >
+                                    <ChatBubbleOutline />
+                                </IconButton>
                             </Grid>
 
-                            <Grid
-                                sx={{
-                                    order: { xs: 1, sm: 2 }
-                                }}
-                            >
-                                <IconButton>
-                                    <TurnedInNot />
+                            <Grid>
+                                <IconButton
+                                    aria-label="share"
+                                >
+                                    <Send />
                                 </IconButton>
                             </Grid>
                         </Grid>
+
+                        <Grid>
+                            <IconButton>
+                                <TurnedInNot />
+                            </IconButton>
+                        </Grid>
+                    </Grid>
+
+                    <Grid container>
+                        <Typography
+                            variant="subtitle1"
+                            color="text.secondary"
+                            sx={{
+                                padding: 1
+                            }}
+                        >
+                            Нравится: {postData.likesCount ? postData.likesCount : '0'}
+                        </Typography>
                     </Grid>
                 </Box>
             </CardActions>
 
-            <CardContent>
-                Нравится: {postData.likesCount ? postData.likesCount : '0'}
-                {/* Нравится: {postData.likesCount || '0'} // сработает или нет - проверить */}
-            </CardContent>
-
             <Divider />
 
             <CardActions>
-                <Box
-                    sx={{
-                        display: 'flex',
-                        alignItems: 'flex-end',
-                        justifyContent: 'space-between'
-                    }}
-                >
-                    <AccountCircle
-                        sx={{
-                            color: 'action.active',
-                            mr: 1,
-                            my: 0.5
-                        }}
-                    />
-
-                    <TextField
-                        id="addCommentField"
-                        label="Add comment..."
-                        variant="standard"
-                    />
-
-                    <Send
-                        sx={{
-                            color: 'action.active',
-                            mr: 1,
-                            my: 0.5
-                        }}
-                    />
-                </Box>
+                <CommentField id={postData?._id} />
             </CardActions>
         </Card>
     )

+ 0 - 1
js/Project/project/src/components/post/carousel_post.js

@@ -36,7 +36,6 @@ export function MyCarouselPost({ postImages }) {
                             backgroundImage: `url(/images/noPhoto.png)`,
                             backgroundRepeat: 'no-repeat',
                             backgroundPosition: 'center',
-
                         }}
 
                         key={item?.url}

+ 60 - 31
js/Project/project/src/components/post/comments.js

@@ -1,5 +1,6 @@
 import { url } from "../../App";
-import { useHistory } from "react-router-dom";
+import { useHistory, useParams } from "react-router-dom";
+import { useEffect, useState } from "react";
 
 import './style.scss'
 
@@ -16,10 +17,39 @@ import {
 import Grid from '@mui/material/Unstable_Grid2';
 
 
-function CommentsCard({ data }) {
-    console.log('data: ', data)
+import { actionFindCommentsAnswerTo } from "../redux/action";
+import { actionFullFindCommentsPostOne } from "../redux/thunks";
+import { connect, useDispatch } from "react-redux";
+
+
+function CommentCard({ data }) {
+    // console.log('data: ', data)
 
     const history = useHistory()
+    const dispatch = useDispatch()
+
+    let answerToCommentData
+    // скрываем/открываем вложенные комментарии
+    const [openComments, setOpenComments] = useState('Посмотреть ответы')
+    // скрываем/открываем блок с ответами на комментарии
+    const [toggleAnswerToBlock, setToggleAnswerToBlock] = useState(false)
+
+    // функция скрытия/открытия ответов на комменты
+    async function changeText(id) {
+        setToggleAnswerToBlock(!toggleAnswerToBlock)
+
+        await dispatch(actionFindCommentsAnswerTo(id))
+
+        return (openComments === 'Посмотреть ответы'
+            ? setOpenComments('Скрыть ответы')
+            : setOpenComments('Посмотреть ответы')
+        )
+    }
+
+
+
+
+
 
     // дата поста
     const dateofPost = new Date(+data?.createdAt)
@@ -103,10 +133,11 @@ function CommentsCard({ data }) {
                         paddingBottom: 0
                     }}
                 >
-                    <IconButton>
+                    <IconButton
+                        onClick={() => (console.log('click like comment'))}
+                    >
                         <FavoriteBorderRounded
                             fontSize='small'
-                            onClick={() => (console.log('click like comment'))}
                         />
                     </IconButton>
                 </Grid>
@@ -169,34 +200,32 @@ function CommentsCard({ data }) {
                         padding: '0 8px'
                     }}
                 >
-                    <Divider>
-                        <Typography
-                            variant="caption"
-                            color="text.disabled"
-                            sx={{
-                                cursor: 'pointer'
-                            }}
-                            onClick={() => (console.log('click show answers'))}
-                        >
-                            Посмотреть ответы
-                        </Typography>
-                    </Divider>
+                    {(data?.answers.length !== 0) &&
+                        <Divider>
+                            <Typography
+                                variant="caption"
+                                color="text.disabled"
+                                sx={{
+                                    cursor: 'pointer'
+                                }}
+                                onClick={() => changeText(data?._id)}
+                            >
+                                {openComments}
+                            </Typography>
+                        </Divider>}
                 </Grid>
-            </Grid>
-        </Grid>
-    )
-}
-
-
 
-function Comments({ data }) {
-
-    return (
-        <Box>
-            {data && data.map(item => <CommentsCard data={item} />)}
-        </Box>
+                {toggleAnswerToBlock &&
+                    <Grid xs={12}
+                        sx={{
+                            padding: '0 8px'
+                        }}>
+                        <div sx={{ backgroundColor: 'red' }}>тут будут новые комментарии/ а если их будет много, то они будут в одну строку или как то так</div>
+                        <CommentCard data={answerToCommentData} />
+                    </Grid>}
+            </Grid>
+        </Grid >
     )
 }
 
-
-export default Comments
+export default CommentCard

+ 226 - 0
js/Project/project/src/components/post/comment_card.js

@@ -0,0 +1,226 @@
+import { url } from "../../App";
+import { useHistory } from "react-router-dom";
+import { useState } from "react";
+
+import {
+    Avatar,
+    IconButton,
+    Typography,
+    Divider,
+} from '@mui/material'
+
+import Grid from '@mui/material/Unstable_Grid2';
+
+import { FavoriteBorderRounded } from '@mui/icons-material/'
+
+import './style.scss'
+
+
+function CommentCard({ data }) {
+    console.log('data: ', data)
+
+    const history = useHistory()
+
+    // дата поста
+    const dateofPost = new Date(+data?.createdAt)
+    const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
+    const dateofPostParse = `${dateofPost.getDate() < 10 ? '0' + dateofPost.getDate() : dateofPost.getDate()} 
+    ${months[dateofPost.getMonth()]} 
+    ${dateofPost.getFullYear()}
+    ${dateofPost.getHours() < 10 ? '0' + dateofPost.getHours() : dateofPost.getHours()}:${dateofPost.getMinutes() < 10 ? '0' + dateofPost.getMinutes() : dateofPost.getMinutes()}`
+
+
+    // let answerToCommentData
+    // скрываем/открываем вложенные комментарии
+    const [openComments, setOpenComments] = useState('Посмотреть ответы')
+    // скрываем/открываем блок с ответами на комментарии
+    const [toggleAnswerToBlock, setToggleAnswerToBlock] = useState(false)
+
+    // функция скрытия/открытия ответов на комменты
+    async function changeText(id) {
+        setToggleAnswerToBlock(!toggleAnswerToBlock)
+
+        return (openComments === 'Посмотреть ответы'
+            ? setOpenComments('Скрыть ответы')
+            : setOpenComments('Посмотреть ответы')
+        )
+    }
+
+    function toAccount(id) {
+        history.push(`/user/${id}`)
+    }
+
+    function addCommentFocus() {
+        const inputField = document.getElementById('addCommentField')
+        console.log(inputField)
+
+        // if (inputField) {
+        //     inputField.value = `@text`
+
+        inputField.focus()
+        // }
+
+        // const focused = document.hasFocus()
+        // console.log(focused)
+
+
+    }
+
+
+    return (
+        <Grid
+            container
+            spacing={2}
+            sx={{
+                marginBottom: 2
+            }}
+        >
+            <Grid
+                xs={1.5}
+                sx={{
+                    flex: '0 0 45px'
+                }}
+            >
+                <Avatar
+                    alt={data?.owner?.login}
+                    src={(url + data?.owner?.avatar?.url)}
+                    sx={{
+                        width: 40,
+                        height: 40
+                    }}
+                />
+            </Grid>
+
+            <Grid
+                xs={10.5}
+                container
+            >
+                <Grid
+                    xs={10}
+                    sx={{
+                        paddingBottom: 0
+                    }}
+                >
+                    <Typography
+                        variant="subtitle2"
+                        color="text.secondary"
+                        sx={{
+                            cursor: 'pointer'
+                        }}
+                        onClick={() => toAccount(data?.owner?._id)}
+                    >
+                        {data?.owner?.login}
+                    </Typography>
+
+                    <Typography
+                        variant="body2"
+                        color="text.secondary"
+                    >
+                        {data?.text}
+                    </Typography>
+                </Grid>
+
+                <Grid
+                    xs={2}
+                    sx={{
+                        paddingBottom: 0
+                    }}
+                >
+                    <IconButton
+                        onClick={() => (console.log('click like comment'))}
+                    >
+                        <FavoriteBorderRounded
+                            fontSize='small'
+                        />
+                    </IconButton>
+                </Grid>
+
+                <Grid
+                    xs={5.5}
+                    sx={{
+                        padding: 0,
+                        paddingLeft: 1
+
+                    }}
+                >
+                    <Typography
+                        variant="caption"
+                        color="text.disabled"
+                        align='left'
+                    >
+                        {dateofPostParse}
+                    </Typography>
+                </Grid>
+
+                <Grid
+                    xs={3.5}
+                    sx={{
+                        padding: 0
+                    }}
+                >
+                    <Typography
+                        variant="caption"
+                        color="text.disabled"
+                        align='left'
+                    >
+                        Нравится: {data?.likesCount || '0'}
+                    </Typography>
+                </Grid>
+
+                <Grid
+                    xs={3}
+                    sx={{
+                        padding: 0,
+                        paddingRight: 1
+                    }}
+                >
+                    <Typography
+                        variant="caption"
+                        color="text.disabled"
+                        align='left'
+                        sx={{
+                            cursor: 'pointer'
+                        }}
+                        onClick={addCommentFocus}
+                    >
+                        Ответить
+                    </Typography>
+                </Grid>
+
+                <Grid
+                    xs={12}
+                    sx={{
+                        padding: '0 8px'
+                    }}
+                >
+                    {(data?.answers.length !== 0) &&
+                        <Divider>
+                            <Typography
+                                variant="caption"
+                                color="text.disabled"
+                                sx={{
+                                    cursor: 'pointer'
+                                }}
+                                onClick={() => changeText(data?._id)}
+                            >
+                                {openComments}
+                            </Typography>
+                        </Divider>}
+                </Grid>
+
+                {toggleAnswerToBlock &&
+                    <Grid xs={12}
+                        sx={{
+                            padding: '0 8px'
+                        }}>
+                        {data?.answers && (data?.answers).map(item => <CommentCard
+                            data={item}
+                            key={item._id}
+                        />)}
+                    </Grid>}
+            </Grid>
+        </Grid >
+    )
+}
+
+export default CommentCard

+ 132 - 0
js/Project/project/src/components/post/comment_field.js

@@ -0,0 +1,132 @@
+import { url } from "../../App";
+
+import './style.scss'
+
+import {
+    IconButton,
+    Typography,
+    Box,
+    TextField,
+    Popover
+} from '@mui/material'
+import {
+    SentimentSatisfiedAlt
+} from '@mui/icons-material/'
+
+import EmojiPicker from 'emoji-picker-react';
+import { SkinTones } from 'emoji-picker-react';
+
+import { useState } from "react";
+import { useDispatch } from "react-redux";
+
+import { actionAddComment } from "../redux/action";
+
+
+function CommentField({ id }) {
+    // console.log('id: ', id)
+
+    const dispatch = useDispatch()
+
+    // отслеживаем состояние поля ввода комментария для поста
+    const [comment, setComment] = useState({ text: '', post: { _id: id } })
+    // console.log('comment: ', comment)
+
+    // открытие поповера emoji
+    const [openPopover, setOpenPopover] = useState(null);
+    const openEmoji = (event) => {
+        setOpenPopover(event.currentTarget);
+    }
+    const closeEmoji = () => {
+        setOpenPopover(null);
+    }
+    const open = Boolean(openPopover);
+    const emojiField = open ? 'simple-popover' : undefined;
+
+
+    // вот это будет перерабатываться после того, как загружу все комментарии: после отправки коммента, нужно перезагрузить комментарии, чтобы обновить их на странице и сразу отобразить
+    function uploadComment(params) {
+        dispatch(actionAddComment(params))
+    }
+
+
+    return (
+        <Box
+            sx={{
+                display: 'flex',
+                alignItems: 'flex-end',
+                justifyContent: 'space-between',
+                width: '100%'
+            }}
+        >
+            <TextField
+                id='addCommentField'
+                variant="standard"
+                multiline
+                placeholder='Комментировать...'
+                size="small"
+                color="info"
+                sx={{
+                    margin: 1,
+                    width: '100%',
+                }}
+                value={comment.text}
+                onChange={e => setComment({ ...comment, text: e.target.value })}
+
+                InputProps={{
+                    startAdornment:
+                        <Box>
+                            <IconButton
+                                aria-describedby={emojiField}
+                                onClick={openEmoji}
+                            >
+                                <SentimentSatisfiedAlt
+                                    fontSize='small'
+                                />
+                            </IconButton>
+
+                            <Popover
+                                id={emojiField}
+                                open={open}
+                                anchorEl={openPopover}
+                                onClose={closeEmoji}
+                                anchorOrigin={{
+                                    vertical: 'top',
+                                    horizontal: 'right',
+                                }}
+                                transformOrigin={{
+                                    vertical: 'bottom',
+                                    horizontal: 'left',
+                                }}
+                            >
+                                <EmojiPicker
+                                    width={300}
+                                    height={400}
+                                    defaultSkinTone={SkinTones}
+                                    onEmojiClick={e => setComment({ ...comment, text: comment.text + e.emoji })}
+                                />
+                            </Popover>
+                        </Box>,
+
+                    endAdornment:
+                        <Box>
+                            {comment.text !== '' && <Typography
+                                variant='subtitle2'
+                                color="primary.main"
+                                align='center'
+                                sx={{
+                                    alignSelf: 'center',
+                                    cursor: 'pointer',
+                                    margin: '0 8px'
+                                }}
+                                onClick={() => uploadComment(comment)}
+                            >
+                                Отправить
+                            </Typography>}
+                        </Box>
+                }}
+            />
+        </Box>
+    )
+}
+
+export default CommentField

+ 58 - 0
js/Project/project/src/components/post/comments_feed.js

@@ -0,0 +1,58 @@
+import { url } from "../../App";
+import { useParams } from "react-router-dom";
+import { useEffect } from "react";
+import { connect } from "react-redux";
+
+import { actionFullFindCommentsPostOne } from "../redux/thunks";
+
+import CommentCard from "./comment_card";
+
+import './style.scss';
+
+
+function CommentsFeed({ comments = [], loadComments }) {
+    // console.log('comments: ', comments)
+
+    const { postId } = useParams()
+    useEffect(() => { loadComments(postId) }, [postId])
+
+
+    // фуyкция построения дерева комментариев
+    function commentsTreeConstructor(arr, answerToId = null) {
+        const result = []
+
+        for (const commentItem of arr) {
+            if (commentItem.answerTo && commentItem.answerTo._id === answerToId) {
+                commentItem.answers = commentsTreeConstructor(arr, commentItem._id)
+                result.push(commentItem)
+            }
+
+            if (!commentItem.answerTo && !answerToId) {
+                commentItem.answers = commentsTreeConstructor(arr, commentItem._id)
+                result.push(commentItem)
+            }
+        }
+
+        // сортируем от новых к старым
+        return result.sort((x, y) => y.createdAt - x.createdAt)
+    }
+
+    const data = commentsTreeConstructor(comments)
+
+
+    return (
+        <>
+            {data && data.map(item => <CommentCard
+                data={item}
+                key={item._id}
+            />
+            )}
+        </>
+    )
+
+}
+
+const CCommentsFeed = connect(state => ({ comments: state?.promise?.FindComments?.payload }), { loadComments: actionFullFindCommentsPostOne })(CommentsFeed)
+
+
+export default CCommentsFeed

+ 2 - 5
js/Project/project/src/components/post/index.js

@@ -27,9 +27,8 @@ function Comments({ post = {}, loadPost }) {
         <Box>
             <Grid2 container sx={{
                 height: '80vh',
-                backgroundColor: "blue"
             }}>
-                <Grid2 xs={8}>
+                <Grid2 xs={7.5}>
                     <Item sx={{
                         backgroundColor: "black",
                         width: '100%',
@@ -40,7 +39,7 @@ function Comments({ post = {}, loadPost }) {
                         <MyCarouselPost postImages={post?.images} />
                     </Item>
                 </Grid2>
-                <Grid2 xs={4}>
+                <Grid2 xs={4.5}>
                     <Item >
                         <div style={{ backgroundColor: "yellow" }}>
                             <CardPost postData={post} />
@@ -49,8 +48,6 @@ function Comments({ post = {}, loadPost }) {
                 </Grid2>
             </Grid2>
         </Box>
-
-
     )
 }
 

+ 43 - 2
js/Project/project/src/components/redux/action.js

@@ -288,8 +288,7 @@ export const actionPostsCount = (id, promiseName) => actionPromise('PROMISE', pr
 
 
 // Запрос на создание поста
-export const actionCreatePost = params => actionPromise('PROMISE', 'CreatePost', gql(
-  `mutation CreatePost($createNewPost: PostInput){
+export const actionCreatePost = params => actionPromise('PROMISE', 'CreatePost', gql(`mutation CreatePost($createNewPost: PostInput){
   PostUpsert(post: $createNewPost){
     _id
   }
@@ -300,14 +299,56 @@ export const actionCreatePost = params => actionPromise('PROMISE', 'CreatePost',
 
 
 
+// запрос на создание комментария с последующим добавлением его к посту
+export const actionAddComment = params => actionPromise('PROMISE', 'CreateComment', gql(`mutation AddComment($createComment: CommentInput){
+  CommentUpsert(comment: $createComment){
+    _id createdAt text
+  }
+}`, {
+  createComment: params
+}))
 
 
 
 
+// запрос на поиск всех ответов, которые есть у данного комментария
+export const actionFindCommentsAnswerTo = id => actionPromise('PROMISE', 'FindCommentsAnswerTo', gql(`query FindCommentAnswers2($answerTo: String) {
+  CommentFind(query: $answerTo){
+  _id createdAt text likesCount
+    answers{
+      _id
+    }
+    owner{
+      _id login avatar{
+        url
+      }
+    }
+  }
+}`, {
+  answerTo: JSON.stringify([{ 'answerTo._id': id }])
+}))
 
 
 
 
+// запрос на поиск всех комментариев, которые есть у поста
+export const actionFindCommentsPostOne = id => actionPromise('PROMISE', 'FindComments', gql(`query FindCommentsToPost($commentsToPost: String) {
+  CommentFind(query: $commentsToPost){
+  _id createdAt text likesCount
+    answerTo{
+      _id
+    }
+    owner{
+      _id login avatar{
+        url
+      }
+    }
+  }
+}`, {
+  commentsToPost: JSON.stringify([{ 'post._id': id }, { sort: [{ _id: -1 }] }])
+}))
+
+
 
 
 

+ 14 - 1
js/Project/project/src/components/redux/thunks.js

@@ -10,7 +10,8 @@ import {
     actionPostsCount,
     actionFeedFindOne,
     actionCreatePost,
-    actionFindPostOne
+    actionFindPostOne,
+    actionFindCommentsPostOne
 } from "./action"
 
 
@@ -154,4 +155,16 @@ export const actionFullCreatePost = (params) =>
 
 
 
+// Загрузка всех комментариев к посту с последующей их сортировкой и построением дерева комментариве
+export const actionFullFindCommentsPostOne = id =>
+    async dispatch => {
+        const comments = await dispatch(actionFindCommentsPostOne(id))
+
+        // console.log('comments: ', comments)
+
+        // const res = commentsTreeConstructor(comments)
 
+        // console.log('result: ', res)
+
+        // return res
+    }