Browse Source

01.04.2023 04:00

Volddemar4ik 1 year ago
parent
commit
34669ff2de

+ 1 - 1
js/Project/project/src/components/create_post/dnd.js

@@ -42,7 +42,7 @@ const Droppable = ({ id, items, itemProp, keyField, render }) => {
 
     return (
         <SortableContext id={id} items={items} strategy={rectSortingStrategy}>
-            {items.map((item) => (
+            {items?.map((item) => (
                 <SortableItem render={render} key={item[keyField]} id={item}
                     itemProp={itemProp} item={item} />
             ))}

+ 5 - 6
js/Project/project/src/components/create_post/index.js

@@ -23,7 +23,7 @@ export const CreatePost = () => {
     const [post, setPost] = useState({ title: '', text: '', images: [] })
 
     // создаем объект с данными из форм для отправки на бек
-    const newPostData = ({ ...post, images: ((post.images).map(item => ({ _id: item._id }))) })
+    const newPostData = ({ ...post, images: ((post.images)?.map(item => ({ _id: item._id }))) })
 
     const dispatch = useDispatch()
 
@@ -51,12 +51,11 @@ export const CreatePost = () => {
 
 
     // какого хуя не работает await???
-    const onSend = async () => {
-        await store.dispatch(actionFullCreatePost(newPostData));
+    async function onSend() {
+        const res = await dispatch(actionFullCreatePost(newPostData));
 
-        if (newPost) {
-            // console.log('щас пойдем на переход', newPost)
-            history.push(`/post/${newPost}`);
+        if (res) {
+            history.push(`/post/${res?._id}`);
         }
     }
 

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

@@ -77,9 +77,9 @@ export function MyCarousel({ images }) {
                         }
                     }}
                 >
-                    {images && images.map((item) => <DynamicItem key={item?._id} item={item} />)}
+                    {images && images?.map((item) => <DynamicItem key={item?._id} item={item} />)}
                 </Carousel >
-                : images && images.map((item) => <StaticItem key={item?._id} item={item} />)
+                : images && images?.map((item) => <StaticItem key={item?._id} item={item} />)
             }
         </Box>
     )

+ 143 - 20
js/Project/project/src/components/feed/index.js

@@ -1,3 +1,115 @@
+// import React, { useEffect, useState } from 'react';
+// import { connect, useDispatch, useSelector } from 'react-redux';
+
+// import { Box, Divider, Paper } from '@mui/material';
+// import { styled } from '@mui/material/styles';
+// import { Container } from '@mui/system';
+// import Grid2 from '@mui/material/Unstable_Grid2/Grid2';
+
+// // import { actionAboutMe, actionDownloadFeed } from '../redux/action';
+// import { actionAboutMe, actionDownloadFeed } from '../../redux/thunks';
+// import { CardFeed } from './card';
+// import { CAboutMe } from './aboutMe';
+// import Recommended from './recommended';
+
+
+// const Item = styled(Paper)(() => ({
+//     padding: '0 10px',
+//     marginBottom: 10,
+//     borderRadius: 0,
+//     boxShadow: 'none',
+// }))
+
+
+// function Feed({ feed, loadFeed }) {
+//     const dispatch = useDispatch()
+
+//     const [posts, setPosts] = useState(feed)
+
+//     const newPosts = useSelector(state => state.feed?.AddFeed?.payload)
+
+//     // useEffect((() => {
+//     //     if (newPosts) {
+//     //         setPosts([...posts, ...newPosts])
+//     //     }
+//     // }), [newPosts])
+
+//     // чекер дна страницы
+//     window.onscroll = async function feedScroll() {
+//         if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
+//             const downloadedPosts = await dispatch(actionDownloadFeed(feed.length))
+
+//             // добавляем новые посты в общй массив постов
+//             downloadedPosts.map(post => feed.push(post))
+//         }
+//     }
+
+
+//     // console.log('feed: ', feed)
+//     // console.log('posts: ', posts)
+
+//     // первая загрузка страницы
+//     useEffect(() => { loadFeed() }, [])
+
+//     return (
+//         <Container sx={{
+//             width: '90%',
+//             mt: 1
+//         }}>
+//             <Box sx={{
+//                 flexGrow: 1
+//             }}>
+//                 <Grid2 container spacing={2}>
+//                     <Grid2
+//                         xs={7}
+//                         sx={{
+//                             display: 'flex',
+//                             justifyContent: 'center'
+//                         }}
+//                     >
+//                         <Item>
+//                             {feed && feed?.map(post => <Item key={post._id}><CardFeed postData={post} /></Item>)}
+//                         </Item>
+//                     </Grid2>
+//                     <Grid2 xs={5}
+//                         sx={{
+//                             display: 'flex',
+//                             justifyContent: 'center'
+//                         }}
+//                     >
+//                         <Item sx={{
+//                             position: 'fixed'
+//                         }}>
+//                             <CAboutMe />
+
+//                             <Recommended />
+//                         </Item>
+//                     </Grid2>
+//                 </Grid2>
+//             </Box>
+//         </Container>
+//     )
+// }
+
+// export const CFeed = connect(state => ({ feed: state.feed?.MyFeed?.payload }), { loadFeed: actionAboutMe })(Feed)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 import React, { useEffect, useState } from 'react';
 import { connect, useDispatch, useSelector } from 'react-redux';
 
@@ -24,32 +136,37 @@ const Item = styled(Paper)(() => ({
 function Feed({ feed, loadFeed }) {
     const dispatch = useDispatch()
 
-    const [posts, setPosts] = useState(feed)
-
-    const newPosts = useSelector(state => state.feed?.AddFeed?.payload)
-
-    // useEffect((() => {
-    //     if (newPosts) {
-    //         setPosts([...posts, ...newPosts])
-    //     }
-    // }), [newPosts])
+    // отслеживаем дозагрузку новых постов
+    const newPosts = useSelector(state => state?.feed?.AddFeed?.payload)
+    console.log('newPosts: ', newPosts)
+
+    // когда пришли посты, делаем проверку на дубли и пушим в основную ленту
+    if (newPosts) {
+        newPosts.forEach((obj2) => {
+            const obj1Exists = feed?.some((obj1) => obj1?._id === obj2?._id);
+            if (!obj1Exists) {
+                feed?.push(obj2);
+            }
+        });
+    }
 
-    // чекер дна страницы
-    window.onscroll = async function feedScroll() {
+    // функция отслеживания дна
+    function handleScroll() {
         if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
-            const downloadedPosts = await dispatch(actionDownloadFeed(feed.length))
-
-            // добавляем новые посты в общй массив постов
-            downloadedPosts.map(post => feed.push(post))
+            dispatch(actionDownloadFeed())
         }
-    }
+    };
+
+    // первая загрузка страницы и монтирование прослушки
+    useEffect(() => {
+        loadFeed()
 
+        window.addEventListener('scroll', handleScroll);
 
-    // console.log('feed: ', feed)
-    // console.log('posts: ', posts)
+        return () => window.removeEventListener('scroll', handleScroll);
+    }, [])
 
 
-    useEffect(() => { loadFeed() }, [])
 
     return (
         <Container sx={{
@@ -68,7 +185,8 @@ function Feed({ feed, loadFeed }) {
                         }}
                     >
                         <Item>
-                            {feed && feed.map(post => <Item key={post._id}><CardFeed postData={post} /></Item>)}
+                            {/* {posts && posts?.map(post => <Item key={post._id}><CardFeed postData={post} /></Item>)} */}
+                            {feed && feed?.map(post => <Item key={post._id}><CardFeed postData={post} /></Item>)}
                         </Item>
                     </Grid2>
                     <Grid2 xs={5}
@@ -92,3 +210,8 @@ function Feed({ feed, loadFeed }) {
 }
 
 export const CFeed = connect(state => ({ feed: state.feed?.MyFeed?.payload }), { loadFeed: actionAboutMe })(Feed)
+
+
+
+
+

+ 46 - 37
js/Project/project/src/components/feed/recommended.js

@@ -12,65 +12,74 @@ import { RecommendedCard } from '../structure/modal';
 
 // Блок с рекомендациями
 function Recommended() {
-
+    const myId = useSelector(state => state?.auth?.payload?.sub?.id)
     const followers = useSelector(state => state?.promise?.FindFollowers?.payload)
     const followings = useSelector(state => state?.promise?.FindFollowings?.payload)
     const myFollowings = useSelector(state => state?.promise?.AboutMe?.payload?.following)
 
     let recommendedList = []
 
-    // собираем список подписок и подписчиков моих подписок и подписчико и удаляем из него повторы и моих подписок
+    // собираем список подписок и подписчиков моих подписок и подписчиков и удаляем из него повторы и моих подписок
     if (followers && followings && myFollowings) {
-        const joinArr = [
+        const joinArr = ([
             ...followers,
             ...followings.filter((item) =>
                 !followers.some((current) => current._id === item._id)
             )
         ].filter((item) =>
             !myFollowings.some((current) => current._id === item._id)
-        )
+            // ))
+        )).filter(currentItem => currentItem._id !== myId)
+
 
         // теперь оставляем в массиве только random рандомных элементов элементов
         const random = 20
-        for (let i = 0; i < random; i++) {
-            const randomIndex = Math.floor(Math.random() * joinArr.length)
-            recommendedList?.push(joinArr[randomIndex])
+        if (joinArr.length != 0) {
+            for (let i = 0; i < random; i++) {
+                const randomIndex = Math.floor(Math.random() * joinArr.length)
+                recommendedList.push(joinArr[randomIndex])
 
-            // удаляем элементы из массива, чтобы снова их не показывать
-            joinArr.splice(randomIndex, 1)
+                // удаляем элементы из массива, чтобы снова их не показывать
+                joinArr.splice(randomIndex, 1)
+            }
         }
     }
 
 
     return (
-        <Box
-            sx={{
-                marginTop: '10px'
-            }}>
-            <Box
-                sx={{
-                    padding: '0 24px'
-                }}>
-                <Typography
-                    variant="subtitle1"
-                    color='text.secondary'
-                    gutterBottom
-                >
-                    Рекомендации для Вас
-                </Typography>
-            </Box>
-
-            <Box
-                className='recommendedBox'
-                sx={{
-                    margin: '8px',
-                    width: '95%',
-                    height: '400px',
-                    overflowY: 'auto'
-                }}>
-                {recommendedList && recommendedList.map(item => <RecommendedCard key={item._id} data={item} />)}
-            </Box>
-        </Box>
+        <React.Fragment>
+            {recommendedList?.length != 0 &&
+                <Box
+                    sx={{
+                        marginTop: '10px'
+                    }}>
+                    <Box
+                        sx={{
+                            padding: '0 24px'
+                        }}>
+                        <Typography
+                            variant="subtitle1"
+                            color='text.secondary'
+                            gutterBottom
+                        >
+                            Рекомендации для Вас
+                        </Typography>
+                    </Box>
+
+                    <Box
+                        className='recommendedBox'
+                        sx={{
+                            margin: '8px',
+                            width: '95%',
+                            height: '400px',
+                            overflowY: 'auto'
+                        }}>
+                        {recommendedList?.map(item => <RecommendedCard key={item._id} data={item} />)}
+                        {/* {recommendedList?.length != 0 && recommendedList?.map(item => <RecommendedCard key={item?._id} data={item} />)} */}
+                    </Box>
+                </Box>}
+        </React.Fragment>
+
     )
 }
 

+ 83 - 0
js/Project/project/src/components/feed/test.js

@@ -0,0 +1,83 @@
+import React, { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { Box, Divider, Paper } from '@mui/material';
+import { styled } from '@mui/material/styles';
+import { Container } from '@mui/system';
+import Grid2 from '@mui/material/Unstable_Grid2/Grid2';
+import { actionAboutMe, actionDownloadFeed } from '../../redux/thunks';
+import { CardFeed } from './card';
+import { CAboutMe } from './aboutMe';
+import Recommended from './recommended';
+
+const Item = styled(Paper)(() => ({
+    padding: '0 10px',
+    marginBottom: 10,
+    borderRadius: 0,
+    boxShadow: 'none',
+}))
+
+function Feed({ feed, loadFeed }) {
+    const [loading, setLoading] = useState(false);
+    const [page, setPage] = useState(feed);
+
+    const handleScroll = () => {
+        if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
+            setPa(dispatch(actionDownloadFeed()))
+        }
+    };
+
+    useEffect(() => {
+        loadFeed();
+        window.addEventListener('scroll', handleScroll);
+        return () => window.removeEventListener('scroll', handleScroll);
+    }, []);
+
+    useEffect(() => {
+        if (!loading) return;
+        setLoading(true);
+        loadFeed(page).then(() => setLoading(false));
+    }, [page]);
+
+    const renderFeed = () => {
+        if (!feed) return null;
+        const filteredFeed = feed.filter(
+            (item, index, self) =>
+                index === self.findIndex((t) => t._id === item._id)
+        );
+        return filteredFeed.map((post) => (
+            <Item key={post._id}>
+                <CardFeed postData={post} />
+            </Item>
+        ));
+    };
+
+    return (
+        <Container sx={{ width: '90%', mt: 1 }}>
+            <Box sx={{ flexGrow: 1 }}>
+                <Grid2 container spacing={2}>
+                    <Grid2
+                        xs={7}
+                        sx={{ display: 'flex', justifyContent: 'center' }}
+                    >
+                        <Item>{renderFeed()}</Item>
+                    </Grid2>
+                    <Grid2
+                        xs={5}
+                        sx={{ display: 'flex', justifyContent: 'center' }}
+                    >
+                        <Item sx={{ position: 'fixed' }}>
+                            <CAboutMe />
+                            <Recommended />
+                        </Item>
+                    </Grid2>
+                </Grid2>
+            </Box>
+        </Container>
+    );
+}
+
+export const CFeed = connect(
+    (state) => ({ feed: state.feed?.MyFeed?.payload }),
+    { loadFeed: actionAboutMe }
+)(Feed);
+

+ 13 - 13
js/Project/project/src/components/post/comments_add_field.js

@@ -9,6 +9,9 @@ import {
     TextField,
     Popover
 } from '@mui/material'
+
+import Button from '@mui/material-next/Button';
+
 import {
     SentimentSatisfiedAlt
 } from '@mui/icons-material/'
@@ -136,24 +139,21 @@ function CommentField() {
                         </Box>,
 
                     endAdornment:
-                        <Box>
-                            {comment.text !== '' && <Typography
-                                variant='subtitle2'
-                                color="primary.main"
-                                align='center'
-                                sx={{
+                        <Box
+                            onClick={uploadComment}
+                        >
+                            {comment.text !== '' &&
+                                <Button size="medium" align='center' sx={{
                                     alignSelf: 'center',
                                     cursor: 'pointer',
-                                    margin: '0 8px'
-                                }}
-                                onClick={uploadComment}
-                            >
-                                Отправить
-                            </Typography>}
+                                    marginLeft: '8px',
+                                    padding: '2px 5px'
+                                }}>отправить</Button>
+                            }
                         </Box>
                 }}
             />
-        </Box>
+        </Box >
     )
 }
 

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

@@ -45,7 +45,7 @@ function CommentsFeed({ comments = [], loadComments }) {
 
     return (
         <>
-            {data && data.map(item => <CommentCard
+            {data && data?.map(item => <CommentCard
                 data={item}
                 key={item._id}
             />

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

@@ -269,7 +269,7 @@ function CommentCard({ data }) {
                         sx={{
                             padding: '0 8px'
                         }}>
-                        {data?.answers && (data?.answers).map(item => <CommentCard
+                        {data?.answers && (data?.answers)?.map(item => <CommentCard
                             data={item}
                             key={item._id}
                         />)}

+ 20 - 17
js/Project/project/src/components/search/index.js

@@ -56,29 +56,26 @@ export default function Search() {
     // отслеживание текста в поле ввода
     const [inputText, setInputText] = useState('')
 
+    // отслеживаем, запустили поиск или нет
+    const [searching, setSearching] = useState(false);
 
-    // отслеживание нажатия enter на кнопку поиска
-    const searchButtonClick = document.getElementById('searchField');
-    searchButtonClick && searchButtonClick.addEventListener('keydown', function (e) {
-        if (e.code === 'Enter') {
-            e.preventDefault()
-            onSearching()
+    // функция вызова поиска
+    const onSearch = () => {
+        if (searching) {
+            return
         }
-    })
 
+        setSearching(true)
 
-    // отправка запроса на поиск
-    function onSearching() {
-        // собираем регулярку
-        const newText = (new RegExp(inputText.split(' ').join('|'))).toString()
+        const newData = new RegExp(inputText.split(' ').join('|')).toString()
 
-        console.log('reg: ', newText)
-
-        dispatch(actionFullSearch(newText))
+        dispatch(actionFullSearch(newData)).finally(() => {
+            setSearching(false)
+            setInputText('')
+        })
     }
 
 
-
     return (
         <Box
             sx={{
@@ -100,9 +97,14 @@ export default function Search() {
                         placeholder="Найти..."
                         value={inputText}
                         onChange={e => setInputText(e.target.value)}
+                        onKeyDown={e => {
+                            if (e.code === 'Enter') {
+                                e.preventDefault()
+                                onSearch()
+                            }
+                        }}
                         inputProps={{
                             'aria-label': 'Найти...',
-                            id: 'searchField'
                         }}
                         sx={{
                             ml: 1, flex: 1
@@ -124,7 +126,8 @@ export default function Search() {
                                 }}>
                                 {inputText !== '' &&
                                     <Box
-                                        onClick={onSearching}
+                                        // onClick={onSearching}
+                                        onClick={onSearch}
                                     >
                                         <Button
                                             startIcon={<TouchAppRounded />}

+ 0 - 266
js/Project/project/src/components/search/test.js

@@ -1,266 +0,0 @@
-import { url } from "../../App";
-
-import React, { useEffect, useState } from "react"
-import { Tabs, Tab, TabPanel, Box, Typography, CardHeader, Avatar, Stack, FormControl, InputLabel, OutlinedInput, InputAdornment, IconButton, InputBase, Grid, List, ListItem, ListItemAvatar, ListItemText, Divider, Paper, CircularProgress } from '@mui/material';
-import Button from '@mui/material-next/Button';
-import PropTypes from 'prop-types';
-import { PersonSearchRounded, ForumRounded, CollectionsRounded, SearchRounded, TouchAppRounded } from '@mui/icons-material';
-import { useDispatch, useSelector } from "react-redux";
-
-import { actionFullSearch } from "../../redux/thunks";
-import { useHistory } from "react-router-dom";
-
-
-
-export default function Search() {
-
-    const dispatch = useDispatch()
-
-    const searchUserLogin = useSelector(state => state?.search?.userLogin?.payload)
-    const searchUserNick = useSelector(state => state?.search?.userNick?.payload)
-    const searchPostTitle = useSelector(state => state?.search?.postTitle?.payload)
-    const searchPostText = useSelector(state => state?.search?.postText?.payload)
-    const searchCommenttext = useSelector(state => state?.search?.commetText?.payload)
-
-    const searchUserLoginStatus = useSelector(state => state?.search?.userLogin?.status)
-    const searchUserNickStatus = useSelector(state => state?.search?.userNick?.status)
-    const searchPostTitleStatus = useSelector(state => state?.search?.postTitle?.status)
-    const searchPostTextStatus = useSelector(state => state?.search?.postText?.status)
-    const searchCommenttextStatus = useSelector(state => state?.search?.commetText?.status)
-
-    // отслеживаем статус загрузки всех промисов
-    const [downloadStatus, setDownloadStatus] = useState(false)
-    console.log('downloadStatus: ', downloadStatus)
-
-    useEffect(() => {
-        setDownloadStatus(
-            (searchUserLoginStatus === 'FULFILLED') &&
-            (searchUserNickStatus === 'FULFILLED') &&
-            (searchPostTitleStatus === 'FULFILLED') &&
-            (searchPostTextStatus === 'FULFILLED') &&
-            (searchCommenttextStatus === 'FULFILLED')
-        )
-    },
-        [searchUserLoginStatus, searchUserNickStatus, searchPostTitleStatus, searchPostTextStatus, searchCommenttextStatus])
-
-
-    // собираем все в один массив после завершения поиска
-    const [fullSearchData, setFullSearchData] = useState([])
-    // console.log('fullSearchData; ', fullSearchData?.length)
-
-    useEffect(() => {
-        setFullSearchData((searchUserLogin && searchUserNick && searchPostTitle && searchPostText && searchCommenttext) && [...new Map([...searchUserLogin, ...searchUserNick, ...searchPostTitle, ...searchPostText, ...searchCommenttext]?.map(item => [item?._id, item])).values()])
-    },
-        [searchUserLogin, searchUserNick, searchPostTitle, searchPostText, searchCommenttext])
-
-
-    // отслеживание состояния для элемента статус-бара
-    const [isProgress, setIsProgress] = useState(downloadStatus)
-    // console.log('isProgress: ', isProgress)
-
-
-    // отслеживание текста в поле ввода
-    const [inputText, setInputText] = useState('')
-
-
-    // отслеживание нажатия enter на кнопку поиска
-    const searchButtonClick = document.getElementById('searchField');
-    searchButtonClick && searchButtonClick.addEventListener('keydown', function (e) {
-        if (e.code === 'Enter') {
-            e.preventDefault()
-            onSearching()
-        }
-    })
-
-
-    // отправка запроса на поиск
-    async function onSearching() {
-        // setIsProgress(!isProgress)
-
-        const newText = (new RegExp(inputText.split(' ').join('|'))).toString()
-
-        const res = await dispatch(actionFullSearch(newText))
-
-        // console.log(22, res)
-
-        // setIsProgress(!isProgress)
-    }
-
-
-
-    return (
-        <Box
-            sx={{
-                padding: '16px',
-                width: '80%',
-                margin: '0 auto',
-            }}
-        >
-            <Stack spacing={2}>
-                <Box sx={{
-                    border: '1px solid #E8E8E8',
-                    borderRadius: '8px',
-                    padding: '8px'
-                }}
-                >
-                    <InputBase
-
-                        fullWidth={true}
-                        placeholder="Найти..."
-                        value={inputText}
-                        onChange={e => setInputText(e.target.value)}
-                        inputProps={{
-                            'aria-label': 'Найти...',
-                            id: 'searchField'
-                        }}
-                        sx={{
-                            ml: 1, flex: 1
-                        }}
-                        startAdornment={
-                            <SearchRounded position="start" />
-                        }
-
-                        endAdornment={
-                            <Typography
-                                variant='subtitle2'
-                                align='right'
-                                color='primary.main'
-                                sx={{
-                                    alignSelf: 'center',
-                                    cursor: 'pointer',
-                                    margin: '0 8px',
-                                    fontWeight: '700'
-                                }}>
-                                {inputText !== '' &&
-                                    <Box
-                                        onClick={onSearching}
-                                    >
-                                        <Button
-                                            startIcon={<TouchAppRounded />}
-                                            color="primary"
-                                            size="small"
-                                            variant="filledTonal"
-                                            sx={{
-                                                padding: '5px 10px'
-                                            }}
-                                        >
-                                            Искать
-                                        </Button>
-                                    </Box>
-                                }
-                            </Typography>
-                        }
-                    />
-                </Box>
-
-
-                {/* {!downloadStatus
-                    ? isProgress && <CircularProgress />
-                    : */}
-                <Box>
-                    <List
-                        sx={{
-                            bgcolor: 'background.paper',
-                            width: '90%',
-                            margin: '0 auto'
-                        }}>
-                        {fullSearchData && fullSearchData?.map(item => <SearchCard data={item} key={item?._id} />)}
-                    </List>
-                </Box>
-                {/* } */}
-
-
-
-            </Stack >
-
-            {fullSearchData && fullSearchData?.length === 0 &&
-                <Typography>
-                    нихера не нашло
-                </Typography>}
-        </Box>
-    )
-}
-
-
-function SearchCard({ data }) {
-    const history = useHistory()
-
-    function toPost() {
-        if (data?.title) history.push(`/post/${data?._id}`)
-
-        if (data?.post) history.push(`/post/${data?.post?._id}`)
-    }
-
-    function toUser() {
-        history.push(`/user/${data?.owner ? data?.owner?._id : data?._id}`)
-    }
-
-
-    return (
-        <Paper
-            elevation={3}
-            sx={{
-                padding: '8px',
-                marginTop: '10px'
-            }}
-        >
-
-            <ListItem
-                alignItems="flex-start"
-                sx={{
-                    cursor: 'pointer',
-                    width: '100%',
-                    padding: '0 16px'
-                }}
-                onClick={toUser}
-            >
-                <ListItemAvatar>
-                    <Avatar
-                        alt={data?.owner ? data?.owner?.login : data?.login}
-                        src={url + (data?.owner ? data?.owner?.avatar?.url : data?.avatar?.url)} />
-                </ListItemAvatar>
-
-                <ListItemText
-                    primary={data?.owner ? data?.owner?.login : data?.login}
-                    secondary={
-                        <Typography
-                            sx={{ display: 'inline' }}
-                            component="span"
-                            variant="body2"
-                            color="text.primary"
-                        >
-                            {data?.owner ? data?.owner?.nick : data?.nick}
-                        </Typography>
-                    }
-                />
-
-            </ListItem>
-
-            {data?.owner &&
-                <ListItem
-                    sx={{
-                        border: '1px solid #E8E8E8',
-                        borderRadius: '8px',
-                        marginTop: '8px',
-                        cursor: 'pointer'
-                    }}
-                    onClick={toPost}
-                >
-                    <ListItemText
-                        primary={data?.title && data?.title}
-                        secondary={data?.text &&
-                            <Typography
-                                sx={{ display: 'inline' }}
-                                component="span"
-                                variant="body2"
-                                color="text.primary"
-                            >
-                                {data?.text}
-                            </Typography>
-                        }
-                    />
-                </ListItem>}
-
-        </Paper>
-    )
-}

+ 22 - 19
js/Project/project/src/components/structure/header.js

@@ -158,32 +158,30 @@ function Header({ login }) {
     // отслеживание введенного текста в поиске
     const [searchText, setSearchText] = useState('')
 
+    // отслеживаем, запустили поиск или нет
+    const [searching, setSearching] = useState(false);
 
-    // отслеживание нажатия enter на кнопку поиска
-    const searchButtonClick = document.getElementById('searchFieldHeader');
-    searchButtonClick && searchButtonClick.addEventListener('keydown', function (e) {
-        if (e.code === 'Enter') {
-            e.preventDefault()
-            onSearching()
+    // функция вызова поиска
+    const onSearch = () => {
+        if (searching) {
+            return
         }
-    })
 
-    // функция поиска
-    function onSearching() {
-        history.push('/search')
-
-        // собираем регулярку
-        const newText = (new RegExp(searchText.split(' ').join('|'))).toString()
-
-        dispatch(actionFullSearch(newText))
-    }
+        setSearching(true)
 
+        const newData = new RegExp(searchText.split(' ').join('|')).toString()
 
+        dispatch(actionFullSearch(newData)).finally(() => {
+            setSearching(false)
+            setSearchText('')
+        });
 
+        history.push('/search')
+    }
 
 
     function toMain() {
-        history.push('/');
+        history.push('/')
     }
 
 
@@ -252,11 +250,16 @@ function Header({ login }) {
                                         variant="standard"
                                         value={searchText}
                                         onChange={e => setSearchText(e.target.value)}
+                                        onKeyDown={e => {
+                                            if (e.code === 'Enter') {
+                                                e.preventDefault()
+                                                onSearch()
+                                            }
+                                        }}
 
                                         InputProps={{
                                             'disableUnderline': true,
                                             'aria-label': 'search',
-                                            id: 'searchFieldHeader',
                                             endAdornment:
                                                 <Typography
                                                     variant='subtitle2'
@@ -270,7 +273,7 @@ function Header({ login }) {
                                                     }}>
                                                     {searchText !== '' &&
                                                         <Box
-                                                            onClick={onSearching}
+                                                            onClick={onSearch}
                                                         >
                                                             <Button
                                                                 startIcon={<TouchAppRounded />}

+ 1 - 1
js/Project/project/src/components/structure/modal.js

@@ -190,7 +190,7 @@ function ModalWindow() {
                                 overflowY: 'auto'
                             }}>
                             {modalArray.length != 0
-                                ? modalArray.map(item => <RecommendedCard key={item._id} data={item} />)
+                                ? modalArray?.map(item => <RecommendedCard key={item._id} data={item} />)
                                 : <Typography
                                     variant="subtitle1"
                                     align='center'

+ 1 - 1
js/Project/project/src/components/user/gallery.js

@@ -30,7 +30,7 @@ export default function StandardImageList({ images }) {
             cols={3}
             rowHeight={'auto'}
         >
-            {images.map(item => (
+            {images?.map(item => (
 
                 <ImageListItem
                     key={item?._id}

+ 6 - 2
js/Project/project/src/components/user/userData.js

@@ -24,6 +24,7 @@ function UptadeProfileButton({ data }) {
 
     // контекст обновления профиля
     const [updateProfile, setUpdateProfile] = useContext(UpdateProfile)
+    console.log('updateProfile: ', updateProfile)
 
     // определяем мой id
     const myId = updateProfile?._id
@@ -41,8 +42,11 @@ function UptadeProfileButton({ data }) {
         // при клике на посте
         const newData = {
             ...updateProfile, following: (isFollowing
-                ? updateProfile.following.filter(item => item._id !== (data?.owner?._id || data?._id)) // отписка
-                : [...updateProfile.following, { _id: (data?.owner?._id || data?._id) }] // подписка
+                ? updateProfile?.following?.filter(item => item?._id !== (data?.owner?._id || data?._id)) // отписка
+                // : [...updateProfile?.following, { _id: (data?.owner?._id || data?._id) }] // подписка
+                : updateProfile?.following
+                    ? [...updateProfile?.following, { _id: (data?.owner?._id || data?._id) }] // подписка если уже есть кто-то в подписках
+                    : [{ _id: (data?.owner?._id || data?._id) }] // подписка, если это первая подписка
             )
         }
 

+ 1 - 1
js/Project/project/src/redux/action.js

@@ -414,7 +414,7 @@ export const actionUpdateProfile = params => actionPromise('PROMISE', 'UpdatePro
 
 
 
-
+// массив запросов на поиск
 
 // запрос поиска по юзерам
 export const actionSearchUser = (params, name) => actionPromise('SEARCH', name, gql(`query UserSearch($findUser: String){

+ 22 - 17
js/Project/project/src/redux/reducers.js

@@ -15,7 +15,6 @@ const jwtDecode = function (token) {
 // authReducer
 export function authReducer(state = {}, { type, token }) {
     if (type === 'AUTH_LOGIN') {
-
         let payload = jwtDecode(token)
 
         return state = {
@@ -25,13 +24,34 @@ export function authReducer(state = {}, { type, token }) {
     }
 
     if (type === 'AUTH_LOGOUT') {
-        return state = {}
+        return {}
     }
 
     return state
 }
 
 
+// универсальный создатель редьюсеров в зависимости от передаваемого типа
+function createReducer(type) {
+    function wrapper(state = {}, action) {
+        const { status, payload, error, nameOfPromise } = action
+        if (action.type === type) {
+            return {
+                ...state,
+                [nameOfPromise]: { status, payload, error }
+            }
+        }
+
+        if (action.type === 'AUTH_LOGOUT') {
+            return {}
+        }
+
+        return state
+    }
+    return wrapper
+}
+
+
 // localStoredReducer, который обрабатывает все наши редьюсеры для разных направлений и добавляет в localStorage
 export function localStoredReducer(originalReducer, localStorageKey) {
     function wrapper(state, action) {
@@ -53,21 +73,6 @@ export function localStoredReducer(originalReducer, localStorageKey) {
     return wrapper
 }
 
-// универсальный создатель редьюсеров в зависимости от передаваемого типа
-function createReducer(type) {
-    function wrapper(state = {}, action) {
-        const { status, payload, error, nameOfPromise } = action
-        if (action.type === type) {
-            return {
-                ...state,
-                [nameOfPromise]: { status, payload, error }
-            }
-        }
-        return state
-    }
-    return wrapper
-}
-
 
 export const reducers = {
     auth: localStoredReducer(authReducer, 'auth'),

+ 53 - 92
js/Project/project/src/redux/thunks.js

@@ -29,6 +29,8 @@ import {
 export const actionFullLogin = (login, password) =>
     async dispatch => {
 
+        localStorage.clear()
+
         const token = await dispatch(actionLogin(login, password))
 
         if (token !== null) {
@@ -68,23 +70,7 @@ export const actionFullLogout = () =>
 
 
 
-
-
-
-
 // Запрос юзера (данные о пользователе + количество его постов + все его посты(100 шт))
-// export const actionFullUserFindOne = _id =>
-//     async dispatch => {
-
-//         // запрашиваем информацию о пользователе
-//         await dispatch(actionFindUserOne(_id, 'UserFindOne'))
-
-//         // парсим счетчик, сколько постов у юзера
-//         dispatch(actionPostsCount(_id, 'UserPostsCount'))
-
-//         // запрашиваем список постов для юзера
-//         dispatch(actionFeedFindOne([_id], -1, 100, 'UserFeed'))
-//     }
 export const actionFullUserFindOne = _id =>
     dispatch => {
         const requestsAboutUser = [
@@ -93,57 +79,12 @@ export const actionFullUserFindOne = _id =>
             actionFeedFindOne([_id], -1, 100, 'UserFeed')
         ]
 
-        return Promise.all(requestsAboutUser.map(item => dispatch(item)))
+        return Promise.all(requestsAboutUser?.map(item => dispatch(item)))
     }
 
 
 
-
-
-
 // Запрос AboutMe для главной
-// export const actionAboutMe = () =>
-//     async (dispatch, getState) => {
-//         const myId = getState()?.auth?.payload?.sub?.id
-
-//         // диспатчим запрос AboutMe (о себе)
-//         const myData = await dispatch(actionFindUserOne(myId, 'AboutMe'))
-
-//         // собираем список id моих подписок
-//         let followingList = []
-//         if (myData?.following) {
-//             followingList = (myData.following).map(user => user?._id)
-//         }
-
-//         // собираем id моих подписок и подписчиков
-//         const podpisotaList = []
-//         for (const key in myData) {
-//             if (key === 'following' || key === 'followers') {
-//                 for (const item of myData[key]) {
-//                     if (!podpisotaList.includes(item._id)) {
-//                         podpisotaList.push(item._id)
-//                     }
-//                 }
-//             }
-//         }
-
-//         // шлем все запросы на меня одновременно
-//         const requestsAboutMe = [
-//             actionPostsCount(myId, 'MyPostsCount'),
-//             actionFeedFindOne(followingList, -1, 10, 'MyFeed'),
-//             actionFindFollowers(podpisotaList),
-//             actionFindFollowing(podpisotaList)
-//         ]
-
-//         Promise.all(requestsAboutMe.map(item => dispatch(item)))
-
-//         // парсим счетчик, сколько постов у меня
-//         // dispatch(actionPostsCount(myId, 'MyPostsCount'))
-//         // диспатчим ленту моих постов (первый параметр - список id, второй - это сортировка постов от новых)
-//         // dispatch(actionFeedFindOne(followingList, -1, 10, 'MyFeed'))
-//         // диспатчим список для рекомендаций
-//         // await Promise.all([dispatch(actionFindFollowers(podpisotaList)), dispatch(actionFindFollowing(podpisotaList))])
-//     }
 export const actionAboutMe = () =>
     async (dispatch, getState) => {
         const myId = getState()?.auth?.payload?.sub?.id
@@ -154,16 +95,18 @@ export const actionAboutMe = () =>
                 // собираем список id моих подписок
                 let followingList = []
                 if (myData?.following) {
-                    followingList = myData.following.map(user => user?._id)
+                    followingList = myData?.following?.map(user => user?._id)
                 }
 
                 // собираем id моих подписок и подписчиков
                 const podpisotaList = []
                 for (const key in myData) {
                     if (key === 'following' || key === 'followers') {
-                        for (const item of myData[key]) {
-                            if (!podpisotaList.includes(item._id)) {
-                                podpisotaList.push(item._id)
+                        if (myData[key]) {
+                            for (const item of myData[key]) {
+                                if (!podpisotaList.includes(item._id)) {
+                                    podpisotaList.push(item._id)
+                                }
                             }
                         }
                     }
@@ -177,33 +120,48 @@ export const actionAboutMe = () =>
                     actionFindFollowing(podpisotaList)
                 ]
 
-                return Promise.all(requestsAboutMe.map(item => dispatch(item)))
+                return Promise.all(requestsAboutMe?.map(item => dispatch(item)))
             })
     }
 
 
 
+// // ================= на удаление (начало)=====================
+// // Запрос на догрузку ленты постов
+// export const actionDownloadFeed = () =>
+//     async (dispatch, getState) => {
 
+//         // console.log('скипаем: ', skip)
 
+//         const followingList = (getState()?.promise?.AboutMe?.payload?.following)?.map(user => user._id)
 
+//         const skipLength = (getState()?.feed?.MyFeed?.payload?.length)
 
+//         if (followingList) {
+//             // const result = await dispatch(actionFeedFindOne(followingList, -1, 5, 'AddFeed', skipLength))
+//             const result = await dispatch(actionFeedFindOne(followingList, -1, 5, 'MyFeed', skipLength))
 
+//             return result
+//         }
+//     }
+// // ================= на удаление(конец) =====================
 
+// ================= на удаление (начало)=====================
 
 
-// ================= на удаление (начало)=====================
 // Запрос на догрузку ленты постов
-export const actionDownloadFeed = (skip) =>
+export const actionDownloadFeed = () =>
     async (dispatch, getState) => {
+        console.log('касание')
 
-        console.log('скипаем: ', skip)
-        const followingList = (getState()?.promise?.AboutMe?.payload?.following).map(user => user._id)
+        const followingList = (getState()?.promise?.AboutMe?.payload?.following)?.map(user => user._id)
 
-        if (followingList) {
-            const result = await dispatch(actionFeedFindOne(followingList, -1, 10, 'AddFeed', skip))
+        const myFeed = (getState()?.feed?.MyFeed?.payload)
 
-            return result
-        }
+        const result = await dispatch(actionFeedFindOne(followingList, -1, 10, 'AddFeed', myFeed?.length))
+
+
+        return result
     }
 // ================= на удаление(конец) =====================
 
@@ -211,6 +169,21 @@ export const actionDownloadFeed = (skip) =>
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 // запрос на загрузку картинок на бек
@@ -230,7 +203,7 @@ function fileUpload(file) {
 }
 
 function filesUpload(files) {
-    return Promise.all(files.map(fileUpload))
+    return Promise.all(files?.map(fileUpload))
 }
 
 export const actionFilesUpload = files => actionPromise('PROMISE', 'FilesUpload',
@@ -239,9 +212,6 @@ export const actionFilesUpload = files => actionPromise('PROMISE', 'FilesUpload'
 
 
 
-
-
-
 // запрос на создание поста и последующий переход на него
 export const actionFullCreatePost = (params) =>
     async dispatch => {
@@ -250,9 +220,9 @@ export const actionFullCreatePost = (params) =>
         if (newPost) {
             dispatch(actionFindPostOne(newPost._id))
         }
-    }
-
 
+        return newPost
+    }
 
 
 
@@ -266,9 +236,6 @@ export const actionFullFindCommentsPostOne = id =>
 
 
 
-
-
-
 // создание комментария с последующей загрузкой с бека списка всех постов, которые относятся к этой записи
 export const actionFullAddComment = (nameOfPromise, params, id) =>
     async dispatch => {
@@ -281,8 +248,6 @@ export const actionFullAddComment = (nameOfPromise, params, id) =>
 
 
 
-
-
 // создание лайка с последующим добавлением к определенной сущности и последующим обновление определенной сущности
 export const actionFullAddLike = params =>
     async dispatch => {
@@ -302,8 +267,6 @@ export const actionFullAddLike = params =>
 
 
 
-
-
 // удаление лайка с последующим обновлением определенной сущности
 export const actionFullDeleteLike = params =>
     async dispatch => {
@@ -323,10 +286,7 @@ export const actionFullDeleteLike = params =>
 
 
 
-
-
 // запрос на обновление моего профиля и последующая отправка запроса обо мне на бек
-// export const actionFullUpdateProfile = params =>
 export const actionFullUpdateProfile = (params, id) =>
     async dispatch => {
         const res = await dispatch(actionUpdateProfile(params))
@@ -342,6 +302,7 @@ export const actionFullUpdateProfile = (params, id) =>
     }
 
 
+
 // запрос на подписку/отписку на странице пользователя
 export const actionUserPageSubscribing = (params, id) =>
     async dispatch => {
@@ -367,7 +328,7 @@ export const actionFullSearch = param =>
         ]
 
         // запускаем все акшоны
-        const result = await Promise.all(searchPromises.map(item => dispatch(item)))
+        const result = await Promise.all(searchPromises?.map(item => dispatch(item)))
 
         return result
     }