Browse Source

28.03.2023 14:00

Volddemar4ik 1 year ago
parent
commit
8885bd40f6

+ 153 - 8
js/Project/project/src/App.js

@@ -1,4 +1,118 @@
-import React, { useEffect, useState } from 'react'
+// import React, { useEffect, useState } from 'react'
+// import { Router, Route, Redirect, withRouter, Switch } from 'react-router-dom';
+// import { Provider, useSelector } from 'react-redux';
+// import { store } from './components/redux/index';
+// import createHistory from "history/createBrowserHistory";
+
+// import './App.css';
+// // import logo from './logo.svg';
+
+// // импорт страниц
+// import { CUser } from './components/user';
+// import { CFeed } from './components/feed';
+// import { CComments } from './components/post';
+// import { CreatePost } from './components/create_post';
+// import AuthReg from './components/auth_reg';
+// // import Header from './components/structure/header';
+// import { CHeader } from './components/structure/header';
+// import Footer from './components/structure/footer';
+// import Search from './components/search';
+// import Page404 from './components/404/page404';
+
+// // url проекта
+// export const url = 'http://hipstagram.node.ed.asmer.org.ua/'
+
+
+// const history = createHistory()
+
+
+// // Приватный роутинг - удалить, если не буду использовать
+
+// {
+//     // фейковый авторизатор
+//     const fakeAuth = {
+//         isAuthenticated: false,
+//         authenticate(cb) {
+//             this.isAuthenticated = true
+//             setTimeout(cb, 100)
+//         },
+//         signout(cb) {
+//             this.isAuthenticated = false
+//             setTimeout(cb, 100)
+//         }
+//     }
+
+
+
+//     // кнопка разлогина, которая рисуется, если залогинен
+//     const AuthButton = withRouter(({ history }) => (
+//         fakeAuth.isAuthenticated && (
+//             <p>
+//                 Welcome! <button onClick={() => {
+//                     fakeAuth.signout(() => history.push('/'))
+//                 }}>Sign out</button>
+//             </p>
+//         )
+//     ))
+
+//     const PrivateRoute = ({ component: Component, ...rest }) => (
+//         <Route {...rest} render={(props) => (
+//             typeof localStorage.authToken === 'string'
+//                 ? <Component {...props} />
+//                 : <Redirect to={{
+//                     pathname: '/authorization',
+//                     state: { from: props.location }
+//                 }} />
+//         )} />
+//     )
+
+
+// }
+
+// // роутинг в зависимости от того.залогинен пользователь или нет
+// const MainRoutes = () => {
+//     const currentState = useSelector(state => state?.auth?.token)
+
+//     return (
+//         <main style={{ flexGrow: '1' }}>
+//             {currentState
+//                 ? <Switch>
+//                     <Route path="/" component={CFeed} exact />
+//                     <Route path="/post/:postId" component={CComments} />
+//                     <Route path="/user/:userId" component={CUser} />
+//                     <Route path="/createpost" component={CreatePost} />
+//                     <Route path='/search' component={Search} />
+//                     <Route path="*" component={Page404} />
+//                 </Switch>
+//                 : <Switch>
+//                     <Route path="/" component={AuthReg} exact />
+//                     <Route path="/registration" component={AuthReg} />
+//                     <Route path="*" component={Page404} />
+//                 </Switch>
+//             }
+//         </main>
+//     )
+// }
+
+
+// export default function App() {
+//     return (
+//         <Provider store={store}>
+//             <Router history={history}>
+//                 <div className="wrapper">
+//                     <CHeader />
+//                     <MainRoutes />
+//                     <Footer />
+//                 </div>
+//             </Router>
+//         </Provider>
+
+//     )
+// }
+
+
+
+import React, { createContext, useContext, useEffect, useState } from 'react'
 import { Router, Route, Redirect, withRouter, Switch } from 'react-router-dom';
 import { Provider, useSelector } from 'react-redux';
 import { store } from './components/redux/index';
@@ -22,10 +136,14 @@ import Page404 from './components/404/page404';
 // url проекта
 export const url = 'http://hipstagram.node.ed.asmer.org.ua/'
 
-
 const history = createHistory()
 
 
+// общий контекст для модального окна
+export const ModalForCountsContext = createContext()
+export const UpdateProfile = createContext()
+
+
 // Приватный роутинг - удалить, если не буду использовать
 
 {
@@ -73,22 +191,49 @@ const history = createHistory()
 const MainRoutes = () => {
     const currentState = useSelector(state => state?.auth?.token)
 
+    // функции управления открытием/закрытием модального окна
+    const [modalName, setModalName] = useState('')
+    const [modalArray, setModalArray] = useState([])
+    const [openModal, setOpenModal] = useState(false);
+    const handleOpenModal = (param) => {
+        setOpenModal(true)
+        param.arr && setModalArray([...param.arr]) // идет проверка на null, из-за баги на беке?
+        setModalName(param.name)
+    }
+    const handleCloseModal = () => {
+        setOpenModal(false)
+        setModalArray([])
+    }
+
+
+    const aboutMe = useSelector(state => state?.promise?.AboutMe?.payload)
+    const myFollowings = aboutMe?.following.map(item => {
+        return { _id: item._id }
+    })
+
+    // функция управления моими данными для обновления профиля
+    const [updateProfile, setUpdateProfile] = useState({ _id: aboutMe?._id, login: aboutMe?.login, nick: aboutMe?.nick, avatar: { _id: aboutMe?.avatar?._id }, following: myFollowings })
+    // console.log('updateProfile: ', updateProfile)
+
+
     return (
         <main style={{ flexGrow: '1' }}>
             {currentState
                 ? <Switch>
-                    <Route path="/" component={CFeed} exact />
-                    <Route path="/post/:postId" component={CComments} />
-                    <Route path="/user/:userId" component={CUser} />
+                    <UpdateProfile.Provider value={[updateProfile, setUpdateProfile]}>
+                        <ModalForCountsContext.Provider value={[modalName, setModalName, modalArray, setModalArray, openModal, setOpenModal, handleOpenModal, handleCloseModal]}>
+                            <Route path="/" component={CFeed} exact />
+                            <Route path="/post/:postId" component={CComments} />
+                            <Route path="/user/:userId" component={CUser} />
+                        </ModalForCountsContext.Provider>
+                        <Route path='/search' component={Search} />
+                    </UpdateProfile.Provider>
                     <Route path="/createpost" component={CreatePost} />
-                    <Route path='/search' component={Search} />
                     <Route path="*" component={Page404} />
                 </Switch>
                 : <Switch>
                     <Route path="/" component={AuthReg} exact />
                     <Route path="/registration" component={AuthReg} />
-                    {/* <Route path="/post/:postId" component={CComments} /> */}
-                    {/* <Route path="/user/:userId" component={CUser} /> */}
                     <Route path="*" component={Page404} />
                 </Switch>
             }

+ 209 - 69
js/Project/project/src/components/feed/aboutMe.js

@@ -1,9 +1,33 @@
-// import { Avatar, Typography, Box, Stack, CardHeader } from '@mui/material'
+// import React, { useState } from 'react';
+// import { Avatar, Typography, Box, Stack, CardHeader, Backdrop, Modal, Fade, Divider, IconButton } from '@mui/material'
+// import { Close } from '@mui/icons-material'
 // import { useSelector, connect } from 'react-redux'
 // import { useHistory } from 'react-router-dom'
 
+// import { RecommendedCard } from './recommended';
+
+// import './style.scss'
+
 // import { url } from "../../App"
 
+
+// const style = {
+//     position: 'absolute',
+//     top: '50%',
+//     left: '50%',
+//     transform: 'translate(-50%, -50%)',
+//     width: 400,
+//     height: 'fit-content',
+//     bgcolor: 'background.paper',
+//     boxShadow: 24,
+//     outline: 0,
+//     borderRadius: 3,
+//     padding: '5px 0'
+// };
+
+
+
+
 // function AboutMe({ aboutMe = {} }) {
 //     let history = useHistory()
 
@@ -13,6 +37,18 @@
 //         history.push(`/user/${aboutMe?._id}`)
 //     }
 
+//     // функции управления открытием/закрытием модального окна
+//     const [modalName, setModalName] = useState('')
+//     const [modalArray, setModalArray] = useState([])
+//     const [openModal, setOpenModal] = useState(false);
+//     const handleOpenModal = (param) => {
+//         setOpenModal(true)
+//         setModalArray([...param.arr])
+//         setModalName(param.name)
+//     }
+
+//     const handleCloseModal = () => setOpenModal(false);
+
 //     return (
 //         <Box sx={{
 //             maxWidth: 400
@@ -46,19 +82,93 @@
 //                 direction="row"
 //                 spacing={1}
 //                 padding={2}>
-//                 <Typography>
+//                 <Typography
+//                     sx={{
+//                         cursor: 'pointer'
+//                     }}
+//                     onClick={toMyAccount}
+//                 >
 //                     {myPostsCount || '0'} публикаций
 //                 </Typography>
-//                 <Typography>
+//                 <Typography
+//                     sx={{
+//                         cursor: 'pointer'
+//                     }}
+//                     onClick={() => handleOpenModal({ arr: aboutMe?.followers, name: 'Ваши подписчики' })}
+//                 >
 //                     {aboutMe?.followers?.length || '0'} подписчиков
 //                 </Typography>
-//                 <Typography>
+//                 <Typography
+//                     sx={{
+//                         cursor: 'pointer'
+//                     }}
+//                     onClick={() => handleOpenModal({ arr: aboutMe?.following, name: 'Ваши подписки' })}
+//                 >
 //                     {aboutMe?.following?.length || '0'} подписок
 //                 </Typography>
 //             </Stack>
 
-//             {/* вот тут можно добавить список всех юзеров, которые есть в базе: аватар+логин+кнопка подписаться/отписаться */}
-
+//             {modalArray && <Modal
+//                 aria-labelledby="transition-modal-title"
+//                 aria-describedby="transition-modal-description"
+//                 open={openModal}
+//                 onClose={handleCloseModal}
+//                 closeAfterTransition
+//                 slots={{ backdrop: Backdrop }}
+//                 slotProps={{
+//                     backdrop: {
+//                         timeout: 500,
+//                     },
+//                 }}
+//             >
+//                 <Fade in={openModal}>
+//                     <Box sx={style}>
+//                         <Stack
+//                             direction="row"
+//                             justifyContent="space-between"
+//                             alignItems="center"
+//                             sx={{
+//                                 padding: '0 24px'
+//                             }}>
+//                             <Typography
+//                                 variant="subtitle1"
+//                                 color='text.primary'
+//                                 gutterBottom
+//                             >
+//                                 {modalName}
+//                             </Typography>
+
+//                             <IconButton
+//                                 onClick={handleCloseModal}
+//                                 title='Закрыть'
+//                             >
+//                                 <Close
+//                                     sx={{
+//                                         position: 'absolute',
+//                                         color: 'black'
+//                                     }}
+//                                     fontSize='medium'
+//                                 />
+//                             </IconButton>
+//                         </Stack>
+
+//                         <Divider />
+
+//                         <Box
+//                             className='recommendedBox'
+//                             sx={{
+//                                 margin: '8px 0',
+//                                 width: '95%',
+//                                 paddingLeft: '8px',
+//                                 minHeight: 'fit-content',
+//                                 maxHeight: 350,
+//                                 overflowY: 'auto'
+//                             }}>
+//                             {modalArray.map(item => <RecommendedCard key={item._id} data={item} />)}
+//                         </Box>
+//                     </Box>
+//                 </Fade>
+//             </Modal>}
 //         </Box>
 
 //     )
@@ -68,16 +178,22 @@
 
 
 
-import { Avatar, Typography, Box, Stack, CardHeader } from '@mui/material'
+
+
+
+
+
+
+
+import React, { useContext } from 'react';
+import { Avatar, Typography, Box, Stack, CardHeader, Backdrop, Modal, Fade, Divider, IconButton } from '@mui/material'
+import { Close } from '@mui/icons-material'
 import { useSelector, connect } from 'react-redux'
 import { useHistory } from 'react-router-dom'
-import React, { useState } from 'react';
-
-import Backdrop from '@mui/material/Backdrop';
-import Modal from '@mui/material/Modal';
-import Fade from '@mui/material/Fade';
 
 import { RecommendedCard } from './recommended';
+import { ModalWindow } from '../structure/modal';
+import { ModalForCountsContext } from "../../App";
 
 import './style.scss'
 
@@ -90,12 +206,12 @@ const style = {
     left: '50%',
     transform: 'translate(-50%, -50%)',
     width: 400,
-    height: 'auto',
+    height: 'fit-content',
     bgcolor: 'background.paper',
     boxShadow: 24,
-    p: 4,
     outline: 0,
-    borderRadius: 1.5
+    borderRadius: 3,
+    padding: '5px 0'
 };
 
 
@@ -110,17 +226,20 @@ function AboutMe({ aboutMe = {} }) {
         history.push(`/user/${aboutMe?._id}`)
     }
 
-    // функции управления открытием/закрытием модального окна
-    const [modalName, setModalName] = useState('')
-    const [modalArray, setModalArray] = useState([])
-    const [open, setOpen] = useState(false);
-    const handleOpen = (param) => {
-        setOpen(true)
-        setModalArray([...param.arr])
-        setModalName(param.name)
-    }
+    // // функции управления открытием/закрытием модального окна
+    // const [modalName, setModalName] = useState('')
+    // const [modalArray, setModalArray] = useState([])
+    // const [openModal, setOpenModal] = useState(false);
+    // const handleOpenModal = (param) => {
+    //     setOpenModal(true)
+    //     setModalArray([...param.arr])
+    //     setModalName(param.name)
+    // }
 
-    const handleClose = () => setOpen(false);
+    // const handleCloseModal = () => setOpenModal(false);
+
+    // контекст модального окна
+    const [modalName, setModalName, modalArray, setModalArray, openModal, setOpenModal, handleOpenModal, handleCloseModal] = useContext(ModalForCountsContext)
 
     return (
         <Box sx={{
@@ -167,7 +286,7 @@ function AboutMe({ aboutMe = {} }) {
                     sx={{
                         cursor: 'pointer'
                     }}
-                    onClick={() => handleOpen({ arr: aboutMe?.followers, name: 'подписчики' })}
+                    onClick={() => handleOpenModal({ arr: aboutMe?.followers, name: 'Ваши подписчики' })}
                 >
                     {aboutMe?.followers?.length || '0'} подписчиков
                 </Typography>
@@ -175,54 +294,75 @@ function AboutMe({ aboutMe = {} }) {
                     sx={{
                         cursor: 'pointer'
                     }}
-                    onClick={() => handleOpen({ arr: aboutMe?.following, name: 'подписки' })}
+                    onClick={() => handleOpenModal({ arr: aboutMe?.following, name: 'Ваши подписки' })}
                 >
                     {aboutMe?.following?.length || '0'} подписок
                 </Typography>
             </Stack>
 
-            {modalArray && <Modal
-                aria-labelledby="transition-modal-title"
-                aria-describedby="transition-modal-description"
-                open={open}
-                onClose={handleClose}
-                closeAfterTransition
-                slots={{ backdrop: Backdrop }}
-                slotProps={{
-                    backdrop: {
-                        timeout: 500,
-                    },
-                }}
-            >
-                <Fade in={open}>
-                    <Box sx={style}>
-                        <Box sx={{
-                            padding: '0 24px'
-                        }}>
-                            <Typography
-                                variant="subtitle1"
-                                color='text.secondary'
-                                gutterBottom
-                            >
-                                Ваши {modalName}
-                            </Typography>
-                        </Box>
-
-                        <Box
-                            className='recommendedBox'
-
-                            sx={{
-                                margin: '8px 0',
-                                width: '95%',
-                                paddingLeft: '8px',
-                                height: '450px',
-                                overflowY: 'auto'
-                            }}>
-                            {modalArray.map(item => <RecommendedCard key={item._id} data={item} />)}
-                        </Box>
-                    </Box>
-                </Fade>
-            </Modal>}
+            {modalArray && <ModalWindow />
+                //     <ModalWindow
+                //     aria-labelledby="transition-modal-title"
+                //     aria-describedby="transition-modal-description"
+                //     open={openModal}
+                //     onClose={handleCloseModal}
+                //     closeAfterTransition
+                //     slots={{ backdrop: Backdrop }}
+                //     slotProps={{
+                //         backdrop: {
+                //             timeout: 500,
+                //         },
+                //     }}
+                // >
+                //     <Fade in={openModal}>
+                //         <Box sx={style}>
+                //             <Stack
+                //                 direction="row"
+                //                 justifyContent="space-between"
+                //                 alignItems="center"
+                //                 sx={{
+                //                     padding: '0 24px'
+                //                 }}>
+                //                 <Typography
+                //                     variant="subtitle1"
+                //                     color='text.primary'
+                //                     gutterBottom
+                //                 >
+                //                     {modalName}
+                //                 </Typography>
+
+                //                 <IconButton
+                //                     onClick={handleCloseModal}
+                //                     title='Закрыть'
+                //                 >
+                //                     <Close
+                //                         sx={{
+                //                             position: 'absolute',
+                //                             color: 'black'
+                //                         }}
+                //                         fontSize='medium'
+                //                     />
+                //                 </IconButton>
+                //             </Stack>
+
+                //             <Divider />
+
+                //             <Box
+                //                 className='recommendedBox'
+                //                 sx={{
+                //                     margin: '8px 0',
+                //                     width: '95%',
+                //                     paddingLeft: '8px',
+                //                     minHeight: 'fit-content',
+                //                     maxHeight: 350,
+                //                     overflowY: 'auto'
+                //                 }}>
+                //                 {modalArray.map(item => <RecommendedCard key={item._id} data={item} />)}
+                //             </Box>
+                //         </Box>
+                //     </Fade>
+                // </ModalWindow>
+            }
         </Box>
 
     )

+ 2 - 1
js/Project/project/src/components/feed/card_feed.js

@@ -8,6 +8,7 @@ import { MyCarousel } from './carousel_feed';
 import { url } from '../../App';
 
 export function CardFeed({ postData }) {
+    // console.log('postData: ', postData)
     const history = useHistory()
 
     // формируем дату поста
@@ -116,7 +117,7 @@ export function CardFeed({ postData }) {
             </CardActions>
 
             <CardActions>
-                Нравится: {postData?.likesCount || '0'}
+                Нравится: {postData?.likes?.length || '0'}
             </CardActions>
 
             <CardContent>

+ 5 - 5
js/Project/project/src/components/feed/index.js

@@ -28,11 +28,11 @@ function Feed({ feed, loadFeed }) {
 
     const newPosts = useSelector(state => state.feed?.AddFeed?.payload)
 
-    useEffect((() => {
-        if (newPosts) {
-            setPosts([...posts, ...newPosts])
-        }
-    }), [newPosts])
+    // useEffect((() => {
+    //     if (newPosts) {
+    //         setPosts([...posts, ...newPosts])
+    //     }
+    // }), [newPosts])
 
     // чекер дна страницы
     window.onscroll = async function feedScroll() {

+ 2 - 2
js/Project/project/src/components/feed/recommended.js

@@ -78,7 +78,7 @@ function Recommended() {
             !myFollowings.some((current) => current._id === item._id)
         )
 
-        const random = 15
+        const random = 10
         // теперь оставляем в массиве только random рандомных элементов элементов
         for (let i = 0; i < random; i++) {
             const randomIndex = Math.floor(Math.random() * joinArr.length)
@@ -113,7 +113,7 @@ function Recommended() {
                     margin: '8px 0',
                     width: '95%',
                     paddingLeft: '8px',
-                    height: '450px',
+                    height: '300px',
                     overflowY: 'auto'
                 }}>
                 {recommendedList && recommendedList.map(item => <RecommendedCard key={item._id} data={item} />)}

+ 7 - 0
js/Project/project/src/components/feed/style.scss

@@ -5,6 +5,13 @@
     }
 }
 
+.recommendedBox {
+    .css-185gdzj-MuiCardHeader-root {
+        padding: 8px;
+        padding-left: 16px;
+    }
+}
+
 .recommendedBox::-webkit-scrollbar {
     width: 8px;
 }

+ 4 - 2
js/Project/project/src/components/post/carousel.js

@@ -23,8 +23,11 @@ export function MyCarouselPost({ postImages }) {
             className='myCarousel'
 
             sx={{
+                // flexDirection: 'column',
+                // flex: '1 1 auto',
                 width: '100%',
-                height: '100%'
+                height: '100%',
+
             }}
 
         >
@@ -49,7 +52,6 @@ export function MyCarouselPost({ postImages }) {
                     <Box sx={{
                         width: '100%',
                         height: '743px',
-                        maxHeight: '100%',
                         overflow: 'hidden',
                         position: 'relative'
                     }}

+ 516 - 91
js/Project/project/src/components/post/comments.js

@@ -1,6 +1,346 @@
+// import { url } from "../../App";
+// import { useHistory, useParams } from "react-router-dom";
+// import { createContext, useState, useContext } from "react";
+
+// import './style.scss'
+
+// import {
+//     Card,
+//     CardHeader,
+//     CardContent,
+//     CardActions,
+//     Avatar,
+//     IconButton,
+//     Typography,
+//     Box,
+//     Divider,
+//     Popover,
+//     Tooltip
+// } from '@mui/material'
+
+// import {
+//     FavoriteBorderRounded,
+//     SendRounded,
+//     ChatBubbleOutline,
+//     TurnedInNot,
+// } from '@mui/icons-material/'
+
+// import PopupState, { bindTrigger, bindPopover } from 'material-ui-popup-state';
+
+// import { actionFullAddLike, actionFullDeleteLike } from "../redux/thunks";
+
+// import Grid from '@mui/material/Unstable_Grid2';
+
+// import { ModalForCountsContext } from "../../App";
+
+// import CCommentsFeed from "./comments_feed";
+// import CommentField from "./comments_add_field";
+// import { ModalWindow } from "../structure/modal";
+// import { useDispatch } from "react-redux";
+
+// // контекст для управления состоянием данных для отправки комментов
+// export const CommentContext = createContext()
+
+
+// export function CardPost({ postData }) {
+//     // console.log('postData: ', postData)
+
+//     const dispatch = useDispatch()
+
+//     const history = useHistory()
+//     const { postId } = useParams()
+
+//     // отслеживаем состояние поля ввода комментария для поста
+//     const [comment, setComment] = useState({ text: '', post: { _id: postId } })
+
+//     // отслеживаем, к какой именно сущности будет добавляться лайк
+//     const [like, setLike] = useState({})
+
+//     // контекст модального окна
+//     const [modalName, setModalName, modalArray, setModalArray, openModal, setOpenModal, handleOpenModal, handleCloseModal] = useContext(ModalForCountsContext)
+
+//     // дата поста
+//     const dateofPost = new Date(+postData?.createdAt)
+//     const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
+//     const dateofPostParse = `${dateofPost.getDate() < 10 ? '0' + dateofPost.getDate() : dateofPost.getDate()}
+//     ${months[dateofPost.getMonth()]}
+//     ${dateofPost.getFullYear()}
+//     ${dateofPost.getHours()}:${dateofPost.getMinutes() < 10 ? '0' + dateofPost.getMinutes() : dateofPost.getMinutes()}`
+
+//     // Переход на профиль пользователя
+//     function toAccount() {
+//         history.push(`/user/${postData?.owner?._id}`)
+//     }
+
+//     // перевод фокуса на строку добавления комментария при клике на иконку комментария
+//     function addCommentFocus() {
+//         document.getElementById('addCommentField').focus()
+//     }
+
+//     // отслеживание состояния текста для ToolTips
+//     const [toolTipText, setToolTipText] = useState(true)
+//     let text = toolTipText ? 'Нажмите для копирования' : 'Ссылка скопирована в буфер обмена'
+
+//     // функция копирования ссылки на пост
+//     function copyShareLink() {
+//         // получаем урл текущей страницы
+//         const postUrl = window.location.href
+//         navigator.clipboard.writeText(postUrl)
+
+//         setToolTipText(!toolTipText)
+//         setTimeout(() => setToolTipText(toolTipText), 2000)
+//     }
+
+//     // функция отображения всех, кому понравился пост
+//     // function showLikesOwner() {
+//     //     console.log('покажи нас')
+//     // }
+
+
+//     // функия добавления лайков
+//     function addLike(params) {
+//         dispatch(actionFullAddLike(params))
+//     }
+
+
+
+
+//     return (
+//         <CommentContext.Provider value={[comment, setComment]}>
+//             <Card
+//                 sx={{
+//                     display: 'flex',
+//                     flexDirection: 'column',
+//                     minHeight: '80vh',
+//                     borderRadius: 0,
+//                     height: '100%',
+//                     maxHeight: 450,
+//                 }}
+//             >
+//                 <CardHeader
+//                     avatar={
+//                         <Avatar
+//                             alt={postData?.owner?.login}
+//                             src={(url + postData?.owner?.avatar?.url)}
+//                             sx={{
+//                                 width: 50,
+//                                 height: 50
+//                             }}
+//                         />
+//                     }
+
+//                     title={
+//                         <Typography
+//                             sx={{
+//                                 cursor: 'pointer'
+//                             }}
+//                             onClick={toAccount}
+//                         >
+//                             {postData?.owner?.login}
+//                         </Typography>
+//                     }
+
+//                     subheader={dateofPostParse}
+//                 />
+
+//                 <Divider />
+
+//                 <CardContent
+//                     className='post-comments'
+
+//                     sx={{
+//                         // flex: '0 0 450px',
+//                         flex: '1 1 auto',
+//                         overflowY: 'auto',
+//                     }}
+//                 >
+//                     <Grid
+//                         container
+//                         spacing={2}
+//                         sx={{
+//                             marginBottom: 3
+//                         }}
+//                     >
+//                         <Grid
+//                             xs={2}
+//                             sx={{
+//                                 flex: '0 0 45px'
+//                             }}
+//                         >
+//                             <Avatar
+//                                 alt={postData?.owner?.login}
+//                                 src={(url + postData?.owner?.avatar?.url)}
+//                                 sx={{
+//                                     width: 40,
+//                                     height: 40
+//                                 }}
+//                             />
+//                         </Grid>
+
+//                         <Grid
+//                             xs={10}
+//                         >
+//                             <Typography
+//                                 variant="subtitle2"
+//                                 color="text.secondary"
+//                                 sx={{
+//                                     cursor: 'pointer',
+//                                     width: 'fit-content'
+//                                 }}
+//                                 onClick={toAccount}
+//                             >
+//                                 {postData?.owner?.login}
+//                             </Typography>
+
+//                             <Typography
+//                                 variant="subtitle2"
+//                                 color="text.primary"
+//                             >
+//                                 {postData?.title}
+//                             </Typography>
+
+//                             <Typography
+//                                 variant="body2"
+//                                 color="text.secondary"
+//                             >
+//                                 {postData?.text}
+//                             </Typography>
+//                         </Grid>
+//                     </Grid>
+
+//                     <Grid>
+//                         <CCommentsFeed />
+//                     </Grid>
+//                 </CardContent>
+
+//                 <Divider />
+
+//                 <Box>
+//                     <CardActions disableSpacing>
+//                         <Box
+//                             sx={{
+//                                 flexGrow: 1
+//                             }}>
+//                             <Grid
+//                                 xs={12}
+//                                 container
+//                                 justifyContent="space-between"
+//                                 alignItems="center"
+//                                 sx={{
+//                                     fontSize: '12px'
+//                                 }}
+//                             >
+//                                 <Grid container>
+//                                     <Grid>
+//                                         <IconButton
+//                                             aria-label="add to favorites"
+//                                             onClick={() => addLike({ post: { _id: postData?._id } })}
+//                                         >
+//                                             <FavoriteBorderRounded />
+//                                         </IconButton>
+//                                     </Grid>
+
+//                                     <Grid>
+//                                         <IconButton
+//                                             onClick={addCommentFocus}
+//                                         >
+//                                             <ChatBubbleOutline />
+//                                         </IconButton>
+//                                     </Grid>
+
+//                                     <Grid>
+//                                         <PopupState variant="popover" popupId="demo-popup-popover">
+//                                             {(popupState) => (
+//                                                 <div>
+//                                                     <IconButton
+//                                                         aria-label="share"
+//                                                         {...bindTrigger(popupState)}
+//                                                     >
+//                                                         <SendRounded
+//                                                             style={{ transform: 'translate(3px, -4px) rotate(-30deg)' }}
+//                                                         />
+//                                                     </IconButton>
+//                                                     <Popover
+//                                                         {...bindPopover(popupState)}
+//                                                         anchorOrigin={{
+//                                                             vertical: 'center',
+//                                                             horizontal: 'right',
+//                                                         }}
+//                                                         transformOrigin={{
+//                                                             vertical: 'center',
+//                                                             horizontal: 'left',
+//                                                         }}
+//                                                     >
+//                                                         <Tooltip title={text} placement='bottom-start'>
+//                                                             <Typography
+//                                                                 sx={{ p: 2 }}
+//                                                                 onClick={copyShareLink}
+//                                                             >
+//                                                                 {window.location.href}
+//                                                             </Typography>
+//                                                         </Tooltip>
+//                                                     </Popover>
+//                                                 </div>
+//                                             )}
+//                                         </PopupState>
+//                                     </Grid>
+//                                 </Grid>
+
+//                                 <Grid>
+//                                     <IconButton>
+//                                         <TurnedInNot />
+//                                     </IconButton>
+//                                 </Grid>
+//                             </Grid>
+
+//                             <Grid container>
+//                                 <Typography
+//                                     variant="subtitle1"
+//                                     color="text.secondary"
+//                                     sx={{
+//                                         padding: 1,
+//                                         cursor: 'pointer'
+//                                     }}
+//                                     // onClick={showLikesOwner}
+//                                     onClick={() => handleOpenModal({ arr: postData?.likes, name: 'Отметки "Нравится"' })}
+//                                 >
+//                                     Нравится: {postData?.likes?.length || '0'}
+//                                 </Typography>
+//                             </Grid>
+//                         </Box>
+
+//                         {modalArray && <ModalWindow />}
+//                     </CardActions>
+
+//                     <Divider />
+
+//                     <CardActions>
+//                         <CommentField />
+//                     </CardActions>
+//                 </Box>
+//             </Card>
+//         </CommentContext.Provider >
+//     )
+// }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 import { url } from "../../App";
 import { useHistory, useParams } from "react-router-dom";
-import { createContext, useState } from "react";
+import { createContext, useState, useContext, useEffect } from "react";
 
 import './style.scss'
 
@@ -15,11 +355,13 @@ import {
     Box,
     Divider,
     Popover,
-    Tooltip
+    Tooltip,
+    Checkbox
 } from '@mui/material'
 
 import {
     FavoriteBorderRounded,
+    FavoriteRounded,
     SendRounded,
     ChatBubbleOutline,
     TurnedInNot,
@@ -27,10 +369,16 @@ import {
 
 import PopupState, { bindTrigger, bindPopover } from 'material-ui-popup-state';
 
+import { actionFullAddLike, actionFullDeleteLike } from "../redux/thunks";
+
 import Grid from '@mui/material/Unstable_Grid2';
 
+import { ModalForCountsContext, UpdateProfile } from "../../App";
+
 import CCommentsFeed from "./comments_feed";
-import CommentField from "./comment_field";
+import CommentField from "./comments_add_field";
+import { ModalWindow } from "../structure/modal";
+import { useDispatch, useSelector } from "react-redux";
 
 // контекст для управления состоянием данных для отправки комментов
 export const CommentContext = createContext()
@@ -39,14 +387,22 @@ export const CommentContext = createContext()
 export function CardPost({ postData }) {
     // console.log('postData: ', postData)
 
+    const dispatch = useDispatch()
+
     const history = useHistory()
     const { postId } = useParams()
 
     // отслеживаем состояние поля ввода комментария для поста
     const [comment, setComment] = useState({ text: '', post: { _id: postId } })
 
+    // контекст модального окна
+    const [modalName, setModalName, modalArray, setModalArray, openModal, setOpenModal, handleOpenModal, handleCloseModal] = useContext(ModalForCountsContext)
+
+    // контекст обновления профиля
+    const [updateProfile, setUpdateProfile] = useContext(UpdateProfile)
+
     // дата поста
-    const dateofPost = new Date(+postData.createdAt)
+    const dateofPost = new Date(+postData?.createdAt)
     const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
     const dateofPostParse = `${dateofPost.getDate() < 10 ? '0' + dateofPost.getDate() : dateofPost.getDate()} 
     ${months[dateofPost.getMonth()]} 
@@ -63,7 +419,7 @@ export function CardPost({ postData }) {
         document.getElementById('addCommentField').focus()
     }
 
-    // отслеживание состояния текста для ToolTips
+    // отслеживание состояния текста для ToolTips "поделиться ссылкой"
     const [toolTipText, setToolTipText] = useState(true)
     let text = toolTipText ? 'Нажмите для копирования' : 'Ссылка скопирована в буфер обмена'
 
@@ -71,13 +427,50 @@ export function CardPost({ postData }) {
     function copyShareLink() {
         // получаем урл текущей страницы
         const postUrl = window.location.href
+        // копируем полученный урл в буфер
         navigator.clipboard.writeText(postUrl)
 
+        // меняем текст тултипа и через 2сек возрващаем на место
         setToolTipText(!toolTipText)
         setTimeout(() => setToolTipText(toolTipText), 2000)
     }
 
 
+    // ============= функция отображения лайка (старт) =========================
+    // чекаем мой ид
+    const myId = useSelector(state => state?.auth?.payload?.sub?.id)
+
+    // картинка лайка включить/отключить
+    let isLike = false
+    const [checked, setChecked] = useState(isLike)
+
+    const handleChange = (event) => {
+        setChecked(event.target.checked)
+    }
+
+    // перебираем список всех лайков и сравниваем с моим ид
+    let likeId = ''
+    postData?.likes?.some(item => {
+        if (item?.owner?._id === myId) {
+            isLike = true
+            likeId = item._id
+
+            return true
+        }
+    })
+
+    useEffect(() => setChecked(isLike), [isLike])
+
+
+    function likeAction() {
+        checked
+            ? dispatch(actionFullDeleteLike({ _id: likeId }))
+            : dispatch(actionFullAddLike({ post: { _id: postData?._id } }))
+    }
+    // ============= функция отображения лайка (финиш) =========================
+
+
+
     return (
         <CommentContext.Provider value={[comment, setComment]}>
             <Card
@@ -85,7 +478,9 @@ export function CardPost({ postData }) {
                     display: 'flex',
                     flexDirection: 'column',
                     minHeight: '80vh',
-                    borderRadius: 0
+                    borderRadius: 0,
+                    height: '100%',
+                    maxHeight: 450,
                 }}
             >
                 <CardHeader
@@ -120,7 +515,8 @@ export function CardPost({ postData }) {
                     className='post-comments'
 
                     sx={{
-                        flex: '0 0 450px',
+                        // flex: '0 0 450px',
+                        flex: '1 1 auto',
                         overflowY: 'auto',
                     }}
                 >
@@ -185,102 +581,131 @@ export function CardPost({ postData }) {
 
                 <Divider />
 
-                <CardActions disableSpacing>
-                    <Box
-                        sx={{
-                            flexGrow: 1
-                        }}>
-                        <Grid
-                            xs={12}
-                            container
-                            justifyContent="space-between"
-                            alignItems="center"
+                <Box>
+                    <CardActions disableSpacing>
+                        <Box
                             sx={{
-                                fontSize: '12px'
-                            }}
-                        >
-                            <Grid container>
-                                <Grid>
-                                    <IconButton
-                                        aria-label="add to favorites"
-                                        onClick={() => (console.log('click like main post'))}
-                                    >
-                                        <FavoriteBorderRounded />
-                                    </IconButton>
+                                flexGrow: 1
+                            }}>
+                            <Grid
+                                xs={12}
+                                container
+                                justifyContent="space-between"
+                                alignItems="center"
+                                sx={{
+                                    fontSize: '12px'
+                                }}
+                            >
+                                <Grid container>
+                                    <Grid>
+                                        {/* <IconButton
+                                            aria-label="add to favorites"
+                                            onClick={() => addLike({ post: { _id: postData?._id } })}
+                                        > */}
+                                        {/* <FavoriteBorderRounded /> */}
+
+
+
+                                        <Checkbox
+                                            checked={checked}
+                                            onChange={handleChange}
+                                            inputProps={{ 'aria-label': 'controlled' }}
+                                            icon={<FavoriteBorderRounded />}
+                                            checkedIcon={<FavoriteRounded />}
+                                            onClick={likeAction}
+
+                                            sx={{
+                                                '&.Mui-checked': {
+                                                    color: 'red',
+                                                },
+                                            }}
+                                        />
+
+
+
+
+
+                                        {/* </IconButton> */}
+                                    </Grid>
+
+                                    <Grid>
+                                        <IconButton
+                                            onClick={addCommentFocus}
+                                        >
+                                            <ChatBubbleOutline />
+                                        </IconButton>
+                                    </Grid>
+
+                                    <Grid>
+                                        <PopupState variant="popover" popupId="demo-popup-popover">
+                                            {(popupState) => (
+                                                <div>
+                                                    <IconButton
+                                                        aria-label="share"
+                                                        {...bindTrigger(popupState)}
+                                                    >
+                                                        <SendRounded
+                                                            style={{ transform: 'translate(3px, -4px) rotate(-30deg)' }}
+                                                        />
+                                                    </IconButton>
+                                                    <Popover
+                                                        {...bindPopover(popupState)}
+                                                        anchorOrigin={{
+                                                            vertical: 'center',
+                                                            horizontal: 'right',
+                                                        }}
+                                                        transformOrigin={{
+                                                            vertical: 'center',
+                                                            horizontal: 'left',
+                                                        }}
+                                                    >
+                                                        <Tooltip title={text} placement='bottom-start'>
+                                                            <Typography
+                                                                sx={{ p: 2 }}
+                                                                onClick={copyShareLink}
+                                                            >
+                                                                {window.location.href}
+                                                            </Typography>
+                                                        </Tooltip>
+                                                    </Popover>
+                                                </div>
+                                            )}
+                                        </PopupState>
+                                    </Grid>
                                 </Grid>
 
                                 <Grid>
-                                    <IconButton
-                                        onClick={addCommentFocus}
-                                    >
-                                        <ChatBubbleOutline />
+                                    <IconButton>
+                                        <TurnedInNot />
                                     </IconButton>
                                 </Grid>
-
-                                <Grid>
-                                    <PopupState variant="popover" popupId="demo-popup-popover">
-                                        {(popupState) => (
-                                            <div>
-                                                <IconButton
-                                                    aria-label="share"
-                                                    {...bindTrigger(popupState)}
-                                                >
-                                                    <SendRounded
-                                                        style={{ transform: 'translate(3px, -4px) rotate(-30deg)' }}
-                                                    />
-                                                </IconButton>
-                                                <Popover
-                                                    {...bindPopover(popupState)}
-                                                    anchorOrigin={{
-                                                        vertical: 'center',
-                                                        horizontal: 'right',
-                                                    }}
-                                                    transformOrigin={{
-                                                        vertical: 'center',
-                                                        horizontal: 'left',
-                                                    }}
-                                                >
-                                                    <Tooltip title={text} placement='bottom-start'>
-                                                        <Typography
-                                                            sx={{ p: 2 }}
-                                                            onClick={copyShareLink}
-                                                        >
-                                                            {window.location.href}
-                                                        </Typography>
-                                                    </Tooltip>
-                                                </Popover>
-                                            </div>
-                                        )}
-                                    </PopupState>
-                                </Grid>
                             </Grid>
 
-                            <Grid>
-                                <IconButton>
-                                    <TurnedInNot />
-                                </IconButton>
+                            <Grid container>
+                                <Typography
+                                    variant="subtitle1"
+                                    color="text.secondary"
+                                    sx={{
+                                        padding: 1,
+                                        cursor: 'pointer'
+                                    }}
+                                    // onClick={showLikesOwner}
+                                    onClick={() => handleOpenModal({ arr: postData?.likes, name: 'Отметки "Нравится"' })}
+                                >
+                                    Нравится: {postData?.likes?.length || '0'}
+                                </Typography>
                             </Grid>
-                        </Grid>
+                        </Box>
 
-                        <Grid container>
-                            <Typography
-                                variant="subtitle1"
-                                color="text.secondary"
-                                sx={{
-                                    padding: 1
-                                }}
-                            >
-                                Нравится: {postData.likesCount ? postData.likesCount : '0'}
-                            </Typography>
-                        </Grid>
-                    </Box>
-                </CardActions>
+                        {modalArray && <ModalWindow />}
+                    </CardActions>
 
-                <Divider />
+                    <Divider />
 
-                <CardActions>
-                    <CommentField />
-                </CardActions>
+                    <CardActions>
+                        <CommentField />
+                    </CardActions>
+                </Box>
             </Card>
         </CommentContext.Provider >
     )

+ 1 - 1
js/Project/project/src/components/post/comment_field.js

@@ -66,7 +66,7 @@ function CommentField() {
         // определяем, какое имя дать запросу
         let nameOfPromise = (isInclude && ('answerTo' in comment)) ? 'CreateCommentTo' : 'CreateComment'
 
-        // отправляем запрос на создание комментария с нужным именем
+        // отправляем запрос на создание комментария с нужным именем и параметрами
         dispatch(actionFullAddComment(nameOfPromise, comment, postId))
 
         // и чистим поле ввода комментария после отправки запроса

+ 1 - 1
js/Project/project/src/components/post/comments_feed.js

@@ -5,7 +5,7 @@ import { connect, useSelector } from "react-redux";
 
 import { actionFullFindCommentsPostOne } from "../redux/thunks";
 
-import CommentCard from "./comment_feed_card";
+import CommentCard from "./comments_feed_card";
 
 import './style.scss';
 

+ 15 - 5
js/Project/project/src/components/post/comment_feed_card.js

@@ -12,6 +12,7 @@ import {
 import Grid from '@mui/material/Unstable_Grid2';
 
 import { FavoriteBorderRounded } from '@mui/icons-material/'
+import { ModalForCountsContext } from "../../App";
 
 import './style.scss'
 
@@ -25,8 +26,12 @@ function CommentCard({ data }) {
 
     const history = useHistory()
 
+    // контекст поля ввода комментария
     const [comment, setComment] = useContext(CommentContext)
 
+    // контекст модального окна
+    const [modalName, setModalName, modalArray, setModalArray, openModal, setOpenModal, handleOpenModal, handleCloseModal] = useContext(ModalForCountsContext)
+
     // дата поста
     const dateofPost = new Date(+data?.createdAt)
     const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
@@ -36,7 +41,7 @@ function CommentCard({ data }) {
     ${dateofPost.getHours() < 10 ? '0' + dateofPost.getHours() : dateofPost.getHours()}:${dateofPost.getMinutes() < 10 ? '0' + dateofPost.getMinutes() : dateofPost.getMinutes()}`
 
     // скрываем/открываем вложенные комментарии
-    const [openComments, setOpenComments] = useState('Посмотреть ответы')
+    const [openComments, setOpenComments] = useState(`Показать ответы (${data?.answers.length})`)
     // скрываем/открываем блок с ответами на комментарии
     const [toggleAnswerToBlock, setToggleAnswerToBlock] = useState(false)
 
@@ -44,9 +49,10 @@ function CommentCard({ data }) {
     async function toggleBlock() {
         setToggleAnswerToBlock(!toggleAnswerToBlock)
 
-        return (openComments === 'Посмотреть ответы'
-            ? setOpenComments('Скрыть ответы')
-            : setOpenComments('Посмотреть ответы')
+        return (openComments === (`Показать ответы (${data?.answers.length})`)
+            // ? setOpenComments('Скрыть ответы')
+            ? setOpenComments(`Скрыть ответы (${data?.answers.length})`)
+            : setOpenComments(`Показать ответы (${data?.answers.length})`)
         )
     }
 
@@ -159,11 +165,15 @@ function CommentCard({ data }) {
                     }}
                 >
                     <Typography
+                        sx={{
+                            cursor: 'pointer'
+                        }}
                         variant="caption"
                         color="text.disabled"
                         align='left'
+                        onClick={() => handleOpenModal({ arr: data?.likes, name: 'Отметки "Нравится"' })}
                     >
-                        Нравится: {data?.likesCount || '0'}
+                        Нравится: {data?.likes?.length || '0'}
                     </Typography>
                 </Grid>
 

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

@@ -132,7 +132,13 @@ export const actionFindPostOne = _id => actionPromise('PROMISE', 'PostFindOne',
         _id url
       }
     }
-    
+    likes {
+      _id owner{
+        _id login avatar {
+          _id url
+        }
+      }
+    }
   }
 }`, {
   postOne: JSON.stringify([{ _id }])
@@ -217,7 +223,7 @@ export const actionfindPosts = () => actionPromise('PROMISE', 'PostsFind', gql(`
 //================= вот это тоже нужно будет удалить после тестов =====================
 export const actionFeedFindOne = (arr, sortOne, limitOne, promiseName = 'Feed', skipOne = 0) => actionPromise('FEED', promiseName, gql(`query FeedFindOne ($feedOne: String){
 	PostFind(query: $feedOne){
-            _id createdAt title text likesCount owner{
+            _id createdAt title text owner{
               _id login avatar{
                 url
               }
@@ -227,6 +233,11 @@ export const actionFeedFindOne = (arr, sortOne, limitOne, promiseName = 'Feed',
             }
     images{
       url
+    }
+    likes{
+      _id owner{
+        _id login
+      }
     }
     	}
     }`, {
@@ -269,6 +280,11 @@ export const actionFeedFindOneSkip = (arr, sortOne, skipOne, limitOne, promiseNa
             }
     images{
       url
+    }
+    likes{
+      _id owner{
+        _id login
+      }
     }
     	}
     }`, {
@@ -331,6 +347,8 @@ export const actionFindCommentsAnswerTo = id => actionPromise('PROMISE', 'FindCo
 
 
 
+
+
 // запрос на поиск всех комментариев, которые есть у поста
 export const actionFindCommentsPostOne = id => actionPromise('PROMISE', 'FindComments', gql(`query FindCommentsToPost($commentsToPost: String) {
   CommentFind(query: $commentsToPost){
@@ -343,6 +361,9 @@ export const actionFindCommentsPostOne = id => actionPromise('PROMISE', 'FindCom
         url
       }
     }
+    likes {
+      _id
+    }
   }
 }`, {
   commentsToPost: JSON.stringify([{ 'post._id': id }, { sort: [{ _id: -1 }] }])
@@ -379,6 +400,69 @@ export const actionFindFollowing = arr => actionPromise('PROMISE', 'FindFollowin
 
 
 
+// добавление  лайка к посту/комментарию
+export const actionAddLike = params => actionPromise('PROMISE', 'AddLike', gql(`mutation addLike($addLike: LikeInput){
+  LikeUpsert(like: $addLike){
+    _id
+    post{
+      _id title likes{
+        _id 
+      }
+    }
+    comment{
+      _id text likes{
+        _id 
+      }
+    }
+    owner{
+      _id 
+    }
+  }
+}`, {
+  addLike: params
+}))
+
+
+
+
+
+// удаление лайка с поста/комментария (пример данных: {_id: "6421f0e9cec75c3ebd51bed5"})
+export const actionDeleteLike = params => actionPromise('PROMISE', 'DeleteLike', gql(`mutation deleteLike($deleteLike: LikeInput){
+  LikeDelete(like: $deleteLike){
+    _id post{
+      _id
+    }
+  }
+}`, {
+  deleteLike: params
+}))
+
+
+
+
+
+
+//обновление профил(установка аватара, ник-нейма, логина?, добавления/удаления подписчиков)
+export const actionUpdateProfile = params => actionPromise('PROMISE', 'UpdateProfile', gql(`mutation setAvatar($updateProfile: UserInput){
+    UserUpsert(user: $updateProfile){
+        _id, avatar{
+            _id
+        }
+    }
+}`, {
+  updateProfile: params
+}))
+
+
+
+
+
+
+
+
+
+
+
 
 
 

+ 15 - 13
js/Project/project/src/components/redux/reducers.js

@@ -27,6 +27,21 @@ export function promiseReducer(state = {}, { type, status, payload, error, nameO
 
 
 
+// feedReducer
+export function feedReducer(state = {}, { type, status, payload, error, nameOfPromise }) {
+    if (type === 'FEED') {
+        return {
+            ...state,
+            [nameOfPromise]: { status, payload, error }
+        }
+    }
+    return state
+}
+
+
+
+
+
 // раскодируем JWT-токен
 const jwtDecode = function (token) {
     try {
@@ -61,19 +76,6 @@ export function authReducer(state = {}, { type, token }) {
 
 
 
-// feedReducer
-export function feedReducer(state = {}, { type, status, payload, error, nameOfPromise }) {
-    if (type === 'FEED') {
-        return {
-            ...state,
-            [nameOfPromise]: { status, payload, error }
-        }
-    }
-    return state
-}
-
-
-
 // localStoredReducer, который обрабатывает все наши редьюсеры для разных направлений
 export function localStoredReducer(originalReducer, localStorageKey) {
     function wrapper(state, action) {

+ 52 - 3
js/Project/project/src/components/redux/thunks.js

@@ -14,7 +14,10 @@ import {
     actionFindCommentsPostOne,
     actionAddComment,
     actionFindFollowers,
-    actionFindFollowing
+    actionFindFollowing,
+    actionAddLike,
+    actionDeleteLike,
+    actionUpdateProfile
 } from "./action"
 
 
@@ -194,14 +197,60 @@ export const actionFullFindCommentsPostOne = id =>
 
 
 
-// создание комментария к посту с последующей загрузкой с бека списка всех постов, которые относятся к этой записи
+// создание комментария с последующей загрузкой с бека списка всех постов, которые относятся к этой записи
 export const actionFullAddComment = (nameOfPromise, params, id) =>
     async dispatch => {
         const newComment = await dispatch(actionAddComment(nameOfPromise, params))
 
         if (typeof newComment._id === 'string') {
-            actionFullFindCommentsPostOne(id)
+            dispatch(actionFullFindCommentsPostOne(id))
         }
     }
 
 
+
+
+
+// создание лайка с последующим добавлением к определенной сущности и последующим обновление определенной сущности
+export const actionFullAddLike = params =>
+    async dispatch => {
+        const res = await dispatch(actionAddLike(params))
+
+        // загружаем данные поста с бетка, если лайк был для поста
+        if (res?.post) {
+            dispatch(actionFindPostOne(res?.post?._id))
+        }
+
+        // загружаем данные комментариев для поста с бетка, если лайк был для комментарий
+        if (res?.comment) {
+            dispatch(actionFindPostOne(res.comment._id))
+        }
+    }
+
+
+
+
+
+// удаление лайка с последующим удаление к определенной сущности и последующим обновление определенной сущности
+export const actionFullDeleteLike = params =>
+    async dispatch => {
+        const res = await dispatch(actionDeleteLike(params))
+
+        // при удачном удалении отправляем запрос на обновление данных страницы
+        if (res?._id) {
+            dispatch(actionFindPostOne(res.post._id))
+        }
+    }
+
+
+
+
+
+// запрос на обновление профиля и последующая отправка запрос обо мне на бек
+export const actionFullUpdateProfile = params =>
+    async dispatch => {
+        console.log('params: ', params)
+        // const res = await dispatch(actionUpdateProfile(params))
+
+        // console.log('res: ', res)
+    }

+ 191 - 0
js/Project/project/src/components/structure/modal.js

@@ -0,0 +1,191 @@
+import { useContext } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { useHistory } from "react-router-dom";
+
+import { Typography, Box, Stack, Backdrop, Modal, Fade, Divider, IconButton, Avatar, Button, CardHeader } from '@mui/material'
+import { Close } from '@mui/icons-material'
+
+import { ModalForCountsContext, UpdateProfile } from "../../App";
+import { actionFullUpdateProfile } from "../redux/thunks";
+import { url } from "../../App"
+
+
+const style = {
+    position: 'absolute',
+    top: '50%',
+    left: '50%',
+    transform: 'translate(-50%, -50%)',
+    width: 400,
+    height: 'fit-content',
+    bgcolor: 'background.paper',
+    boxShadow: 24,
+    outline: 0,
+    borderRadius: 3,
+    padding: '5px 0'
+};
+
+
+export function ModalWindow() {
+
+    // контекст модального окна
+    const [modalName, setModalName, modalArray, setModalArray, openModal, setOpenModal, handleOpenModal, handleCloseModal] = useContext(ModalForCountsContext)
+
+
+    return (
+        <div>
+            <Modal
+                aria-labelledby="transition-modal-title"
+                aria-describedby="transition-modal-description"
+                open={openModal}
+                onClose={handleCloseModal}
+                closeAfterTransition
+                slots={{ backdrop: Backdrop }
+                }
+                slotProps={{
+                    backdrop: {
+                        timeout: 500,
+                    },
+                }}
+            >
+                <Fade in={openModal}>
+                    <Box sx={style}>
+                        <Stack
+                            direction="row"
+                            justifyContent="space-between"
+                            alignItems="center"
+                            sx={{
+                                padding: '0 24px'
+                            }}>
+                            <Typography
+                                variant="subtitle1"
+                                color='text.primary'
+                                gutterBottom
+                            >
+                                {modalName}
+                            </Typography>
+
+                            <IconButton
+                                onClick={handleCloseModal}
+                                title='Закрыть'
+                            >
+                                <Close
+                                    sx={{
+                                        position: 'absolute',
+                                        color: 'black'
+                                    }}
+                                    fontSize='medium'
+                                />
+                            </IconButton>
+                        </Stack>
+
+                        <Divider />
+
+                        <Box
+                            className='recommendedBox'
+                            sx={{
+                                margin: '8px 0',
+                                width: '95%',
+                                paddingLeft: '8px',
+                                minHeight: 'fit-content',
+                                maxHeight: 350,
+                                overflowY: 'auto'
+                            }}>
+                            {modalArray.map(item => <RecommendedCard key={item._id} data={item} />)}
+                        </Box>
+                    </Box>
+                </Fade>
+            </Modal >
+        </div>
+    )
+}
+
+
+
+// Компонент карточка юзера с кнопкой подписки/отписки (нужно делать всегда двойную проверку data.owner.id || data.id, потому что у нас разные сущности на лайках и на подписчиках)
+function RecommendedCard({ data }) {
+    console.log('dataIncard: ', data)
+
+    const history = useHistory()
+    const dispatch = useDispatch()
+
+    // контекст обновления профиля
+    const [updateProfile, setUpdateProfile] = useContext(UpdateProfile)
+    console.log('updateProfile: ', updateProfile)
+
+    // проверка, является ли пользователь моим подписчиком
+    const myData = useSelector(state => state?.promise?.AboutMe?.payload)
+    const isFollowing = myData?.following && (myData?.following).some(item => item._id === (data?.owner?._id || data?._id))
+
+    // мой id
+    const myid = myData?._id
+
+    // переход на аккаунт
+    function toAccount() {
+        history.push(data?.owner?._id ? `/user/${data?.owner?._id}` : `/user/${data?._id}`)
+    }
+
+
+    // какого-то хуя не работает((
+    function isSubscribing() {
+        console.log('подписка или отписка при клике на юзера в модальном окне')
+
+        if (isFollowing) {
+
+            console.log('updateProfile START: ', updateProfile)
+
+            setUpdateProfile({ ...updateProfile, following: updateProfile.following.filter(item => item?._id !== data?.owner?._id) })
+
+        } else {
+            setUpdateProfile({ ...updateProfile, following: [...updateProfile.following, { _id: data.owner._id }] })
+        }
+
+        // 
+        console.log('updateProfile END: ', updateProfile)
+        dispatch(actionFullUpdateProfile(updateProfile))
+    }
+
+    return (
+        <CardHeader
+            avatar={
+                <Avatar
+                    src={url + (data?.owner?.avatar?.url || data?.avatar?.url)}
+                    aria-label="recipe"
+                    sx={{ width: 36, height: 36 }}
+                />
+            }
+
+            // action={
+            //     <Button
+            //         variant="text"
+            //         size="small"
+            //         onClick={() => console.log('подписка или отписка при клике на юзера в модальном окне')}
+            //     >
+            //         {isFollowing ? 'Отписаться' : 'Подписаться'}
+            //     </Button>
+            // }
+            action={ //сначала проверка на меня. если не я, рисуем кнопку
+                ((data?.owner?._id || data?._id) != myid) && <Button
+                    variant="text"
+                    size="small"
+                    onClick={isSubscribing}
+                >
+                    {isFollowing ? 'Отписаться' : 'Подписаться'}
+                </Button>
+            }
+
+            title={
+                <Typography
+                    sx={{
+                        cursor: 'pointer',
+                        width: 'fit-content'
+                    }}
+                    variant="subtitle2"
+                    color='text.secondary'
+                    onClick={toAccount}
+                >
+                    {data?.owner?.login || data?.login || 'anon user'}
+                </Typography>
+            }
+        />
+    )
+}