Browse Source

the architecture of the project has been redesigned. The reducer has been split into PostOne and PostTape. fragmented components with nested logic. added media upload limit up to 8. fixed display of likes of sub comments. Added reverse scroll when displaying comments on the post page. The action is divided into actionGetGql and actionCreators. Function refactoring in redux-saga - add/remove likes and comments, subscribe and unsubscribe. fixed error when validating fields in comments, added input character limit

makstravm 2 years ago
parent
commit
a3e04cfc7e
53 changed files with 1521 additions and 1219 deletions
  1. 29 16
      src/App.js
  2. 7 2
      src/App.scss
  3. 87 133
      src/actions/index.js
  4. 138 0
      src/actions/actonsCreators.js
  5. 6 6
      src/components/main/profilePage/EditAvatar.js
  6. 24 25
      src/components/main/postsFeed/FieldComment.jsx
  7. 0 11
      src/pages/Content.jsx
  8. 0 11
      src/components/Footer.jsx
  9. 9 0
      src/components/FooterComponent.jsx
  10. 6 6
      src/components/FormAuthorization.jsx
  11. 55 0
      src/components/GalleryMediaPostsUser.jsx
  12. 75 0
      src/components/ModalFollow.jsx
  13. 1 3
      src/pages/Preloader.jsx
  14. 7 6
      src/components/header/UserAvatar.js
  15. 0 0
      src/components/editPost/EditDescriptionPost.jsx
  16. 24 8
      src/components/uploadPhoto/EditPhotos.js
  17. 0 0
      src/components/editPost/EditTitlePost.jsx
  18. 13 13
      src/components/header/Header.jsx
  19. 9 9
      src/components/header/Search.jsx
  20. 0 11
      src/components/main/DateCreated.js
  21. 0 36
      src/components/main/Posts.jsx
  22. 0 73
      src/components/main/postsFeed/PostImage.jsx
  23. 0 67
      src/components/main/postsFeed/PostUserPanel.jsx
  24. 0 62
      src/components/main/profilePage/ModalFollow.js
  25. 59 0
      src/components/post/CommentsPostInTape.jsx
  26. 44 0
      src/components/post/PostDescription.jsx
  27. 20 9
      src/components/main/post/PostTitle.js
  28. 107 0
      src/components/post/PostImageCover.jsx
  29. 38 43
      src/components/main/post/PostComment.js
  30. 97 0
      src/components/post/PostUserPanel.jsx
  31. 1 51
      src/helpers/index.js
  32. 20 0
      src/hoc/RRoute.js
  33. BIN
      src/images/preloader.gif
  34. 10 9
      src/pages/AllPosts.jsx
  35. 1 0
      src/pages/Authorization.jsx
  36. 12 8
      src/pages/CollectionPage.jsx
  37. 30 30
      src/pages/EntityEditorPost.jsx
  38. 0 129
      src/pages/MainPostsFeed.jsx
  39. 57 0
      src/pages/PostOnePage.jsx
  40. 0 57
      src/pages/PostPage.jsx
  41. 77 0
      src/pages/PostsTapeMyFollowing.jsx
  42. 119 71
      src/pages/ProfilePage.jsx
  43. 48 23
      src/pages/SettingsPage.jsx
  44. 18 0
      src/redux/reducers/aboutMe-reducer.js
  45. 10 1
      src/redux/reducers/auth-reducer.js
  46. 0 22
      src/redux/reducers/myProfile-reducer.js
  47. 0 96
      src/redux/reducers/post-reducer.js
  48. 53 0
      src/redux/reducers/postOne-reducer.js
  49. 40 0
      src/redux/reducers/postsTape-reducer.js
  50. 14 0
      src/redux/reducers/profileData-reducer.js
  51. 0 5
      src/redux/reducers/route-reducer.js
  52. 13 9
      src/redux/redux-store.js
  53. 143 158
      src/redux/saga/index.js

+ 29 - 16
src/App.js

@@ -4,23 +4,31 @@ import { Router, Route, Switch, Redirect } from 'react-router-dom';
 import createHistory from "history/createBrowserHistory";
 import createHistory from "history/createBrowserHistory";
 import { connect, Provider } from 'react-redux';
 import { connect, Provider } from 'react-redux';
 import store from './redux/redux-store';
 import store from './redux/redux-store';
-import { Content, Main } from './pages/Content';
-import { CProfilePage } from './pages/ProfilePage';
-import HeaderComponent from './components/header/Header';
-import { CMainPostsFeed } from './pages/MainPostsFeed';
-import { CRRoute } from './helpers';
-import { CPostPage } from './pages/PostPage';
-import { CAllPosts } from './pages/AllPosts';
-import { CEntityEditorPost } from './pages/EntityEditorPost';
-import { CSettingsPage } from './pages/SettingsPage';
 import { Authorization } from './pages/Authorization';
 import { Authorization } from './pages/Authorization';
+import { CPostsTapeMyFollowing } from './pages/PostsTapeMyFollowing';
+import HeaderComponent from './components/header/Header';
+import { CProfilePage } from './pages/ProfilePage';
+import { CAllPostsTape } from './pages/AllPostsTape';
 import { CCollectionPage } from './pages/CollectionPage';
 import { CCollectionPage } from './pages/CollectionPage';
+import { CSettingsPage } from './pages/SettingsPage';
+import { CEditPostPage } from './pages/EditPostPage';
+import { CPostOnePage } from './pages/PostOnePage';
+import { CRRoute } from './hoc/RRoute';
+import { FooterComponet } from './components/FooterComponent';
 import { useMediaQuery } from 'react-responsive';
 import { useMediaQuery } from 'react-responsive';
-import { FooterComponent } from './components/Footer';
+
 
 
 export const history = createHistory()
 export const history = createHistory()
 
 
 
 
+const Main = ({ children }) =>
+    <div className='Main'>{children}</div>
+
+
+const Content = ({ children }) =>
+    <>{children}</>
+
+
 const AppContent = ({ isToken }) => {
 const AppContent = ({ isToken }) => {
     const isTabletDevice = useMediaQuery({
     const isTabletDevice = useMediaQuery({
         query: "(max-width: 786px)"
         query: "(max-width: 786px)"
@@ -38,24 +46,29 @@ const AppContent = ({ isToken }) => {
                 <HeaderComponent />
                 <HeaderComponent />
                 <Main>
                 <Main>
                     <Switch>
                     <Switch>
-                        <Route path='/feed' component={CMainPostsFeed} />
+                        <Route path='/tape' component={CPostsTapeMyFollowing} />
                         <Route path='/profile/:_id' component={CProfilePage} />
                         <Route path='/profile/:_id' component={CProfilePage} />
-                        <Route path='/edit/post/:_id' component={CEntityEditorPost} />
+                        <Route path='/edit/post/:_id' component={CEditPostPage} />
                         <Route path='/my-settings' component={CSettingsPage} />
                         <Route path='/my-settings' component={CSettingsPage} />
-                        <Route path='/all' component={CAllPosts} />
+                        <Route path='/all' component={CAllPostsTape} />
                         <Route path='/my-collection' component={CCollectionPage} />
                         <Route path='/my-collection' component={CCollectionPage} />
-                        <CRRoute path='/post/:id' component={CPostPage} />
-                        <Redirect from='/*' to='/feed' />
+                        <CRRoute path='/post/:id' component={CPostOnePage} />
+                        <Redirect from='/*' to='/tape' />
                     </Switch>
                     </Switch>
                 </Main>
                 </Main>
-                {isTabletDevice && <FooterComponent />}
+                {isTabletDevice && <FooterComponet  />}
             </Content >
             </Content >
         }
         }
     </Router >
     </Router >
 }
 }
 
 
+
 const CAppContent = connect(state => ({ isToken: state.auth?.token }))(AppContent)
 const CAppContent = connect(state => ({ isToken: state.auth?.token }))(AppContent)
 
 
+
+store.subscribe(() => console.log(store.getState()))
+
+
 function App() {
 function App() {
     return (
     return (
         <Provider store={store}>
         <Provider store={store}>

+ 7 - 2
src/App.scss

@@ -429,13 +429,13 @@ video {
             max-width: 100%;
             max-width: 100%;
             height: 100%;
             height: 100%;
             margin: 0 auto;
             margin: 0 auto;
-            object-fit:cover;
+            object-fit: cover;
         }
         }
     }
     }
     &__description {
     &__description {
         grid-area: 2 / 2 / 3 / 3;
         grid-area: 2 / 2 / 3 / 3;
         background-color: $defaultColorW;
         background-color: $defaultColorW;
-        padding: 5px 20px;
+        padding: 5px 5px 5px 20px;
         height: 100%;
         height: 100%;
         .ant-typography {
         .ant-typography {
             overflow-wrap: anywhere;
             overflow-wrap: anywhere;
@@ -458,6 +458,8 @@ video {
     &__comments {
     &__comments {
         max-height: 300px;
         max-height: 300px;
         overflow: auto;
         overflow: auto;
+        display: flex;
+        flex-direction: column-reverse;
     }
     }
     &__comment-edit {
     &__comment-edit {
         display: block;
         display: block;
@@ -483,6 +485,9 @@ video {
     }
     }
     .ant-empty-image {
     .ant-empty-image {
         height: auto;
         height: auto;
+        img {
+            margin: 0 auto;
+        }
     }
     }
 }
 }
 
 

+ 87 - 133
src/actions/index.js

@@ -1,32 +1,41 @@
-import { gql } from "../helpers";
-
+import { actionPromise } from "./actonsCreators"
+
+const getGQL = url =>
+    async (query, variables = {}) => {
+        let obj = await fetch(url, {
+            method: 'POST',
+            headers: {
+                "Content-Type": "application/json",
+                ...(localStorage.authToken
+                    ? { Authorization: 'Bearer ' + localStorage.authToken }
+                    : sessionStorage.authToken
+                        ? { Authorization: 'Bearer ' + sessionStorage.authToken }
+                        : {})
+            },
+            body: JSON.stringify({ query, variables })
+        })
+        let a = await obj.json()
+        if (!a.data && a.errors)
+            throw new Error(JSON.stringify(a.errors))
+        return a.data[Object.keys(a.data)[0]]
+    }
 
 
-//*************** ACTIONS PROMISE ******************//
+export const backURL = 'http://hipstagram.asmer.fs.a-level.com.ua'
 
 
+export const gql = getGQL(backURL + '/graphql');
 
 
-export const actionPending = name => ({ type: 'PROMISE', status: 'PENDING', name })
-export const actionResolved = (name, payload) => ({ type: 'PROMISE', status: 'RESOLVED', name, payload })
-export const actionRejected = (name, error) => ({ type: 'PROMISE', status: 'REJECTED', name, error })
-export const actionClearPromise = (name) => ({ type: 'CLEAR-PROMISE', name })
-export const actionPromise = (name, promise) => ({ type: 'PROMISE_START', name, promise })
 
 
 
 
 //*************** ACTIONS AUTHORIZATION ******************//
 //*************** ACTIONS AUTHORIZATION ******************//
 
 
 
 
-export const actionAuthLogin = (token, remember) => ({ type: 'AUTH-LOGIN', token, remember })
-export const actionAuthLogout = () => ({ type: 'AUTH-LOGOUT' })
-
 export const actionLogIn = (login, password) =>
 export const actionLogIn = (login, password) =>
     actionPromise('login', gql(`query login($login:String!, $password:String!){
     actionPromise('login', gql(`query login($login:String!, $password:String!){
                 login(login:$login, password:$password)
                 login(login:$login, password:$password)
             }`, { login, password }))
             }`, { login, password }))
 
 
-export const actionFullLogIn = (login, password, remember) => ({ type: 'FULL_LOGIN', login, password, remember })
-export const actionFullRegister = (login, password, remember) => ({ type: 'FULL_REGISTER', login, password, remember })
-
 export const actionRegister = (login, password) =>
 export const actionRegister = (login, password) =>
-    actionPromise('register', gql(`mutation rega ($login:String!, $password:String!){
+    actionPromise('register', gql(`mutation rega ($login:String!,           $password:String!){
                                     createUser(login: $login, password: $password){
                                     createUser(login: $login, password: $password){
                                         _id login
                                         _id login
                                     }
                                     }
@@ -35,13 +44,8 @@ export const actionRegister = (login, password) =>
 
 
 //*************** Action ABOUT ME ******************//
 //*************** Action ABOUT ME ******************//
 
 
-export const actionAboutMeAC = (data) => ({ type: 'ABOUTME-DATA-ADD', data })
-export const actionFullAboutMe = () => ({ type: 'ABOUT_ME' })
-export const actionRemoveMyDataAC = () => ({ type: 'REMOVE-MYDATA' })
-export const actionFullAboutMeUpsert = (nick, login) => ({ type: 'ABOUT_ME_UPSERT', nick, login })
 
 
-
-export const actionAboutMe = (id) =>
+export const actionGetAboutMe = (id) =>
     actionPromise('aboutMe', gql(`query userOned($myID:String!){
     actionPromise('aboutMe', gql(`query userOned($myID:String!){
                         UserFindOne(query: $myID){
                         UserFindOne(query: $myID){
                             _id  login nick
                             _id  login nick
@@ -53,21 +57,15 @@ export const actionAboutMe = (id) =>
 export const actionUpsertAboutMe = (myData) =>
 export const actionUpsertAboutMe = (myData) =>
     actionPromise('upsertAboutMe', gql(`mutation editAboutMe($user:UserInput){
     actionPromise('upsertAboutMe', gql(`mutation editAboutMe($user:UserInput){
                         UserUpsert(user:$user){
                         UserUpsert(user:$user){
-                            _id   _id  login nick
-                            avatar { _id url }
-                            following{ _id}
+                            _id 
                         }
                         }
                 }`, { user: myData }))
                 }`, { user: myData }))
 
 
 
 
-//*************** Action Posts Feed ******************//
+//*************** Action Posts Tape ******************//
 
 
 
 
-export const actionAddPostAC = (postsData, count) => ({ type: 'ADD-POSTS', newResult: postsData, count })
-export const actionRemovePostAC = () => ({ type: 'REMOVE-POSTS' })
-export const actionPostsFeed = () => ({ type: 'POSTS_FEED' })
-
-export const actionPostsMyFollowing = (skip, myFollowing) =>
+export const actionGetPostsMyFollowing = (skip, myFollowing) =>
     actionPromise('followingPosts',
     actionPromise('followingPosts',
         gql(`query allposts($query: String!){
         gql(`query allposts($query: String!){
             PostFind(query:$query){
             PostFind(query:$query){
@@ -89,19 +87,16 @@ export const actionPostsMyFollowing = (skip, myFollowing) =>
             }])
             }])
         }))
         }))
 
 
-export const actionPostsCount = (_id) =>
+export const actionGetPostsTapeCount = (_id) =>
     actionPromise('userPostsCount', gql(` query userPostsCount($id:String!){
     actionPromise('userPostsCount', gql(` query userPostsCount($id:String!){
                 PostCount(query:$id)
                 PostCount(query:$id)
                 }`, { id: JSON.stringify([{ ___owner: { $in: _id } }]) }))
                 }`, { id: JSON.stringify([{ ___owner: { $in: _id } }]) }))
 
 
 
 
-//*************** Action Posts Profile ******************//
-
+//*************** Action Profile Data ******************//
 
 
-export const actionProfileDataAC = (postsData, count, userData) => ({ type: 'ADD-PROFILE-DATA', newResult: postsData, count, userData })
-export const actionProfilePageData = (id) => ({ type: 'DATA_PROFILE', id })
 
 
-export const actionProfileData = (_id) =>
+export const actionGetProfileData = (_id) =>
     actionPromise('userOneData', gql(` query userOned($id:String!){
     actionPromise('userOneData', gql(` query userOned($id:String!){
                         UserFindOne(query: $id){
                         UserFindOne(query: $id){
                             _id  login nick
                             _id  login nick
@@ -112,7 +107,7 @@ export const actionProfileData = (_id) =>
                 
                 
             } `, { id: JSON.stringify([{ _id }]) }))
             } `, { id: JSON.stringify([{ _id }]) }))
 
 
-export const actionProfilePagePost = (_id, skip) => actionPromise('userOneDataPosts', gql(` query userOned($id:String!){
+export const actionGetProfilePagePosts = (_id, skip) => actionPromise('profilePosts', gql(` query userOned($id:String!){
                     PostFind(query:$id){
                     PostFind(query:$id){
                         _id   images{ url _id originalFileName }
                         _id   images{ url _id originalFileName }
                     }
                     }
@@ -131,8 +126,6 @@ export const actionProfilePagePost = (_id, skip) => actionPromise('userOneDataPo
 //****************---All FIND POSTS---*************************//
 //****************---All FIND POSTS---*************************//
 
 
 
 
-export const actionAllPosts = () => ({ type: 'ALL_POSTS' })
-
 export const actionGetAllPosts = (skip) =>
 export const actionGetAllPosts = (skip) =>
     actionPromise('allPosts', gql(` query allPosts($id:String!){
     actionPromise('allPosts', gql(` query allPosts($id:String!){
                 PostFind(query:$id){
                 PostFind(query:$id){
@@ -152,12 +145,10 @@ export const actionAllPostsCount = () =>
                 }`, { id: JSON.stringify([{}]) }))
                 }`, { id: JSON.stringify([{}]) }))
 
 
 
 
-//****************---Action FindUsers ---*************************//
+//****************---Action getAllUsers ---*************************//
 
 
 
 
-export const actionSearchUsers = (value) => ({ type: 'SEARCH_USERS', value })
-
-export const actionLoadSearchUsers = (value) =>
+export const actionGetAllUsers = (value) =>
     actionPromise('findUsersAll', gql(`query findUsersAll($query:String!) {
     actionPromise('findUsersAll', gql(`query findUsersAll($query:String!) {
                                 UserFind(query: $query) {
                                 UserFind(query: $query) {
                                     _id login nick 
                                     _id login nick 
@@ -177,82 +168,78 @@ export const actionLoadSearchUsers = (value) =>
 //****************---Action Like Post ---*************************//
 //****************---Action Like Post ---*************************//
 
 
 
 
-export const actionAddLikePostAC = (findId, newResult) => ({ type: 'ADD-POST-LIKE', findId, newResult })
-export const actionRemoveLikePostAC = (findId, newResult) => ({ type: 'REMOVE-POST-LIKE', findId, newResult })
-export const actionLikePost = (postId) => ({ type: 'LIKE_POST', postId })
-export const actionDelLikePost = (likeId, postId) => ({ type: 'DEL_LIKE_POST', likeId, postId })
-
-export const actionAddLikePost = (_id) =>
-    actionPromise('likePost', gql(`mutation LikePost($like:LikeInput){
+export const actionOnLikePost = (_id) =>
+    actionPromise('onLikePost', gql(`mutation LikePost($like:LikeInput){
         LikeUpsert(like:$like){
         LikeUpsert(like:$like){
             _id
             _id
         }
         }
     }`, { like: { post: { _id } } }))
     }`, { like: { post: { _id } } }))
 
 
-export const actionRemoveLikePost = (_id) =>
-    actionPromise('removelikePost', gql(`mutation LikeRemove($like:LikeInput){
+export const actionDelLikePost = (_id) =>
+    actionPromise('delLikePost', gql(`mutation LikeRemove($like:LikeInput){
             LikeDelete(like:$like){
             LikeDelete(like:$like){
                 _id
                 _id
             }
             }
         }`, { like: { _id } }))
         }`, { like: { _id } }))
 
 
-export const actionMyLikePost = (findId) =>
-    actionPromise('myLikes', gql(`query likeFindPost ($id:String!){
+export const actionGetMyLikePosts = (findId) =>
+    actionPromise('getMyLikes', gql(`query likeFindPost ($id:String!){
         PostFindOne(query:$id){
         PostFindOne(query:$id){
         likes { _id owner {_id}}
         likes { _id owner {_id}}
         }
         }
     }`, { id: JSON.stringify([{ _id: findId }]) }))
     }`, { id: JSON.stringify([{ _id: findId }]) }))
 
 
+export const actionGetPostUsersLiked = (_id) =>
+    actionPromise('usersPostLiked', gql(` query usersPostLiked($id:String!) {
+                                        LikeFind(query:$id){
+                                          owner { _id nick login
+                                                avatar{_id url}
+                                    }
+                }
+            } `, { id: JSON.stringify([{ "post._id": _id }]) }))
 
 
-//****************---Action Like Comment ---*************************//
 
 
+//****************---Action Like Comment ---*************************//
 
 
-export const actionUpsertLikeCommentAC = (findId, newResult) => ({ type: 'UPSERT-LIKE-COMMENT', findId, newResult })
-export const actionLikeComment = (commentId) => ({ type: 'LIKE_COMMENT', commentId })
-export const actionDelLikeComment = (likeId, commentId) => ({ type: 'DEL_LIKE_COMMENT', likeId, commentId })
 
 
-export const actionAddLikeComment = (_id) =>
+export const actionOnLikeComment = (_id) =>
     actionPromise('likePost', gql(`mutation LikePost($like:LikeInput){
     actionPromise('likePost', gql(`mutation LikePost($like:LikeInput){
         LikeUpsert(like:$like){
         LikeUpsert(like:$like){
             _id
             _id
         }
         }
     }`, { like: { comment: { _id } } }))
     }`, { like: { comment: { _id } } }))
 
 
-export const actionRemoveLikeComment = (_id) =>
+export const actionDelLikeComment = (_id) =>
     actionPromise('removelikeComment', gql(`mutation LikeRemove($like:LikeInput){
     actionPromise('removelikeComment', gql(`mutation LikeRemove($like:LikeInput){
             LikeDelete(like:$like){_id}
             LikeDelete(like:$like){_id}
         }`, { like: { _id } }))
         }`, { like: { _id } }))
 
 
-export const actionFindLikeComment = (findId) =>
+export const actionGetLikeComment = (commentId) =>
     actionPromise('findLikeComment', gql(`query findLikeComment ($id:String!){
     actionPromise('findLikeComment', gql(`query findLikeComment ($id:String!){
         CommentFindOne(query:$id){
         CommentFindOne(query:$id){
         likes { _id owner {_id}}
         likes { _id owner {_id}}
         }
         }
-    }`, { id: JSON.stringify([{ _id: findId }]) }))
+    }`, { id: JSON.stringify([{ _id: commentId }]) }))
 
 
 
 
 //****************---Collection---*************************//
 //****************---Collection---*************************//
 
 
 
 
-export const actionUpsertCollectionAC = (data) => ({ type: 'UPSERT-COLLECTION', data })
-export const actionHandlerUpsertCollection = (_id, flag) => ({ type: 'HANDLER_UPSERT_COLLECTION', _id, flag })
-export const actionFullMyCollectionLoad = () => ({ type: 'LOAD_COLLECTION' })
+export const actionGetMyCollection = (_id) =>
+    actionPromise('getMyCollection', gql(`query getCollections($id:String! ){
+        CollectionFindOne(query:$id){
+        _id posts{ _id }
+        }
+    }`, { id: JSON.stringify([{ ___owner: _id }]) }))
 
 
-export const actionAddPostInCollections = (collectionId, newCollection) =>
+export const actionUpsertPostsInCollections = (collectionId, newCollection) =>
     actionPromise('addInCollections', gql(`mutation addInCollections($collection:CollectionInput ){
     actionPromise('addInCollections', gql(`mutation addInCollections($collection:CollectionInput ){
         CollectionUpsert(collection:$collection){
         CollectionUpsert(collection:$collection){
             _id 
             _id 
         }
         }
     }`, { collection: { _id: collectionId, posts: newCollection } }))
     }`, { collection: { _id: collectionId, posts: newCollection } }))
 
 
-export const actionFindMyCollections = (_id) =>
-    actionPromise('findMyCollections', gql(`query findCollections($id:String! ){
-        CollectionFindOne(query:$id){
-        _id text posts{_id }
-        }
-    }`, { id: JSON.stringify([{ ___owner: _id }]) }))
-
-export const actionOnLoadMyCollection = (_id, skip) =>
+export const actionGetPostsMyCollection = (_id, skip) =>
     actionPromise('onLoadMyCollections', gql(`query loadCollections($id:String! ){
     actionPromise('onLoadMyCollections', gql(`query loadCollections($id:String! ){
        CollectionFind(query:$id){
        CollectionFind(query:$id){
          posts { _id  images{ _id url originalFileName}}
          posts { _id  images{ _id url originalFileName}}
@@ -268,29 +255,21 @@ export const actionOnLoadMyCollection = (_id, skip) =>
 
 
 //****************---Action Subscribe ---*************************//
 //****************---Action Subscribe ---*************************//
 
 
-
-export const actionUpdateMyFollowingAC = (data) => ({ type: 'UPDATE-MY-FOLLOWING', data })
-export const actionUpdateFollowersAC = (newResult) => ({ type: 'UPDATE-FOLLOWERS', newResult })
-
-export const actionSubscribe = (userId) => ({ type: 'SUBSCRIBE', userId })
-export const actionUnSubscribe = (userId) => ({ type: 'UN_SUBSCRIBE', userId })
-
-export const actionChangeSubscribe = (newFollowing) =>
+export const actionChangeSubscribed = (newFollowing) =>
     actionPromise('subscribe', gql(`mutation following($user:UserInput){
     actionPromise('subscribe', gql(`mutation following($user:UserInput){
         UserUpsert( user:$user){
         UserUpsert( user:$user){
             following{_id}
             following{_id}
         }
         }
       }`, { user: newFollowing }))
       }`, { user: newFollowing }))
 
 
-
-export const actionUpdateMyFollowing = (_id) =>
+export const actiongetMyFollowing = (_id) =>
     actionPromise('upDateFollowing', gql(` query followers($id:String!){
     actionPromise('upDateFollowing', gql(` query followers($id:String!){
         UserFindOne(query: $id){
         UserFindOne(query: $id){
                             following {_id}
                             following {_id}
         }
         }
     }`, { id: JSON.stringify([{ _id }]) }))
     }`, { id: JSON.stringify([{ _id }]) }))
 
 
-export const actionUpdateFollowers = (_id) =>
+export const actionGetUserFollowers = (_id) =>
     actionPromise('upDateFollowers', gql(` query followers($id:String!){
     actionPromise('upDateFollowers', gql(` query followers($id:String!){
         UserFindOne(query: $id){
         UserFindOne(query: $id){
                             followers {_id nick login}
                             followers {_id nick login}
@@ -301,14 +280,6 @@ export const actionUpdateFollowers = (_id) =>
 //****************---Action Comments ---*************************//
 //****************---Action Comments ---*************************//
 
 
 
 
-export const actionAddCommentAC = (findId, newResult) => ({ type: 'ADD-COMMENT', findId, newResult })
-export const actionUpdateSubCommentAC = (findId, newResult) => ({ type: 'UPDATE-SUBCOMMENT', findId, newResult })
-export const actionEditCommentAC = (findId, newResult) => ({ type: 'EDIT-COMMENT', findId, newResult })
-export const actionEditComment = (commentId, text) => ({ type: 'COMMENT_EDIT', commentId, text })
-export const actionFullAddComment = (postId, text) => ({ type: 'COMMENT_POST', postId, text })
-export const actionAddSubComment = (commentId, text) => ({ type: 'ADD_SUB_COMMENT', commentId, text })
-export const actionSubComment = (commentId) => ({ type: 'FIND_SUBCOMMENT', commentId })
-
 export const actionAddComment = (postId, text) =>
 export const actionAddComment = (postId, text) =>
     actionPromise('addcomment', gql(`mutation addcomment($comment: CommentInput ){
     actionPromise('addcomment', gql(`mutation addcomment($comment: CommentInput ){
         CommentUpsert(comment:$comment){
         CommentUpsert(comment:$comment){
@@ -316,8 +287,8 @@ export const actionAddComment = (postId, text) =>
         }
         }
     }`, { comment: { post: { _id: postId }, text } }))
     }`, { comment: { post: { _id: postId }, text } }))
 
 
-export const actionFindComment = (findId) =>
-    actionPromise('findCommentPost', gql(`query commentFindPost ($id:String!){
+export const actionGetCommentPost = (findId) =>
+    actionPromise('commentPost', gql(`query commentFindPost ($id:String!){
         PostFindOne(query:$id){
         PostFindOne(query:$id){
             comments {
             comments {
                 _id text createdAt 
                 _id text createdAt 
@@ -332,23 +303,23 @@ export const actionFindComment = (findId) =>
         }
         }
     }`, { id: JSON.stringify([{ _id: findId }]) }))
     }`, { id: JSON.stringify([{ _id: findId }]) }))
 
 
-export const actionFindSubComment = (findId) =>
+export const actionGetSubComment = (commentId) =>
     actionPromise('subComments', gql(`query commentFindOne ($id:String!){
     actionPromise('subComments', gql(`query commentFindOne ($id:String!){
-        CommentFindOne(query:$id){
-       _id text answers { 
-                _id text
-                post {_id }
-                answers { _id}
-                createdAt
-                likes { _id owner { _id login nick } }
-                owner {
-                    _id login nick 
-                    avatar { url } 
-                    } 
-                }
-        } 
-    }`, {
-        id: JSON.stringify([{ _id: findId }])
+                                CommentFindOne(query:$id){
+                                _id text answers { 
+                                        _id text
+                                        post {_id }
+                                        answers { _id}
+                                        createdAt
+                                        likes { _id owner { _id login nick } }
+                                        owner {
+                                            _id login nick 
+                                            avatar { url } 
+                                            } 
+                                        }
+                                } 
+                            }`, {
+        id: JSON.stringify([{ _id: commentId }])
     }))
     }))
 
 
 export const actionSubAddComment = (commentId, text) =>
 export const actionSubAddComment = (commentId, text) =>
@@ -358,7 +329,7 @@ export const actionSubAddComment = (commentId, text) =>
         }
         }
     }`, { comment: { answerTo: { _id: commentId }, text } }))
     }`, { comment: { answerTo: { _id: commentId }, text } }))
 
 
-export const actionFindCommentText = (findId) =>
+export const actionGetCommentOne = (findId) =>
     actionPromise('subComments', gql(`query commentFindOne ($id:String!){
     actionPromise('subComments', gql(`query commentFindOne ($id:String!){
         CommentFindOne(query:$id){
         CommentFindOne(query:$id){
        _id text 
        _id text 
@@ -367,7 +338,7 @@ export const actionFindCommentText = (findId) =>
         id: JSON.stringify([{ _id: findId }])
         id: JSON.stringify([{ _id: findId }])
     }))
     }))
 
 
-export const actionUpsertEditComment = (commentId, text) =>
+export const actionEditComment = (commentId, text) =>
     actionPromise('editcomment', gql(`mutation addSubcomment($comment: CommentInput ){
     actionPromise('editcomment', gql(`mutation addSubcomment($comment: CommentInput ){
         CommentUpsert(comment:$comment){
         CommentUpsert(comment:$comment){
             _id text
             _id text
@@ -378,9 +349,6 @@ export const actionUpsertEditComment = (commentId, text) =>
 //****************---Action Udate Avatar ---*************************//
 //****************---Action Udate Avatar ---*************************//
 
 
 
 
-export const actionUpdateAvatar = (file) => ({ type: 'UPDATE_AVATAR', file })
-export const actionUpdateMyAvatart = (data) => ({ type: 'ABOUTME-UPDATE-AVATAR', data })
-
 export const actionSetAvatar = (file, id) =>
 export const actionSetAvatar = (file, id) =>
     actionPromise('uploadPhoto', gql(`mutation avaUpsert($ava: UserInput){
     actionPromise('uploadPhoto', gql(`mutation avaUpsert($ava: UserInput){
                 UserUpsert(user: $ava){
                 UserUpsert(user: $ava){
@@ -397,11 +365,8 @@ export const actionGetAvatar = (id) =>
     }`, { myID: JSON.stringify([{ _id: id }]) }))
     }`, { myID: JSON.stringify([{ _id: id }]) }))
 
 
 
 
-//****************--- Find FOllowing/Follovwrs---*************************//
+//****************--- Get user FOllowing/Follovwrs---*************************//
 
 
-export const actionFindFollowing = (_id) => ({ type: 'FIND_FOLLOWING', _id })
-export const actionFindFollowers = (_id) => ({ type: 'FIND_FOLLOWERS', _id })
-export const actionFindLiked = (_id) => ({ type: 'FIND_LIKED', _id })
 
 
 export const actionGetFindFollowing = (_id) =>
 export const actionGetFindFollowing = (_id) =>
     actionPromise('findFollow', gql(` query findFollowing($id:String!){
     actionPromise('findFollow', gql(` query findFollowing($id:String!){
@@ -425,22 +390,11 @@ export const actionGetFindFollowers = (_id) =>
                 }
                 }
             } `, { id: JSON.stringify([{ _id }]) }))
             } `, { id: JSON.stringify([{ _id }]) }))
 
 
-export const actionGetFindLiked = (_id) =>
-    actionPromise('findLiked', gql(` query LikeFindPost($id:String!) {
-                                        LikeFind(query:$id){
-                                          owner { _id nick login
-                                                avatar{_id url}
-                                    }
-                }
-            } `, { id: JSON.stringify([{ "post._id": _id }]) }))
-
-
-//****************---Create Post ---*************************/
 
 
+//****************--- Create / Edit Post ---*************************/
 
 
-export const actionFullSentPost = (images, title, text) => ({ type: 'CREATE_POST', images, text, title })
 
 
-export const actionUpsertPost = (upSertPostObj) =>
+export const actionCreatOrEditPost = (upSertPostObj) =>
     actionPromise('sentPost', gql(`mutation sentPost($post: PostInput){
     actionPromise('sentPost', gql(`mutation sentPost($post: PostInput){
               PostUpsert(post: $post){
               PostUpsert(post: $post){
                     _id images{_id url originalFileName}
                     _id images{_id url originalFileName}

+ 138 - 0
src/actions/actonsCreators.js

@@ -0,0 +1,138 @@
+//*************** ACTIONS PROMISE ******************//
+
+export const actionPending = name => ({ type: 'PROMISE', status: 'PENDING', name })
+export const actionResolved = (name, payload) => ({ type: 'PROMISE', status: 'RESOLVED', name, payload })
+export const actionRejected = (name, error) => ({ type: 'PROMISE', status: 'REJECTED', name, error })
+export const actionClearPromise = (name) => ({ type: 'CLEAR-PROMISE', name })
+export const actionPromise = (name, promise) => ({ type: 'PROMISE_START', name, promise })
+
+
+//*************** ActionCreator Authorization ******************//
+
+
+export const actionAuthLoginAC = (token, remember) => ({ type: 'AUTH-LOGIN', token, remember })
+export const actionAuthLogoutAC = () => ({ type: 'AUTH-LOGOUT' })
+
+export const actionFullLogInSagaAC = (login, password, remember) => ({ type: 'FULL_LOGIN', login, password, remember })
+export const actionFullRegisterSagaAC = (login, password, remember) => ({ type: 'FULL_REGISTER', login, password, remember })
+
+
+//*************** ActionCreator ABOUT ME ******************//
+
+
+export const actionAboutMeAC = (data) => ({ type: 'ABOUTME-DATA-ADD', data })
+export const actionClearAboutMeDataAC = () => ({ type: 'CLEAR-ABOUTME' })
+
+export const actionAboutMeSagaAC = () => ({ type: 'ABOUT_ME' })
+export const actionAboutMeUpsertSagaAC = (nick, login) => ({ type: 'ABOUT_ME_UPSERT', nick, login })
+
+
+//*************** ActionCreator TAPE POSTS ******************//
+
+
+export const actionAddPostsInPostsTapeAC = (newResult, count) => ({ type: 'POSTS-TAPE', newResult, count })
+export const actionClearPostsTapeAC = () => ({ type: 'CLEAR-POSTS-TAPE' })
+export const actionGetPostsTapeSagaAC = () => ({ type: 'GET_POSTS_TAPE' })
+
+
+//*************** ActionCreator POST ONE ******************//
+
+
+export const actionPostOneDataAC = (newResult) => ({ type: 'POST-ONE-DATA', newResult })
+
+export const actionClearPostsOneAC = () => ({ type: 'CLEAR-POST-ONE' })
+
+
+//*************** ActionCreator LIKE POSTS ******************//
+
+
+export const actionChangeStatusLikePostTapeAC = (postId, newResult) => ({ type: 'POSTS-TAPE-LIKE', postId, newResult })
+
+export const actionChangeLikePostTapeSagaAC = (postId, likeId) => ({ type: 'CHANGE_LIKE_POST_TAPE', postId, likeId })
+
+
+export const actionChangeStatusLikePostOneAC = (postId, newResult) => ({ type: 'POST-ONE-LIKE', postId, newResult })
+
+export const actionChangeLikePostOneSagaAC = (postId, likeId) => ({ type: 'CHANGE_LIKE_POST_ONE', postId, likeId })
+
+
+//**************** ActionCreator Collection *********************//
+
+
+export const actionUpsertCollectionAC = (data) => ({ type: 'UPSERT-COLLECTION', data })
+export const actionHandlerUpsertCollectionSagaAC = (_id, flag) => ({ type: 'HANDLER_UPSERT_COLLECTION', _id, flag })
+
+export const actionGetPostsMyCollectionSagaAC = () => ({ type: 'LOAD_COLLECTION' })
+
+
+//**************** ActionCreator Comments **********************//
+
+
+export const actionAddCommentPostInTapeAC = (postId, newResult) => ({ type: 'ADD-COMMENT-POST-TAPE', postId, newResult })
+
+export const actionAddCommentPostInTapeSagaAC = (postId, text) => ({ type: 'ADD_COMMENT_POST_TAPE', postId, text })
+
+
+export const actionAddCommentPostOneAC = (postId, newResult) => ({ type: 'POST-ONE-ADD-COMMENT', postId, newResult })
+
+export const actionAddCommentPostOneSagaAC = (postId, text) => ({ type: 'ADD_COMMENT_POST_ONE', postId, text })
+
+
+export const actionEditCommentAC = (commentId, newResult) => ({ type: 'EDIT-COMMENT', commentId, newResult })
+export const actionEditCommentSagaAC = (commentId, text) => ({ type: 'EDIT_COMMENT', commentId, text })
+
+
+export const actionUpdateCommentAC = (commentId, newResult) => ({ type: 'UPDATE-COMMENT', commentId, newResult })
+
+export const actionGetSubCommentSagaAC = (commentId) => ({ type: 'GET_SUBCOMMENT', commentId })
+
+export const actionAddSubComment = (commentId, text) => ({ type: 'ADD_SUB_COMMENT', commentId, text })
+
+
+//****************  ActionCreator Like Comment  *************************//
+
+
+export const actionLikeCommentAC = (commentId, newResult) => ({ type: 'LIKE-COMMENT', commentId, newResult })
+
+export const actionChangeLikeCommentSagaAC = (commentId, likeId) => ({ type: 'CHANGE_LIKE_COMMENT', commentId, likeId })
+
+
+//****************  ActionCreator FindUsers *************************//
+
+
+export const actionSearchAllUsers = (value) => ({ type: 'SEARCH_USERS', value })
+
+
+//****************  ActionCreator All Posts Users *************************//
+
+
+export const actionGetAllPostsSagaAC = () => ({ type: 'ALL_POSTS' })
+
+
+//****************  ActionCreator Profile User **************//
+
+
+export const actionProfileDataAC = (data) => ({ type: 'PROFILE-DATA', data })
+export const actionClearProfileDataAC = () => ({ type: 'CLEAR-PROFILE-DATA' })
+
+export const actionProfileDataSagaAC = (id) => ({ type: 'DATA_PROFILE', id })
+
+
+//****************  Action Subscribe *****************//
+
+export const actionUpdateMyFollowingAC = (data) => ({ type: 'UPDATE-MY-FOLLOWING', data })
+export const actionUpdateUserFollowersAC = (data) => ({ type: 'UPDATE-USER-FOLLOWERS', data })
+
+export const actionChangeSubscribeSagaAC = (userId, followCheck) => ({ type: 'CHANGE_SUBSCRIBE', userId, followCheck })
+
+
+//****************  Action Change Avatar *****************//
+
+export const actionChangeMyAvatartAC = (data) => ({ type: 'CHANGE-ABOUTME-AVATAR', data })
+export const actionChangeAvatarSagaAC = (file) => ({ type: 'UPDATE_AVATAR', file })
+
+
+//****************  Action Change Avatar *****************//
+
+
+export const actionCreatePostSagaAC = (images, title, text) => ({ type: 'CREATE_POST', images, text, title })

+ 6 - 6
src/components/main/profilePage/EditAvatar.js

@@ -1,13 +1,13 @@
-import { EditOutlined,} from '@ant-design/icons';
+import { EditOutlined, } from '@ant-design/icons';
 import { connect } from 'react-redux';
 import { connect } from 'react-redux';
 import { Upload, message, } from 'antd';
 import { Upload, message, } from 'antd';
-import {  propsUploadFile } from '../../../helpers';
-import { actionUpdateAvatar } from '../../../actions';
 import ImgCrop from 'antd-img-crop';
 import ImgCrop from 'antd-img-crop';
-import { UserAvatar } from '../../header/UserAvatar';
+import { actionChangeAvatarSagaAC } from '../actions/actonsCreators';
+import { propsUploadFile } from '../helpers';
+import { UserAvatar } from './UserAvatar';
 
 
 
 
-const EditAvatar = ({ avatar, onUploadFile }) => {
+const ChangeAvatar = ({ avatar, onUploadFile }) => {
     const handleChange = ({ file }) => {
     const handleChange = ({ file }) => {
         if (file.status === 'done') {
         if (file.status === 'done') {
             message.success(`${file.name} file uploaded successfully`);
             message.success(`${file.name} file uploaded successfully`);
@@ -32,4 +32,4 @@ const EditAvatar = ({ avatar, onUploadFile }) => {
     )
     )
 }
 }
 
 
-export const CEditAvatar = connect(state => ({ avatar: state?.myData?.avatar }), { onUploadFile: actionUpdateAvatar })(EditAvatar)
+export const CChangeAvatar = connect(state => ({ avatar: state?.aboutMe?.avatar }), { onUploadFile: actionChangeAvatarSagaAC })(ChangeAvatar)

+ 24 - 25
src/components/main/postsFeed/FieldComment.jsx

@@ -4,10 +4,11 @@ import TextArea from 'antd/lib/input/TextArea'
 import { SendOutlined, } from '@ant-design/icons'
 import { SendOutlined, } from '@ant-design/icons'
 import { connect } from 'react-redux'
 import { connect } from 'react-redux'
 import { Button, Col, Row } from 'antd'
 import { Button, Col, Row } from 'antd'
-import { actionAddSubComment, actionEditComment, actionFullAddComment } from '../../../actions'
+import { actionAddCommentPostInTapeSagaAC, actionAddCommentPostOneSagaAC, actionAddSubComment, actionEditCommentSagaAC } from '../actions/actonsCreators'
 
 
 
 
-const FieldCommentSend = ({ id, sentComment, autoFocus, value = '', setOpen, rows = 1,bordered=false }) => {
+
+const CommentField = ({ id, sentComment, autoFocus, value = '', setOpen, rows = 2, bordered = false }) => {
     const [commentValue, setCommentValue] = useState(value)
     const [commentValue, setCommentValue] = useState(value)
     const [error, setError] = useState(false)
     const [error, setError] = useState(false)
 
 
@@ -15,30 +16,26 @@ const FieldCommentSend = ({ id, sentComment, autoFocus, value = '', setOpen, row
         setCommentValue(e.currentTarget.value)
         setCommentValue(e.currentTarget.value)
         setError(false)
         setError(false)
     }
     }
-    const sendCommentValid = (value) => {
-        if (value.trim() !== '') {
-            sentComment(id, value.trim())
+
+    const sendCommentValid = () => {
+        if (commentValue.trim() !== '') {
+            sentComment(id, commentValue.trim())
             setCommentValue('')
             setCommentValue('')
+            setOpen(false)
         } else {
         } else {
             setError(true)
             setError(true)
         }
         }
     }
     }
 
 
-    const handlerClickBtn = () => {
-        sendCommentValid(commentValue)
-        setOpen(false)
-    }
-
-    const onKeyPressHandler = e => {
-        if (e.charCode === 13) {
-            sendCommentValid(commentValue)
-            setOpen(false)
-        }
-    }
-
     return (
     return (
-        <>
-            {error && <Text type='danger'>Field is required</Text>}
+        <div>
+            {error &&
+                <Text
+                    type='danger'
+                    style={{ display: 'inherit', textAlign: 'center' }}
+                >
+                    Field is required
+                </Text>}
             <Row align='middle' className='Post__send-comment'>
             <Row align='middle' className='Post__send-comment'>
                 <Col flex='auto' offset={1}>
                 <Col flex='auto' offset={1}>
                     <TextArea value={commentValue}
                     <TextArea value={commentValue}
@@ -47,23 +44,25 @@ const FieldCommentSend = ({ id, sentComment, autoFocus, value = '', setOpen, row
                         autoSize={{ minRows: 1, maxRows: rows }}
                         autoSize={{ minRows: 1, maxRows: rows }}
                         onChange={changeComentTextarea}
                         onChange={changeComentTextarea}
                         bordered={bordered}
                         bordered={bordered}
-                        onKeyPress={onKeyPressHandler}
+                        maxLength={150}
                     />
                     />
                 </Col>
                 </Col>
                 <Col span={2}>
                 <Col span={2}>
                     <Button
                     <Button
-                        onClick={handlerClickBtn}
+                        onClick={sendCommentValid}
                         icon={< SendOutlined
                         icon={< SendOutlined
                             style={{ fontSize: '1.2em', opacity: .6 }} />}
                             style={{ fontSize: '1.2em', opacity: .6 }} />}
                     />
                     />
                 </Col>
                 </Col>
             </Row>
             </Row>
-        </>
+        </div>
     )
     )
 }
 }
 
 
-export const CFieldCommentSend = connect(null, { sentComment: actionFullAddComment })(FieldCommentSend)
+export const CCommentFieldPostTape = connect(null, { sentComment: actionAddCommentPostInTapeSagaAC })(CommentField)
+
+export const CCommentFieldPostOne = connect(null, { sentComment: actionAddCommentPostOneSagaAC })(CommentField)
 
 
-export const CFieldSubCommentSend = connect(null, { sentComment: actionAddSubComment })(FieldCommentSend)
+export const CFieldSubComment = connect(null, { sentComment: actionAddSubComment })(CommentField)
 
 
-export const CFieldUpsertCommentSend = connect(null, { sentComment: actionEditComment })(FieldCommentSend)
+export const CFieldEditCommentSend = connect(null, { sentComment: actionEditCommentSagaAC})(CommentField)

+ 0 - 11
src/pages/Content.jsx

@@ -2,8 +2,6 @@ import { Col, Row } from 'antd'
 import React from 'react'
 import React from 'react'
 
 
 
 
-
-
 export const Container = ({ children }) =>
 export const Container = ({ children }) =>
     <Row justify='center' className='Main__inner'>
     <Row justify='center' className='Main__inner'>
         <Col xs={{ span: 24 }} sm={{ span: 20 }} md={{ span: 16 }} lg={{ span: 14 }} xl={{ span: 12 }} >
         <Col xs={{ span: 24 }} sm={{ span: 20 }} md={{ span: 16 }} lg={{ span: 14 }} xl={{ span: 12 }} >
@@ -12,12 +10,3 @@ export const Container = ({ children }) =>
     </Row>
     </Row>
 
 
 
 
-export const Main = ({ children }) =>
-    <div className='Main'>{children}</div>
-
-
-
-
-export const Content = ({ children }) =>
-    <>{children}</>
-

+ 0 - 11
src/components/Footer.jsx

@@ -1,11 +0,0 @@
-import { Footer } from 'antd/lib/layout/layout';
-import React from 'react';
-import { CUserNavIcon } from './header/Header';
-
-export const FooterComponent = () => {
-    return (
-        <Footer style={{ position: 'fixed', zIndex: 3, width: '100%', bottom: 0 }}>
-            <CUserNavIcon />
-        </Footer>
-    )
-};

+ 9 - 0
src/components/FooterComponent.jsx

@@ -0,0 +1,9 @@
+import { Footer } from 'antd/lib/layout/layout';
+import React from 'react';
+import { CUserNavIcon } from './header/Header';
+
+
+export const FooterComponet = () =>
+    <Footer style={{ position: 'fixed', zIndex: 3, width: '100%', bottom: 0 }}>
+        <CUserNavIcon />
+    </Footer>

+ 6 - 6
src/components/FormAuthorization.jsx

@@ -2,13 +2,14 @@ import React, { useEffect, useState } from 'react'
 import { connect } from 'react-redux'
 import { connect } from 'react-redux'
 import { Form, Input, Button, Checkbox, message } from 'antd';
 import { Form, Input, Button, Checkbox, message } from 'antd';
 import { UserOutlined, LockOutlined } from '@ant-design/icons';
 import { UserOutlined, LockOutlined } from '@ant-design/icons';
-import { actionFullLogIn, actionFullRegister } from '../actions';
+import { actionFullLogInSagaAC, actionFullRegisterSagaAC } from '../actions/actonsCreators';
+
 
 
 const FormAuthorization = ({ buttonTitle, onSignIn, loginChek }) => {
 const FormAuthorization = ({ buttonTitle, onSignIn, loginChek }) => {
     const [loading, setLoading] = useState(false);
     const [loading, setLoading] = useState(false);
     useEffect(() => {
     useEffect(() => {
         if (loginChek?.status === "PENDING") {
         if (loginChek?.status === "PENDING") {
-            setLoading(loading => loading = true)
+            setLoading(true)
         }
         }
         if (loginChek?.status === "RESOLVED" && loginChek?.payload === null) {
         if (loginChek?.status === "RESOLVED" && loginChek?.payload === null) {
             message.error({
             message.error({
@@ -18,11 +19,10 @@ const FormAuthorization = ({ buttonTitle, onSignIn, loginChek }) => {
                     marginTop: '20vh',
                     marginTop: '20vh',
                 },
                 },
             })
             })
-            setLoading(loading => loading = false)
+            setLoading(false)
         }
         }
     }, [loginChek?.status]);
     }, [loginChek?.status]);
 
 
-
     const onFinish = ({ login, password, remember }) => {
     const onFinish = ({ login, password, remember }) => {
         onSignIn(login, password, remember)
         onSignIn(login, password, remember)
     };
     };
@@ -82,6 +82,6 @@ const FormAuthorization = ({ buttonTitle, onSignIn, loginChek }) => {
     )
     )
 }
 }
 
 
-export const CLoginForm = connect(state => ({ loginChek: state?.promise?.login || {} }), { onSignIn: actionFullLogIn, })(FormAuthorization)
+export const CLoginForm = connect(state => ({ loginChek: state?.promise?.login || {} }), { onSignIn: actionFullLogInSagaAC, })(FormAuthorization)
 
 
-export const CRegisterForm = connect(state => ({ status: state?.promise?.login }), { onSignIn: actionFullRegister, })(FormAuthorization)
+export const CRegisterForm = connect(state => ({ status: state?.promise?.login }), { onSignIn: actionFullRegisterSagaAC, })(FormAuthorization)

+ 55 - 0
src/components/GalleryMediaPostsUser.jsx

@@ -0,0 +1,55 @@
+import { connect } from "react-redux"
+import { Card, Col, Row } from 'antd'
+import postNoData from '../images/profile-post-no.jpeg'
+import { Link } from "react-router-dom"
+import { PlayCircleOutlined } from "@ant-design/icons"
+import { CircularGalleryIcon, videoRegExp } from "../helpers"
+import { backURL } from "../actions/actionsGetGql"
+
+
+const CardImage = ({ media }) =>
+    <div className='Profile__box' >
+        <img src={backURL + '/' + media?.images[0]?.url} alt="images post" />
+        {media?.images.length > 1 &&
+            < CircularGalleryIcon className='Profile__box-icon' style={{ stroke: 'black' }} />
+        }
+    </div>
+
+
+const CardVideo = ({ media }) =>
+    <div className='Profile__box' >
+        <video>
+            <source src={backURL + '/' + media?.images[0]?.url} />
+        </video>
+        <PlayCircleOutlined className='Profile__box-icon--video' />
+    </div>
+
+
+const ValidationImageOrVideo = ({ media }) => (
+    videoRegExp.test(media?.images[0]?.originalFileName)
+        ? <CardVideo media={media} />
+        : <CardImage media={media} />
+)
+
+
+const CardMediaPost = ({ media }) =>
+    <Link to={`/post/${media?._id}`}>
+        <Card className='Profile__post' hoverable>
+            {media?.images && media?.images[0] && media?.images[0]?.url
+                ? <ValidationImageOrVideo media={media} />
+                : <img src={postNoData} alt='no data' />
+            }
+        </Card>
+    </Link>
+
+
+const GalleryMediaPostsUser = ({ posts }) =>
+    <Row gutter={[15, 15]}>
+        {posts.map(p =>
+            <Col key={p._id} span={8}>
+                <CardMediaPost media={p} />
+            </Col>)
+        }
+    </Row >
+
+export const CGalleryMediaPostsUser = connect(state => ({ posts: state?.postsTape?.posts || [] }))(GalleryMediaPostsUser)

+ 75 - 0
src/components/ModalFollow.jsx

@@ -0,0 +1,75 @@
+import { Col, List, Row, Skeleton } from 'antd';
+import Modal from 'antd/lib/modal/Modal'
+import { useEffect } from 'react';
+import { connect } from 'react-redux';
+import { Link } from 'react-router-dom';
+import { actionGetFindFollowers, actionGetFindFollowing, actionGetPostUsersLiked } from '../actions/actionsGetGql';
+import { UserAvatar } from './UserAvatar';
+
+
+const ModalDataInner = ({ _id, avatar, nick, handleCancel }) =>
+    <Link to={`/profile/${_id}`} onClick={() => handleCancel()} style={{ width: '100%' }} >
+        <Row align='middle' >
+            <Col>
+                <UserAvatar avatar={avatar} avatarSize={'40px'} />
+            </Col>
+            <Col offset={2}>
+                {nick}
+            </Col>
+        </Row>
+    </Link >
+
+
+const ModalDataInfo = ({ id, status, statusModal, data, title, getData }) => {
+
+    const handleCancel = () => statusModal(false);
+    const newData = data.map(d => d.owner ? d.owner : d)
+
+    useEffect(() => {
+        getData(id)
+    }, [])
+
+
+    return (
+        <Modal className='Modal'
+            title={title}
+            visible={true}
+            destroyOnClose={true}
+            footer={null}
+            onCancel={handleCancel}>
+            {status !== 'RESOLVED'
+                ? <Skeleton className='Modal__inner' avatar active paragraph={{ rows: 0 }} />
+                : <List className='Modal__inner'
+                    itemLayout="horizontal"
+                    dataSource={newData}
+                    renderItem={item => (
+                        <List.Item >
+                            <ModalDataInner
+                                _id={item._id}
+                                avatar={item.avatar}
+                                nick={item.nick || item.login || 'No Name'}
+                                handleCancel={handleCancel} />
+                        </List.Item>
+                    )}
+                />}
+        </Modal>
+    )
+}
+
+export const CModalFollowers = connect(state => ({
+    id: state?.dataProfile?._id,
+    data: state?.promise?.findFollow?.payload?.followers || [],
+    status: state?.promise?.findFollow?.status
+}), { getData: actionGetFindFollowers })(ModalDataInfo)
+
+export const CModalFollowing = connect(state => ({
+    id: state?.dataProfile?._id,
+    data: state?.promise?.findFollow?.payload?.following || [],
+    status: state?.promise?.findFollow?.status
+}), { getData: actionGetFindFollowing })(ModalDataInfo)
+
+export const CModalUsersLiked = connect(state => ({
+    data: state?.promise?.usersPostLiked?.payload || [],
+    status: state?.promise?.usersPostLiked?.status
+}), { getData: actionGetPostUsersLiked })(ModalDataInfo)
+

+ 1 - 3
src/pages/Preloader.jsx

@@ -1,11 +1,9 @@
 import { message, Spin } from 'antd'
 import { message, Spin } from 'antd'
 import { connect } from 'react-redux'
 import { connect } from 'react-redux'
-import preloader from '../images/preloader.gif'
 
 
 const PreloaderImg = () =>
 const PreloaderImg = () =>
     <div className='PreloaderImg'>
     <div className='PreloaderImg'>
-{/* <Spin size="large" /> */}
-        <img src={preloader} alt="preloader" />
+        <Spin size="large" />
     </div>
     </div>
 
 
 const Preloader = ({ promiseName, promiseState }) =>
 const Preloader = ({ promiseName, promiseState }) =>

+ 7 - 6
src/components/header/UserAvatar.js

@@ -1,12 +1,13 @@
 import Avatar from "antd/lib/avatar/avatar"
 import Avatar from "antd/lib/avatar/avatar"
-import { backURL } from "../../helpers"
-import noAva from "../../images/noAva.png"
+import noAva from "../images/noAva.png"
+import { backURL } from "../actions/actionsGetGql"
 
 
 export const UserAvatar = ({ avatarSize, avatar }) =>
 export const UserAvatar = ({ avatarSize, avatar }) =>
-    <Avatar style={{
-        width: avatarSize,
-        height: avatarSize
-    }}
+    <Avatar
+        style={{
+            width: avatarSize,
+            height: avatarSize
+        }}
         src={avatar && avatar?.url
         src={avatar && avatar?.url
             ? <img src={(backURL + '/' + avatar.url)} alt='avatar' />
             ? <img src={(backURL + '/' + avatar.url)} alt='avatar' />
             : <img src={noAva} alt="avatar" />
             : <img src={noAva} alt="avatar" />

src/components/uploadPhoto/EditDescriptionPost.js → src/components/editPost/EditDescriptionPost.jsx


+ 24 - 8
src/components/uploadPhoto/EditPhotos.js

@@ -1,5 +1,5 @@
 import { DeleteOutlined, EyeOutlined, InboxOutlined } from "@ant-design/icons";
 import { DeleteOutlined, EyeOutlined, InboxOutlined } from "@ant-design/icons";
-import { Button, message, Image, Progress } from "antd";
+import { Button, message, Image, Progress, Upload } from "antd";
 import Dragger from "antd/lib/upload/Dragger";
 import Dragger from "antd/lib/upload/Dragger";
 import React, { useState } from "react";
 import React, { useState } from "react";
 import {
 import {
@@ -8,7 +8,8 @@ import {
     SortableElement,
     SortableElement,
     SortableHandle
     SortableHandle
 } from "react-sortable-hoc";
 } from "react-sortable-hoc";
-import { backURL, propsUploadFile, videoRegExp } from "../../helpers";
+import { backURL } from "../../actions/actionsGetGql";
+import { propsUploadFile, videoRegExp } from "../../helpers";
 
 
 
 
 const SortableItemMask = ({ removePhotosItem, chekMedia, setVisible, id }) =>
 const SortableItemMask = ({ removePhotosItem, chekMedia, setVisible, id }) =>
@@ -79,17 +80,30 @@ const SortableList = SortableContainer(({ items = [], ...restProps }) => {
 export function EditPhotos({ photos = [], setPhotos }) {
 export function EditPhotos({ photos = [], setPhotos }) {
     const [progress, setProgress] = useState(0);
     const [progress, setProgress] = useState(0);
     const [loading, setLoading] = useState(false);
     const [loading, setLoading] = useState(false);
-    const handlerChange = async ({ file, fileList }) => {
+    let count = []
+    const handlerChange = ({ file, fileList }) => {
         if (file.status === "uploading") {
         if (file.status === "uploading") {
             setLoading(true)
             setLoading(true)
             setProgress(file.percent)
             setProgress(file.percent)
         } else if (file.status === 'done') {
         } else if (file.status === 'done') {
+            console.log(file, fileList)
+            count = []
             message.success(`${file.name} file uploaded successfully`);
             message.success(`${file.name} file uploaded successfully`);
             setPhotos([...photos || [], file.response])
             setPhotos([...photos || [], file.response])
         } else if (file.status === 'error') {
         } else if (file.status === 'error') {
             message.error(`${file.name} file upload failed.`);
             message.error(`${file.name} file upload failed.`);
         }
         }
     }
     }
+
+    const beforeUpload = (file) => {
+        if (count.length + photos.length > 8) {
+            message.error('Error, upload Max 8 elements')
+            return false
+        } else {
+            count = [...count, file]
+        }
+    }
+
     const removePhotosItem = (id) => setPhotos(photos.filter(p => p._id !== id))
     const removePhotosItem = (id) => setPhotos(photos.filter(p => p._id !== id))
     const onSortEnd = ({ oldIndex, newIndex }) => {
     const onSortEnd = ({ oldIndex, newIndex }) => {
         setPhotos(arrayMove(photos, oldIndex, newIndex));
         setPhotos(arrayMove(photos, oldIndex, newIndex));
@@ -97,20 +111,22 @@ export function EditPhotos({ photos = [], setPhotos }) {
 
 
     return (
     return (
         <div className="EditPhotos" >
         <div className="EditPhotos" >
-            {photos?.length >= 8 ? null
-                : <Dragger {...propsUploadFile}
+            {photos.length < 8 &&
+                <Dragger {...propsUploadFile}
                     className="EditPhotos__box"
                     className="EditPhotos__box"
-                    multiple={true}
                     maxCount={8}
                     maxCount={8}
+                    beforeUpload={beforeUpload}
+                    multiple={true}
                     listType="picture-card"
                     listType="picture-card"
                     showUploadList={false}
                     showUploadList={false}
                     onChange={handlerChange}>
                     onChange={handlerChange}>
                     <p className="ant-upload-drag-icon">
                     <p className="ant-upload-drag-icon">
                         <InboxOutlined />
                         <InboxOutlined />
                     </p>
                     </p>
-                    <p className="ant-upload-text">
+                    <div className="ant-upload-text">
                         Click or drag file to this area to upload
                         Click or drag file to this area to upload
-                    </p>
+                        <p>{photos?.length} / 8</p>
+                    </div>
                 </Dragger>
                 </Dragger>
             }
             }
             {loading &&
             {loading &&

src/components/uploadPhoto/EditTitlePost.js → src/components/editPost/EditTitlePost.jsx


+ 13 - 13
src/components/header/Header.jsx

@@ -6,15 +6,15 @@ import { connect } from 'react-redux';
 import { Header } from 'antd/lib/layout/layout';
 import { Header } from 'antd/lib/layout/layout';
 import { Col, Row } from 'antd';
 import { Col, Row } from 'antd';
 import { CompassOutlined, HomeOutlined, MessageOutlined, PlusCircleOutlined } from '@ant-design/icons/lib/icons';
 import { CompassOutlined, HomeOutlined, MessageOutlined, PlusCircleOutlined } from '@ant-design/icons/lib/icons';
-import { UserAvatar } from './UserAvatar';
 import MediaQuery from "react-responsive";
 import MediaQuery from "react-responsive";
 import { CollectionEmptySvg } from '../../helpers';
 import { CollectionEmptySvg } from '../../helpers';
+import { UserAvatar } from '../UserAvatar';
 
 
 
 
 const UserNavIcon = ({ userData: { _id, avatar, login } }) =>
 const UserNavIcon = ({ userData: { _id, avatar, login } }) =>
     < Row justify="end" align="middle" className='Header__userNav' >
     < Row justify="end" align="middle" className='Header__userNav' >
         <Col >
         <Col >
-            <NavLink to='/feed'><HomeOutlined /></NavLink>
+            <NavLink to='/tape'><HomeOutlined /></NavLink>
         </Col>
         </Col>
         <Col >
         <Col >
             <NavLink to='/direct'><MessageOutlined /></NavLink>
             <NavLink to='/direct'><MessageOutlined /></NavLink>
@@ -28,27 +28,27 @@ const UserNavIcon = ({ userData: { _id, avatar, login } }) =>
         <Col >
         <Col >
             <NavLink to='/my-collection'><CollectionEmptySvg /></NavLink>
             <NavLink to='/my-collection'><CollectionEmptySvg /></NavLink>
         </Col>
         </Col>
-        <MediaQuery minWidth={787}>
-            <Col>
-                <Link to={`/profile/${_id}`}>
-                    <UserAvatar avatar={avatar} login={login} avatarSize={'45px'} />
-                </Link>
-            </Col>
-        </MediaQuery>
-        <MediaQuery maxWidth={786}>
+        {/* <MediaQuery minWidth={787}> */}
+        <Col>
+            <Link to={`/profile/${_id}`}>
+                <UserAvatar avatar={avatar} login={login} avatarSize={'45px'} />
+            </Link>
+        </Col>
+        {/* </MediaQuery> */}
+        {/* <MediaQuery maxWidth={786}>
             <Col>
             <Col>
                 <Link to={`/profile/${_id}`}>
                 <Link to={`/profile/${_id}`}>
                     <UserAvatar avatar={avatar} login={login} avatarSize={'45px'} />
                     <UserAvatar avatar={avatar} login={login} avatarSize={'45px'} />
                 </Link>
                 </Link>
             </Col>
             </Col>
-        </MediaQuery>
+        </MediaQuery> */}
     </Row >
     </Row >
 
 
-export const CUserNavIcon = connect(state => ({ userData: state.myData || {} }))(UserNavIcon)
+export const CUserNavIcon = connect(state => ({ userData: state?.aboutMe || {} }))(UserNavIcon)
 
 
 
 
 const Logo = () =>
 const Logo = () =>
-    <Link className='Logo' to='/'>
+    <Link className='Logo' to='/tape'>
         <img src={logo} alt='logo' width='180vw' />
         <img src={logo} alt='logo' width='180vw' />
     </Link>
     </Link>
 
 

+ 9 - 9
src/components/header/Search.jsx

@@ -2,9 +2,9 @@ import { Empty, Input, Popover } from 'antd'
 import React from 'react'
 import React from 'react'
 import { connect } from 'react-redux';
 import { connect } from 'react-redux';
 import { Link } from 'react-router-dom';
 import { Link } from 'react-router-dom';
-import {  actionSearchUsers } from '../../actions';
 import { SearchOutlined } from '@ant-design/icons';
 import { SearchOutlined } from '@ant-design/icons';
-import { UserAvatar } from './UserAvatar';
+import { UserAvatar } from '../UserAvatar';
+import { actionSearchAllUsers } from '../../actions/actonsCreators';
 
 
 
 
 const FindUsersResult = ({ usersRes }) =>
 const FindUsersResult = ({ usersRes }) =>
@@ -12,20 +12,20 @@ const FindUsersResult = ({ usersRes }) =>
         {
         {
             usersRes.length === 0 ?
             usersRes.length === 0 ?
                 <Empty /> :
                 <Empty /> :
-                usersRes.map(u => {
-                    return (<Link
+                usersRes.map(u =>
+                    <Link
                         className='Header__search-link'
                         className='Header__search-link'
                         key={u._id}
                         key={u._id}
                         to={`/profile/${u._id}`} >
                         to={`/profile/${u._id}`} >
                         <UserAvatar avatar={u.avatar} login={u.login} nick={u.nick} avatarSize={'40px'} />
                         <UserAvatar avatar={u.avatar} login={u.login} nick={u.nick} avatarSize={'40px'} />
                         <strong>{u?.nick || u?.login || 'User'}</strong>
                         <strong>{u?.nick || u?.login || 'User'}</strong>
-                    </Link>)
-                })
+                    </Link>
+                )
         }
         }
     </div >
     </div >
 
 
 
 
-export const FieldSearch = ({ usersRes, findUsers }) =>
+export const FieldSearch = ({ usersRes, onGetAllUsers }) =>
     <>
     <>
         <Popover placement="bottom"
         <Popover placement="bottom"
             content={<FindUsersResult usersRes={usersRes} />}
             content={<FindUsersResult usersRes={usersRes} />}
@@ -36,11 +36,11 @@ export const FieldSearch = ({ usersRes, findUsers }) =>
                 placeholder="Search users"
                 placeholder="Search users"
                 allowClear
                 allowClear
                 prefix={<SearchOutlined style={{ color: '#c9c9c9' }} />}
                 prefix={<SearchOutlined style={{ color: '#c9c9c9' }} />}
-                onChange={e => findUsers(e.currentTarget.value)}
+                onChange={e => onGetAllUsers(e.currentTarget.value)}
             />
             />
         </Popover>
         </Popover>
     </>
     </>
 
 
 
 
 
 
-export const CFieldSearch = connect(state => ({ usersRes: state.promise?.findUsersAll?.payload || [] }), { findUsers: actionSearchUsers })(FieldSearch) 
+export const CFieldSearch = connect(state => ({ usersRes: state.promise?.findUsersAll?.payload || [] }), { onGetAllUsers: actionSearchAllUsers })(FieldSearch) 

+ 0 - 11
src/components/main/DateCreated.js

@@ -1,11 +0,0 @@
-import React from 'react'
-
-export const DateCreated = ({ date = '' }) => {
-    const newDate = new Date(date * 1)
-    const resultDate = new Intl.DateTimeFormat('default').format(newDate)
-    return (
-        <>
-            {resultDate}
-        </>
-    )
-}

+ 0 - 36
src/components/main/Posts.jsx

@@ -1,36 +0,0 @@
-import { connect } from "react-redux"
-import { Card, Col, Row } from 'antd'
-import postNoData from '../../images/profile-post-no.jpeg'
-import { Link } from "react-router-dom"
-import { backURL, CircularGalleryIcon, videoRegExp } from "../../helpers"
-import { PlayCircleOutlined } from "@ant-design/icons"
-
-const Posts = ({ posts }) =>
-    <Row gutter={[15, 15]}>
-        {Array.isArray(posts) && posts.map(p => <Col key={p._id} span={8}>
-            <Link to={`/post/${p._id}`}>
-                <Card className='Profile__post' hoverable>
-                    {p?.images && p?.images[0] && p.images[0]?.url
-                        ? videoRegExp.test(p.images[0]?.originalFileName)
-                            ? <div className='Profile__box' >
-                                <video>
-                                    <source src={backURL + '/' + p.images[0]?.url} />
-                                </video>
-                                <PlayCircleOutlined className='Profile__box-icon--video' />
-                            </div>
-                            : p.images.length === 1
-                                ?
-                                <img src={backURL + '/' + p.images[0]?.url} alt="images post" />
-                                : <div className='Profile__box' >
-                                    <CircularGalleryIcon className='Profile__box-icon' style={{ stroke: 'black' }} />
-                                    <img src={(backURL + '/' + p?.images[0]?.url)} alt='post Img' />
-                                </div>
-                        : <img src={postNoData} alt='no data' />
-                    }
-                </Card>
-            </Link>
-        </Col>)
-        }
-    </Row >
-    
-export const CPosts = connect(state => ({ posts: state.post?.posts || [] }))(Posts)

+ 0 - 73
src/components/main/postsFeed/PostImage.jsx

@@ -1,73 +0,0 @@
-import { LeftCircleOutlined, RightCircleOutlined } from "@ant-design/icons";
-import { Carousel, Empty } from "antd";
-import React, { createRef } from "react";
-import nodata from '../../../images/nodata.png'
-import { backURL, videoRegExp } from '../../../helpers/index'
-import MediaQuery from "react-responsive";
-
-class PostImage extends React.Component {
-    constructor(props) {
-        super(props);
-        this.carouselRef = createRef();
-        this.state = {
-            movePrev: false,
-            moveNext: false
-        }
-    }
-
-    handleNext = () => this.carouselRef.current.next(this);
-
-    handlePrev = () => this.carouselRef.current.prev(this);
-
-    moveOnDivArray = (length, index) => {
-        if (length === 1) {
-            this.setState({ movePrev: false, moveNext: false })
-        } else if (index === 0) {
-            this.setState({ movePrev: false, moveNext: true })
-        } else if (index === length - 1 && length > 1) {
-            this.setState({ movePrev: true, moveNext: false })
-        } else {
-            this.setState({ movePrev: true, moveNext: true })
-        }
-    }
-
-    downOnDivArray = () => this.setState({ movePrev: false, moveNext: false })
-
-    render() {
-
-        const { images } = this.props
-        return (
-            <Carousel ref={this.carouselRef}
-                effect="fade"
-                infinite={false}
-                dots={{ className: 'Post__dots' }
-                }>
-                {!!images ? images.map((i, index) => i?.url ? <div
-                    key={i._id}
-                    onMouseEnter={() => this.moveOnDivArray(images.length, index)}
-                    onMouseLeave={this.downOnDivArray}>
-                    <MediaQuery minWidth={768}>
-                        <button onClick={() => this.handlePrev()}
-                            className={`Post__prev Post__btn ${this.state.movePrev ? '--active' : ''}`}><LeftCircleOutlined /></button>
-                        <button onClick={() => this.handleNext()}
-                            className={`Post__next Post__btn ${this.state.moveNext ? '--active' : ''}`}><RightCircleOutlined /></button>
-                    </MediaQuery>
-                    <div className="PostOne__wrapper-img">
-                        {videoRegExp.test(i.originalFileName)
-                            ? <video controls loop preload="true" height="500">
-                                <source src={backURL + '/' + i.url} />
-                            </video>
-                            : <img src={backURL + '/' + i.url} />
-                        }
-                    </div>
-
-                </div>
-                    : <Empty key={i._id} image={nodata} description={false} />)
-                    : <Empty image={nodata} description={false} />
-                }
-            </Carousel >
-        );
-    }
-}
-
-export default PostImage

+ 0 - 67
src/components/main/postsFeed/PostUserPanel.jsx

@@ -1,67 +0,0 @@
-import { HeartFilled, HeartOutlined } from "@ant-design/icons"
-import { Button, Col, Row} from "antd"
-import { useState } from "react"
-import { connect } from "react-redux"
-import { actionDelLikePost, actionHandlerUpsertCollection, actionLikePost, } from "../../../actions"
-import { CollectionEmptySvg, CollectionSvgFill } from "../../../helpers"
-import { CModalPostLiked } from "../profilePage/ModalFollow"
-
-
-const HeartLike = ({ styleFontSize, likeStatus, changeLike }) =>
-    <Button
-        onClick={() => changeLike()}
-        type="none"
-        shape="circle"
-        icon={
-            likeStatus
-                ? <HeartFilled style={{ color: '#ff6969', fontSize: `${styleFontSize}` }} />
-                : <HeartOutlined style={{ color: '#1890ff', fontSize: `${styleFontSize}` }} />
-        }
-    />
-
-const PostUserPanel = ({ myID, postId = '', likes = [], collections, styleFontSize, addLikePost, removeLikePost, handlerCollection }) => {
-    const [open, setOpen] = useState(false)
-
-    const likeId = likes.find(l => l?.owner?._id === myID)?._id
-
-    const flag = collections?.posts.find(c => c._id === postId)
-
-    const changeLike = () => likeId ? removeLikePost(likeId, postId) : addLikePost(postId)
-
-    return (
-        <>
-            {open && <CModalPostLiked statusModal={setOpen} title={'Liked'} id={postId} />}
-            <Row className="Post__panel-btn" justify="space-between" align="middle">
-                <Col flex={'50%'}>
-                    <Row align="middle" wrap={false}>
-                        <Col className='Post__heart' >
-                            <HeartLike
-                                changeLike={changeLike}
-                                likeStatus={likeId}
-                                styleFontSize={styleFontSize} />
-                        </Col>
-                        <Col offset={1}>
-                            {!!likes.length && <button onClick={() => { setOpen(true) }}>Likes:<strong>{` ${likes.length}`}</strong></button>}
-                        </Col>
-                    </Row>
-                </Col>
-                <Col flex={'10%'} className='Post__collection'>
-                    <Button type="none"
-                        shape="circle" onClick={() => handlerCollection(postId, flag)}>
-                        {flag ? <CollectionSvgFill /> : <CollectionEmptySvg />}
-                    </Button>
-                </Col>
-            </Row>
-
-        </>
-    )
-}
-
-export const CPostUserPanel = connect(state => ({
-    myID: state.auth.payload.sub.id || '',
-    collections: state.myData?.collections
-}), {
-    addLikePost: actionLikePost,
-    removeLikePost: actionDelLikePost,
-    handlerCollection: actionHandlerUpsertCollection,
-})(PostUserPanel)

+ 0 - 62
src/components/main/profilePage/ModalFollow.js

@@ -1,62 +0,0 @@
-import { Col, List, Row, Skeleton } from 'antd';
-import Modal from 'antd/lib/modal/Modal'
-import { useEffect } from 'react';
-import { connect } from 'react-redux';
-import { Link } from 'react-router-dom';
-import { actionFindFollowers, actionFindFollowing, actionFindLiked } from '../../../actions';
-import { UserAvatar } from '../../header/UserAvatar';
-
-
-const ModalFolower = ({ id, status, statusModal, data, title, follow }) => {
-    const handleCancel = () => statusModal(false);
-
-    useEffect(() => {
-        follow(id)
-    }, [])
-    const newData = data.map(d => d.owner ? d.owner : d)
-    return (
-        <Modal className='Modal'
-            title={title}
-            visible={true}
-            destroyOnClose={true}
-            footer={null}
-            onCancel={handleCancel}>
-            {status !== 'RESOLVED'
-                ? <Skeleton className='Modal__inner' avatar active paragraph={{ rows: 0 }} />
-                : <List className='Modal__inner'
-                    itemLayout="horizontal"
-                    dataSource={newData}
-                    renderItem={item => (
-                        <List.Item >
-                            <Link to={`/profile/${item._id}`} style={{ width: '100%' }} onClick={handleCancel}>
-                                <Row align='middle' >
-                                    <Col>
-                                        <UserAvatar avatar={item.avatar} avatarSize={'40px'} />
-                                    </Col>
-                                    <Col offset={2}>{item.nick || item.login || 'No Name'}</Col>
-                                </Row>
-                            </Link>
-                        </List.Item>
-                    )}
-                />}
-        </Modal>
-    )
-}
-
-export const CModalFollowers = connect(state => ({
-    id: state?.post?.userData?._id,
-    data: state?.promise?.findFollow?.payload?.followers || [],
-    status: state?.promise?.findFollow?.status
-}), { follow: actionFindFollowers })(ModalFolower)
-
-export const CModalFollowing = connect(state => ({
-    id: state?.post?.userData?._id,
-    data: state?.promise?.findFollow?.payload?.following || [],
-    status: state?.promise?.findFollow?.status
-}), { follow: actionFindFollowing })(ModalFolower)
-
-export const CModalPostLiked = connect(state => ({
-    data: state?.promise?.findLiked?.payload || [],
-    status: state?.promise?.findLiked?.status
-}), { follow: actionFindLiked })(ModalFolower)
-

+ 59 - 0
src/components/post/CommentsPostInTape.jsx

@@ -0,0 +1,59 @@
+import { Divider, Tooltip } from "antd"
+import Paragraph from "antd/lib/typography/Paragraph"
+import { Link } from "react-router-dom"
+import moment from 'moment'
+import { CCommentFieldPostTape } from "../CommentField"
+
+
+export const PostCommentDate = ({ createdAt }) =>
+    <Tooltip
+        title={moment(new Date(+createdAt)).format('DD-MM-YYYY HH:mm:ss')}
+    >
+        {moment(new Date(+createdAt)).startOf('seconds').fromNow()}
+    </ Tooltip>
+
+
+const CommentPostInTape = ({ comment }) =>
+    <div className='CommentPostFeed'>
+        <Link to={`/profile/${comment.owner._id}`}>
+            {comment?.owner?.nick || comment?.owner?.login}
+        </Link>
+        <PostCommentDate createdAt={comment.createdAt} />
+        <Paragraph
+            style={{ paddingLeft: 20 }}
+            ellipsis={{ rows: 1, expandable: true, symbol: 'more' }}>
+            {comment?.text}
+        </Paragraph>
+    </div>
+
+
+const CommentsInnerPostInTape = ({ comments, _id }) =>
+    <>
+        {(comments.length > 2) && <Link to={`/post/${_id}`}>
+            <Divider orientation="left">
+                {`View ${comments.length} comments`}
+            </Divider>
+        </Link>}
+        {comments.slice(-2).map(c => <CommentPostInTape key={c._id} comment={c} />)}
+    </>
+
+
+const CommentsContentPostInTape = ({ comments, _id }) =>
+    <>
+        {
+            comments && comments.length
+                ? <CommentsInnerPostInTape comments={comments} _id={_id} />
+                : <Link to={`/post/${_id}`}>
+                    <Divider orientation="left">
+                        {comments?.length ? `View ${comments.length} comments` : 'No comments'}
+                    </Divider>
+                </Link>
+        }
+    </>
+
+
+export const CommentsPostInTape = ({ comments, _id }) =>
+    <>
+        <CommentsContentPostInTape comments={comments} _id={_id} />
+        <CCommentFieldPostTape id={_id} setOpen={() => { }} />
+    </>

+ 44 - 0
src/components/post/PostDescription.jsx

@@ -0,0 +1,44 @@
+import { Col, Row } from "antd"
+import Paragraph from "antd/lib/typography/Paragraph"
+import Text from "antd/lib/typography/Text"
+import { connect } from "react-redux"
+
+
+export const DateCreated = ({ date = '' }) => {
+
+    const newDate = new Date(date * 1)
+    const resultDate = new Intl.DateTimeFormat('default').format(newDate)
+
+    return (
+        <>
+            {resultDate}
+        </>
+    )
+}
+
+const PostTitle = ({ title, date }) =>
+    <Row justify='space-between'>
+        <Col >
+            {!!title && <Text level={3} strong>{title}</Text>}
+        </Col>
+        <Col >
+            <Text type='secondary'>
+                <DateCreated date={date} />
+            </Text>
+        </Col>
+    </Row>
+
+export const PostDescription = ({ title, description, date }) =>
+    <>
+        <PostTitle title={title} date={date} />
+        <Paragraph ellipsis={true ? { rows: 1, expandable: true, symbol: '...More' } : false}>
+            {description}
+        </Paragraph>
+    </>
+
+
+export const CPostDescription = connect(state => ({
+    title: state?.postOne?.title,
+    description: state?.postOne?.text,
+    date: state?.postOne?.createdAt
+}))(PostDescription) 

+ 20 - 9
src/components/main/post/PostTitle.js

@@ -2,7 +2,8 @@ import { Col, Row, Button, Dropdown, Menu } from 'antd'
 import { MoreOutlined } from '@ant-design/icons'
 import { MoreOutlined } from '@ant-design/icons'
 import { Link } from 'react-router-dom'
 import { Link } from 'react-router-dom'
 import { connect } from 'react-redux'
 import { connect } from 'react-redux'
-import { UserAvatar } from '../../header/UserAvatar'
+import { UserAvatar } from '../UserAvatar'
+
 
 
 const MenuOverlay = ({ postId }) =>
 const MenuOverlay = ({ postId }) =>
     <Menu>
     <Menu>
@@ -11,7 +12,22 @@ const MenuOverlay = ({ postId }) =>
         </Menu.Item>
         </Menu.Item>
     </Menu >
     </Menu >
 
 
-export const PostTitle = ({ owner, myID, postId }) =>
+
+const EditMyPostBtn = ({ myID, postId, owner }) =>
+    <>
+        {owner?._id === myID &&
+            <Col>
+                <Dropdown overlay={<MenuOverlay postId={postId} />} placement="bottomRight" trigger={['click']}>
+                    <Button type='link'>
+                        <MoreOutlined style={{ fontSize: '1.4em' }} />
+                    </Button>
+                </Dropdown>
+            </Col>
+        }
+    </>
+export const CEditMyPostBtn = connect(state => ({ myID: state?.aboutMe?._id }))(EditMyPostBtn)
+
+export const PostHeader = ({ owner, children }) =>
     <Row justify="space-between" align='middle'>
     <Row justify="space-between" align='middle'>
         <Col>
         <Col>
             <Link to={`/profile/${owner?._id}`} className='owner'>
             <Link to={`/profile/${owner?._id}`} className='owner'>
@@ -19,14 +35,9 @@ export const PostTitle = ({ owner, myID, postId }) =>
                 <span className='nick'>{owner?.nick ? owner.nick : owner?.login ? owner.login : 'Null'}</span>
                 <span className='nick'>{owner?.nick ? owner.nick : owner?.login ? owner.login : 'Null'}</span>
             </Link >
             </Link >
         </Col>
         </Col>
-        {owner?._id === myID && <Col>
-            <Dropdown overlay={<MenuOverlay postId={postId} />} placement="bottomRight" trigger={['click']}>
-                <Button type='link'><MoreOutlined style={{ fontSize: '1.4em' }} /></Button>
-            </Dropdown>
-
-        </Col>}
+        {children}
     </Row>
     </Row>
 
 
 
 
 
 
-export const CPostTitle = connect(state => ({ myID: state?.auth?.payload?.sub?.id || '' }))(PostTitle)
+

+ 107 - 0
src/components/post/PostImageCover.jsx

@@ -0,0 +1,107 @@
+import { LeftCircleOutlined, RightCircleOutlined } from "@ant-design/icons";
+import { Carousel, Empty } from "antd";
+import React, { createRef } from "react";
+import nodata from '../../images/nodata.png'
+import MediaQuery from "react-responsive";
+import { backURL } from "../../actions/actionsGetGql";
+import { videoRegExp } from "../../helpers";
+
+
+const PostImageOrVideo = ({ url, originalFileName }) =>
+    <div className="PostOne__wrapper-img">
+        {
+            videoRegExp.test(originalFileName)
+                ? <video controls loop preload="true">
+                    <source src={backURL + '/' + url} />
+                </video>
+                : <img src={backURL + '/' + url} alt="post image" />
+        }
+    </div>
+
+
+const PostImageCaruselBtn = ({ styleClass, handlerClick, flagClass, children }) => 
+        <MediaQuery minWidth={768}>
+            <button onClick={() => handlerClick()}
+                className={`${styleClass} Post__btn ${flagClass ? '--active' : ''}`}>
+                {children}
+            </button>
+        </MediaQuery>
+
+
+class PostImage extends React.Component {
+    render() {
+        const { url, originalFileName, handlePrev, handleNext, movePrev, moveNext } = this.props
+        return (
+            <>
+                {url ? <>
+                    <PostImageCaruselBtn styleClass={'Post__prev'} handlerClick={handlePrev} flagClass={movePrev} >
+                        <LeftCircleOutlined />
+                    </PostImageCaruselBtn>
+                    <PostImageCaruselBtn styleClass={'Post__next'} handlerClick={handleNext} flagClass={moveNext} >
+                        <RightCircleOutlined />
+                    </PostImageCaruselBtn>
+                    <PostImageOrVideo url={url} originalFileName={originalFileName} />
+                </>
+                    : <Empty image={nodata} description={false} />}
+            </>)
+    }
+}
+
+class PostImageCover extends React.Component {
+    constructor(props) {
+        super(props);
+        this.carouselRef = createRef();
+        this.state = {
+            movePrev: false,
+            moveNext: false
+        }
+    }
+
+    handleNext = () => this.carouselRef.current.next(this);
+
+    handlePrev = () => this.carouselRef.current.prev(this);
+
+    moveOnDivArray = (length, index) => {
+        if (length === 1) {
+            this.setState({ movePrev: false, moveNext: false })
+        } else if (index === 0) {
+            this.setState({ movePrev: false, moveNext: true })
+        } else if (index === length - 1 && length > 1) {
+            this.setState({ movePrev: true, moveNext: false })
+        } else {
+            this.setState({ movePrev: true, moveNext: true })
+        }
+    }
+
+    downOnDivArray = () => this.setState({ movePrev: false, moveNext: false })
+
+    render() {
+
+        const { images } = this.props
+        return (
+            <Carousel ref={this.carouselRef}
+                effect="fade"
+                infinite={false}
+                dots={{ className: 'Post__dots' }
+                }>
+                {images
+                    ? images.map((i, index) => <div
+                        key={i._id}
+                        onMouseEnter={() => this.moveOnDivArray(images.length, index)}
+                        onMouseLeave={this.downOnDivArray}>
+                        <PostImage
+                            url={i.url}
+                            handleNext={this.handleNext}
+                            handlePrev={this.handlePrev}
+                            originalFileName={i.originalFileName}
+                            moveNext={this.state.moveNext}
+                            movePrev={this.state.movePrev} />
+                    </div>)
+                    : <Empty image={nodata} description={false} />
+                }
+            </Carousel >
+        );
+    }
+}
+
+export default PostImageCover

+ 38 - 43
src/components/main/post/PostComment.js

@@ -7,9 +7,11 @@ import moment from 'moment';
 import { Link } from 'react-router-dom';
 import { Link } from 'react-router-dom';
 import { EditOutlined, LikeFilled, LikeOutlined, MoreOutlined } from '@ant-design/icons';
 import { EditOutlined, LikeFilled, LikeOutlined, MoreOutlined } from '@ant-design/icons';
 import Paragraph from 'antd/lib/typography/Paragraph';
 import Paragraph from 'antd/lib/typography/Paragraph';
-import { UserAvatar } from '../../header/UserAvatar';
-import { CFieldSubCommentSend, CFieldUpsertCommentSend } from '../postsFeed/FieldComment';
-import { actionDelLikeComment, actionLikeComment, actionSubComment } from '../../../actions';
+import { UserAvatar } from '../UserAvatar';
+import { PostCommentDate } from './CommentsPostInTape';
+import { CFieldEditCommentSend, CFieldSubComment, CFieldUpsertCommentSend } from '../CommentField';
+import { actionChangeLikeCommentSagaAC, actionGetSubCommentSagaAC } from '../../actions/actonsCreators';
+
 
 
 
 
 
 
@@ -31,46 +33,46 @@ const PostCommentText = ({ myID, commentId, owner, text }) => {
     const [editComment, setEditComment] = useState(false)
     const [editComment, setEditComment] = useState(false)
     return (
     return (
         <>
         <>
-            {owner?._id === myID && <Dropdown overlay={<EditMenu setEditComment={setEditComment} />} placement="bottomRight">
-                <span className='PostOne__comment-edit'
-                >
-                    <MoreOutlined />
-                </span >
-            </Dropdown>}
+            {owner?._id === myID &&
+                <Dropdown
+                    overlay={<EditMenu setEditComment={setEditComment} />}
+                    placement="bottomRight">
+                    <span className='PostOne__comment-edit'>
+                        <MoreOutlined />
+                    </span>
+                </Dropdown>
+            }
             {!editComment
             {!editComment
-                ? <Dropdown overlay={owner?._id === myID && <EditMenu setEditComment={setEditComment} />} trigger={['contextMenu']}>
+                ? <Dropdown
+                    overlay={owner?._id === myID && <EditMenu setEditComment={setEditComment} />}
+                    trigger={['contextMenu']}>
                     <Paragraph ellipsis={{ rows: 2, expandable: true, symbol: 'more' }} >
                     <Paragraph ellipsis={{ rows: 2, expandable: true, symbol: 'more' }} >
                         {text}
                         {text}
                     </ Paragraph>
                     </ Paragraph>
                 </Dropdown>
                 </Dropdown>
-                : <CFieldUpsertCommentSend value={text} id={commentId} autoFocus={true} setOpen={setEditComment} rows={4} bordered={true} />}
+                : <CFieldEditCommentSend value={text} id={commentId} autoFocus={true} setOpen={setEditComment} rows={2} bordered={true} />}
         </>)
         </>)
 }
 }
 
 
 const CPostCommentText = connect(state => ({ myID: state.auth.payload.sub.id || '' }))(PostCommentText)
 const CPostCommentText = connect(state => ({ myID: state.auth.payload.sub.id || '' }))(PostCommentText)
 
 
 
 
-export const PostCommentDate = ({ createdAt }) =>
-    <Tooltip title={moment(new Date(+createdAt)).format('DD-MM-YYYY HH:mm:ss')} >
-        {moment(new Date(+createdAt)).startOf().fromNow()}
-    </ Tooltip>
-
-
-const PostCommentAction = ({ myID, commentId, likes, delLikeComment, addLikeComment }) => {
+const PostCommentAction = ({ myID, commentId, likes, changeLikeComment }) => {
     const [open, setOpen] = useState(false);
     const [open, setOpen] = useState(false);
-    debugger
     const likeId = likes.find(l => l?.owner?._id === myID)?._id
     const likeId = likes.find(l => l?.owner?._id === myID)?._id
-    console.log(likeId)
-    const changeLike = () => likeId ? delLikeComment(likeId, commentId) : addLikeComment(commentId)
-
     return (
     return (
         <>
         <>
-            <span onClick={changeLike}>
+            <span onClick={() => changeLikeComment(commentId, likeId)}>
                 {likeId ? <LikeFilled /> : <LikeOutlined />}
                 {likeId ? <LikeFilled /> : <LikeOutlined />}
-                <span style={{ paddingLeft: 8, cursor: 'auto' }}>{likes.length ? likes.length : ''}</span>
+                {
+                    !!likes.length &&
+                    <span style={{ paddingLeft: 8, cursor: 'auto' }}>
+                        {likes.length}
+                    </span>
+                }
             </span>
             </span>
             <span onClick={() => setOpen(!open)}>Reply to</span>
             <span onClick={() => setOpen(!open)}>Reply to</span>
-            {open && <CFieldSubCommentSend autoFocus={true} id={commentId} setOpen={setOpen} />}
+            {open && <CFieldSubComment autoFocus={true} id={commentId} setOpen={setOpen} />}
         </>
         </>
     )
     )
 }
 }
@@ -78,44 +80,37 @@ const PostCommentAction = ({ myID, commentId, likes, delLikeComment, addLikeComm
 const CPostCommentAction = connect(state => ({
 const CPostCommentAction = connect(state => ({
     myID: state.auth.payload.sub.id || ''
     myID: state.auth.payload.sub.id || ''
 }), {
 }), {
-    addLikeComment: actionLikeComment,
-    delLikeComment: actionDelLikeComment
+    changeLikeComment: actionChangeLikeCommentSagaAC
 })(PostCommentAction)
 })(PostCommentAction)
 
 
-const PostComments = ({ comments, findSubComment, parentId, }) => {
-    return (<>
+const PostOneComments = ({ comments, findSubComment, parentId, }) =>
+    <>
         {comments?.length && Object.keys(comments[0]).length > 1
         {comments?.length && Object.keys(comments[0]).length > 1
             ? comments.map(c => {
             ? comments.map(c => {
                 return (
                 return (
                     <Comment
                     <Comment
                         key={c._id}
                         key={c._id}
                         author={<PostCommentAuthor owner={c.owner} />}
                         author={<PostCommentAuthor owner={c.owner} />}
-                        avatar={< UserAvatar avatar={c?.owner?.avatar} avatarSize={'35px'} />}
+                        avatar={<UserAvatar avatar={c?.owner?.avatar} avatarSize={'35px'} />}
                         datetime={<PostCommentDate createdAt={c.createdAt} />}
                         datetime={<PostCommentDate createdAt={c.createdAt} />}
                         content={<CPostCommentText text={c.text} commentId={c._id} owner={c.owner} />}
                         content={<CPostCommentText text={c.text} commentId={c._id} owner={c.owner} />}
                         actions={[<CPostCommentAction likes={c.likes} commentId={c._id} />]}
                         actions={[<CPostCommentAction likes={c.likes} commentId={c._id} />]}
                     >
                     >
-                        {
-                            c.answers && c.answers?.length
-                                ? <>
-                                    <PostComments comments={c?.answers} parentId={c._id} findSubComment={findSubComment} />
-                                </>
-                                : null
-                        }
+                        <PostOneComments comments={c?.answers} parentId={c._id} findSubComment={findSubComment} />
                     </Comment>
                     </Comment>
                 )
                 )
             })
             })
             :
             :
-            !!comments.length && <Divider plain>
+            !!comments?.length && <Divider plain>
                 <Text type='secodary' onClick={() => findSubComment(parentId)} >
                 <Text type='secodary' onClick={() => findSubComment(parentId)} >
                     View answers {comments.length}
                     View answers {comments.length}
                 </Text>
                 </Text>
             </Divider>
             </Divider>
         }
         }
-    </>)
-}
+    </>
+
 
 
-export const CPostComments = connect(state => ({
-    comments: state?.post?.posts?.comments || [],
+export const CPostOneComments = connect(state => ({
+    comments: state?.postOne?.comments || [],
 
 
-}), { findSubComment: actionSubComment })(PostComments)
+}), { findSubComment: actionGetSubCommentSagaAC })(PostOneComments)

+ 97 - 0
src/components/post/PostUserPanel.jsx

@@ -0,0 +1,97 @@
+import { HeartFilled, HeartOutlined } from "@ant-design/icons"
+import { Button, Col, Row } from "antd"
+import { useState } from "react"
+import { connect } from "react-redux"
+import { actionChangeLikePostOneSagaAC, actionChangeLikePostTapeSagaAC, actionDelLikePostSagaAC, actionHandlerUpsertCollectionSagaAC, actionOnLikePostSagaAC } from "../../actions/actonsCreators"
+import { CollectionEmptySvg, CollectionSvgFill } from "../../helpers"
+import { CModalUsersLiked } from "../ModalFollow"
+
+
+const HeartIcon = ({ myID, postId, styleFontSize, likes, changeLikePost }) => {
+    const likeId = likes.find(l => l?.owner?._id === myID)?._id
+    return (
+        <Button
+            onClick={() => changeLikePost(postId, likeId)}
+            type="none"
+            shape="circle"
+            icon={
+                likeId
+                    ? <HeartFilled style={{ color: '#ff6969', fontSize: `${styleFontSize}` }} />
+                    : <HeartOutlined style={{ color: '#1890ff', fontSize: `${styleFontSize}` }} />
+            }
+        />
+    )
+}
+
+const CHeartIcon = connect(state => ({ myID: state?.aboutMe?._id || '' }))(HeartIcon)
+
+
+
+const PostLike = ({ postId, likes = [], styleFontSize, changeLikePost }) => {
+
+    const [open, setOpen] = useState(false)
+
+    return (
+        <>
+            <Row align="middle" wrap={false}>
+                <Col className='Post__heart' >
+                    <CHeartIcon
+                        postId={postId}
+                        likes={likes}
+                        styleFontSize={styleFontSize}
+                        changeLikePost={changeLikePost}
+                    />
+                </Col>
+                <Col offset={1}>
+                    {!!likes.length &&
+                        <button onClick={() => { setOpen(true) }}>
+                            Likes:<strong>{` ${likes.length}`}</strong>
+                        </button>}
+                </Col>
+            </Row>
+            {open && <CModalUsersLiked id={postId} title={'Liked'} statusModal={setOpen} />}
+        </>)
+}
+
+
+const CollectionButton = ({ postId, collection, handlerCollection }) => {
+    const flag = collection?.find(c => c._id === postId)
+    return (
+        <Button
+            type="none"
+            shape="circle"
+            onClick={() => handlerCollection(postId, flag)}>
+            {flag ? <CollectionSvgFill /> : <CollectionEmptySvg />}
+        </ Button >
+    )
+}
+
+const CCollectionButton = connect(state => ({ collection: state?.aboutMe?.collection?.posts }))(CollectionButton)
+
+
+const PostUserPanel = ({ postId, likes, styleFontSize, changeLikePost, handlerCollection }) =>
+    <Row className="Post__panel-btn" justify="space-between" align="middle">
+        <Col flex={'50%'}>
+            <PostLike
+                postId={postId}
+                likes={likes}
+                styleFontSize={styleFontSize}
+                changeLikePost={changeLikePost}
+            />
+        </Col>
+        <Col flex={'10%'} className='Post__collection'>
+            <CCollectionButton
+                postId={postId}
+                handlerCollection={handlerCollection} />
+        </Col>
+    </Row>
+
+export const CPostTapeUserPanel = connect(null, {
+    handlerCollection: actionHandlerUpsertCollectionSagaAC,
+    changeLikePost: actionChangeLikePostTapeSagaAC,
+})(PostUserPanel)
+
+export const CPostOneUserPanel = connect(null, {
+    handlerCollection: actionHandlerUpsertCollectionSagaAC,
+    changeLikePost: actionChangeLikePostOneSagaAC,
+})(PostUserPanel)

+ 1 - 51
src/helpers/index.js

@@ -1,15 +1,8 @@
 import Icon from '@ant-design/icons';
 import Icon from '@ant-design/icons';
-import { useEffect } from 'react';
-import { connect } from 'react-redux';
-import { Route } from 'react-router-dom';
-
-
-export const backURL = 'http://hipstagram.asmer.fs.a-level.com.ua'
-
+import { backURL } from '../actions/actionsGetGql';
 
 
 export const videoRegExp = (/\.(mp4|mov|avi|wmv|flv|flv|3gp|mpg)$/i)
 export const videoRegExp = (/\.(mp4|mov|avi|wmv|flv|flv|3gp|mpg)$/i)
 
 
-
 export const propsUploadFile = {
 export const propsUploadFile = {
     name: 'photo',
     name: 'photo',
     action: `${backURL}/upload`,
     action: `${backURL}/upload`,
@@ -17,39 +10,6 @@ export const propsUploadFile = {
 }
 }
 
 
 
 
-export const jwtDecode = (token) => {
-    try {
-        let arrToken = token.split('.')
-        let base64Token = atob(arrToken[1])
-        return JSON.parse(base64Token)
-    }
-    catch (e) {
-        console.log('Ой, ошибочка вышла ' + e);
-    }
-}
-
-const getGQL = url =>
-    async (query, variables = {}) => {
-        let obj = await fetch(url, {
-            method: 'POST',
-            headers: {
-                "Content-Type": "application/json",
-                ...(localStorage.authToken
-                    ? { Authorization: 'Bearer ' + localStorage.authToken }
-                    : sessionStorage.authToken
-                        ? { Authorization: 'Bearer ' + sessionStorage.authToken }
-                        : {})
-            },
-            body: JSON.stringify({ query, variables })
-        })
-        let a = await obj.json()
-        if (!a.data && a.errors)
-            throw new Error(JSON.stringify(a.errors))
-        return a.data[Object.keys(a.data)[0]]
-    }
-
-export const gql = getGQL(backURL + '/graphql');
-
 
 
 const CircularGallerySvg = () =>
 const CircularGallerySvg = () =>
     <svg aria-label="Кольцевая галерея" color="#ffffff" fill="#ffffff" height="22" role="img" viewBox="0 0 48 48" width="22">
     <svg aria-label="Кольцевая галерея" color="#ffffff" fill="#ffffff" height="22" role="img" viewBox="0 0 48 48" width="22">
@@ -74,15 +34,5 @@ export const CollectionSvgFill = props =>
     <Icon component={CollectionFillSvg} {...props} />
     <Icon component={CollectionFillSvg} {...props} />
 
 
 
 
-const RRoute = ({ action, component: Component, ...routeProps }) => {
-    const WrapperComponent = (componentProps) => {
-        useEffect(() => {
-            action(componentProps.match)
-        })
-        return <Component {...componentProps} />
-    }
-    return <Route {...routeProps} component={WrapperComponent} />
-}
 
 
-export const CRRoute = connect(null, { action: match => ({ type: 'ROUTE', match }) })(RRoute)
 
 

+ 20 - 0
src/hoc/RRoute.js

@@ -0,0 +1,20 @@
+import { useEffect } from "react"
+import { connect } from "react-redux"
+import { Route } from "react-router-dom"
+
+
+
+const RRoute = ({ action, component: Component, ...routeProps }) => {
+    const WrapperComponent = (componentProps) => {
+        useEffect(() => {
+            action(componentProps.match)
+        })
+        return <Component {...componentProps} />
+    }
+    return <Route {...routeProps} component={WrapperComponent} />
+}
+
+export const CRRoute = connect(null, { action: match => ({ type: 'ROUTE', match }) })(RRoute)
+
+
+

BIN
src/images/preloader.gif


+ 10 - 9
src/pages/AllPosts.jsx

@@ -1,16 +1,17 @@
 import React, { useEffect, useState } from 'react';
 import React, { useEffect, useState } from 'react';
 import { connect } from 'react-redux';
 import { connect } from 'react-redux';
-import { actionAllPosts, actionRemovePostAC } from '../actions';
-import { CPosts } from '../components/main/Posts';
-import { Container } from './Content';
-import { CPreloader } from './Preloader';
+import { actionAllGetPostsSagaAC, actionClearPostsTapeAC, actionGetAllPostsSagaAC } from '../actions/actonsCreators';
+import { Container } from '../components/Container';
+import { CGalleryMediaPostsUser } from '../components/GalleryMediaPostsUser';
+import { CPreloader } from '../components/Preloader';
 
 
-const AllPosts = ({ onAllPosts, postsRemove }) => {
+
+const AllPostsTape = ({ onGetAllPosts, clearPostsTape }) => {
     const [checkScroll, setCheckScroll] = useState(true)
     const [checkScroll, setCheckScroll] = useState(true)
 
 
     useEffect(() => {
     useEffect(() => {
         if (checkScroll) {
         if (checkScroll) {
-            onAllPosts()
+            onGetAllPosts()
             setCheckScroll(false)
             setCheckScroll(false)
         }
         }
     }, [checkScroll])
     }, [checkScroll])
@@ -19,7 +20,7 @@ const AllPosts = ({ onAllPosts, postsRemove }) => {
         document.addEventListener('scroll', scrollHandler)
         document.addEventListener('scroll', scrollHandler)
         return () => {
         return () => {
             document.removeEventListener('scroll', scrollHandler)
             document.removeEventListener('scroll', scrollHandler)
-            postsRemove()
+            clearPostsTape()
         }
         }
     }, [])
     }, [])
 
 
@@ -32,9 +33,9 @@ const AllPosts = ({ onAllPosts, postsRemove }) => {
     return (
     return (
         <Container>
         <Container>
             <CPreloader promiseName='allPosts' />
             <CPreloader promiseName='allPosts' />
-            <CPosts />
+            <CGalleryMediaPostsUser />
         </Container>
         </Container>
     )
     )
 }
 }
 
 
-export const CAllPosts = connect(null, { onAllPosts: actionAllPosts, postsRemove: actionRemovePostAC, })(AllPosts)
+export const CAllPostsTape = connect(null, { onGetAllPosts: actionGetAllPostsSagaAC, clearPostsTape: actionClearPostsTapeAC })(AllPostsTape)

+ 1 - 0
src/pages/Authorization.jsx

@@ -1,6 +1,7 @@
 import { Card, Col, Divider, Row } from "antd";
 import { Card, Col, Divider, Row } from "antd";
 import { NavLink } from "react-router-dom";
 import { NavLink } from "react-router-dom";
 import { CLoginForm, CRegisterForm } from "../components/FormAuthorization";
 import { CLoginForm, CRegisterForm } from "../components/FormAuthorization";
+
 import authBg from "../images/authBg.png"
 import authBg from "../images/authBg.png"
 
 
 export const Authorization = ({ match: { params: { _id } } }) =>
 export const Authorization = ({ match: { params: { _id } } }) =>

+ 12 - 8
src/pages/CollectionPage.jsx

@@ -2,17 +2,18 @@ import { Divider } from 'antd';
 import Title from 'antd/lib/typography/Title';
 import Title from 'antd/lib/typography/Title';
 import React, { useEffect } from 'react';
 import React, { useEffect } from 'react';
 import { connect } from 'react-redux';
 import { connect } from 'react-redux';
-import { actionFullMyCollectionLoad, actionRemovePostAC } from '../actions';
-import { CPosts } from '../components/main/Posts';
-import { Container } from './Content';
-import { CPreloader } from './Preloader';
+import { actionClearPostsTapeAC, actionGetPostsMyCollectionSagaAC } from '../actions/actonsCreators';
+import { Container } from '../components/Container';
+import { CGalleryMediaPostsUser } from '../components/GalleryMediaPostsUser';
+import { CPreloader } from '../components/Preloader';
 
 
-export const CollectionPage = ({ posts, onLoadPosts, postsRemove }) => {
+
+export const CollectionPage = ({ onLoadPosts, clearPostsTape }) => {
 
 
     useEffect(() => {
     useEffect(() => {
         onLoadPosts()
         onLoadPosts()
         return () => {
         return () => {
-            postsRemove()
+            clearPostsTape()
         }
         }
     }, [])
     }, [])
 
 
@@ -20,8 +21,11 @@ export const CollectionPage = ({ posts, onLoadPosts, postsRemove }) => {
         <Container>
         <Container>
             <CPreloader promiseName='onLoadMyCollections' />
             <CPreloader promiseName='onLoadMyCollections' />
             <Divider><Title level={1}>Collections</Title></Divider>
             <Divider><Title level={1}>Collections</Title></Divider>
-            <CPosts />
+            <CGalleryMediaPostsUser />
         </Container>
         </Container>
     )
     )
 }
 }
-export const CCollectionPage = connect(state => ({ posts: state?.post?.posts || [] }), { onLoadPosts: actionFullMyCollectionLoad, postsRemove: actionRemovePostAC })(CollectionPage)
+export const CCollectionPage = connect(null, {
+    onLoadPosts: actionGetPostsMyCollectionSagaAC,
+    clearPostsTape: actionClearPostsTapeAC
+})(CollectionPage)

+ 30 - 30
src/pages/EntityEditorPost.jsx

@@ -2,41 +2,31 @@ import { Button, Divider, message } from "antd"
 import Title from "antd/lib/typography/Title"
 import Title from "antd/lib/typography/Title"
 import { useEffect, useState } from "react"
 import { useEffect, useState } from "react"
 import { connect } from "react-redux"
 import { connect } from "react-redux"
-import { actionAddPostAC, actionClearPromise, actionFullSentPost, actionRemovePostAC, } from "../actions"
-import { EditPhotos } from "../components/uploadPhoto/EditPhotos"
-import { EditDescriptionPost } from "../components/uploadPhoto/EditDescriptionPost"
-import { EditTitlePost } from "../components/uploadPhoto/EditTitlePost"
-import { Container } from "./Content"
+import { actionClearPostsOneAC, actionCreatePostSagaAC, actionPostOneDataAC } from "../actions/actonsCreators"
 import { history } from '../App'
 import { history } from '../App'
+import { Container } from "../components/Container"
+import { EditDescriptionPost } from "../components/editPost/EditDescriptionPost"
+import { EditPhotos } from "../components/editPost/EditPhotos"
+import { EditTitlePost } from "../components/editPost/EditTitlePost"
 
 
 
 
 const ContainEditorPost = ({ children }) =>
 const ContainEditorPost = ({ children }) =>
     <div className='ContainEditPost ContainerInner'>{children}</div>
     <div className='ContainEditPost ContainerInner'>{children}</div>
 
 
-const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, onSave, updatePost, clearState, clearStatus }) => {
+
+const EditPostPage = ({ match: { params: { _id } }, myID, entity, status, onSave, clearPostOne }) => {
 
 
     const [photos, setPhotos] = useState(entity?.images || []);
     const [photos, setPhotos] = useState(entity?.images || []);
     const [titleSend, setTitleSend] = useState(entity?.title || '')
     const [titleSend, setTitleSend] = useState(entity?.title || '')
     const [description, setDescription] = useState(entity?.text || '');
     const [description, setDescription] = useState(entity?.text || '');
 
 
     useEffect(() => {
     useEffect(() => {
-        if (_id !== 'new') {
-            if (Array.isArray(entity)) {
-                let findEntity = entity.find(e => e._id === _id)
-                setPhotos(findEntity?.images)
-                setTitleSend(findEntity?.title)
-                setDescription(findEntity?.text)
-                updatePost(findEntity)
-            }
-        } else {
+        if (_id === 'new' && Object.keys(entity).length) {
+            clearPostOne()
             setPhotos([])
             setPhotos([])
             setTitleSend('')
             setTitleSend('')
             setDescription('')
             setDescription('')
         }
         }
-        return () => {
-            clearState()
-            clearStatus('sentPost')
-        }
     }, [_id]);
     }, [_id]);
 
 
 
 
@@ -50,30 +40,40 @@ const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, on
     }, [status])
     }, [status])
 
 
     const disabledBtn = photos?.length && titleSend && description ? false : true
     const disabledBtn = photos?.length && titleSend && description ? false : true
-    const sentPost = () => onSave(photos, titleSend, description)
+    const savePost = () => onSave(photos, titleSend, description)
 
 
     return (
     return (
         <Container>
         <Container>
             <ContainEditorPost >
             <ContainEditorPost >
                 <h1 className="title" level={1}>Create / edit Post</h1>
                 <h1 className="title" level={1}>Create / edit Post</h1>
-                <Divider orientation="left" orientationMargin="0"><Title level={3}>Photos</Title></Divider>
+                <Divider orientation="left" orientationMargin="0">
+                    <Title level={3}>Photos</Title>
+                </Divider>
+
                 <EditPhotos photos={photos} setPhotos={setPhotos} />
                 <EditPhotos photos={photos} setPhotos={setPhotos} />
                 <EditTitlePost titleSend={titleSend} setTitleSend={setTitleSend} />
                 <EditTitlePost titleSend={titleSend} setTitleSend={setTitleSend} />
                 <EditDescriptionPost description={description} setDescription={setDescription} />
                 <EditDescriptionPost description={description} setDescription={setDescription} />
-                <Divider orientation="right">   <Button disabled={disabledBtn} type="primary" onClick={sentPost}>Send a Post</Button></Divider>
+
+                <Divider orientation="right">
+                    <Button
+                        disabled={disabledBtn}
+                        type="primary"
+                        onClick={savePost}
+                    >
+                        Save a Post
+                    </Button>
+                </Divider>
             </ContainEditorPost>
             </ContainEditorPost>
         </ Container>
         </ Container>
     )
     )
 }
 }
 
 
-export const CEntityEditorPost = connect(state => ({
-    myID: state?.auth?.payload?.sub?.id,
-    entity: state?.post.posts,
+export const CEditPostPage = connect(state => ({
+    myID: state?.aboutMe?._id,
+    entity: state?.postOne,
     status: state?.promise?.sentPost?.status
     status: state?.promise?.sentPost?.status
 }),
 }),
     {
     {
-        updatePost: actionAddPostAC,
-        onSave: actionFullSentPost,
-        clearState: actionRemovePostAC,
-        clearStatus: actionClearPromise
-    })(EntityEditorPost)
+        onSave: actionCreatePostSagaAC,
+        clearPostOne: actionClearPostsOneAC
+    })(EditPostPage)

+ 0 - 129
src/pages/MainPostsFeed.jsx

@@ -1,129 +0,0 @@
-import { Card, Col, Row, Divider } from 'antd'
-import React, { useEffect, useState } from 'react'
-import { connect } from 'react-redux'
-import { Link } from 'react-router-dom'
-import Paragraph from 'antd/lib/typography/Paragraph'
-import Text from 'antd/lib/typography/Text'
-import { actionPostsFeed, actionRemovePostAC } from '../actions'
-import { DateCreated } from '../components/main/DateCreated'
-import PostImage from '../components/main/postsFeed/PostImage'
-import { CPostUserPanel } from '../components/main/postsFeed/PostUserPanel'
-import { Container } from './Content'
-import { CPostTitle } from '../components/main/post/PostTitle'
-import { CPreloader } from './Preloader'
-import { CFieldCommentSend } from '../components/main/postsFeed/FieldComment'
-import { PostCommentDate } from '../components/main/post/PostComment'
-import Title from 'antd/lib/typography/Title'
-
-
-export const PostDescription = ({ title, description, date }) =>
-    <>
-        <Row justify='space-between'>
-            <Col >
-                {!!title && <Text level={3} strong>{title}</Text>}
-            </Col>
-            <Col >
-                <Text type='secondary'>
-                    <DateCreated date={date} />
-                </Text>
-            </Col>
-        </Row>
-        <Paragraph ellipsis={true ? { rows: 1, expandable: true, symbol: '...More' } : false}>
-            {description}
-        </Paragraph>
-    </>
-
-const CommentPostFeed = ({ comment }) =>
-    <div className='CommentPostFeed'>
-        <Link to={`/profile/${comment.owner._id}`}>
-            {comment?.owner?.nick || comment?.owner?.login}
-        </Link>
-        <PostCommentDate createdAt={comment.createdAt} />
-        <Paragraph ellipsis={{ rows: 1, expandable: true, symbol: 'more' }}>
-            {comment?.text}
-        </Paragraph>
-    </div>
-
-export const CommentSPostFeed = ({ comments = [], _id }) =>
-    <>
-        {
-            comments && comments.length
-                ? <>
-                    {(comments.length > 2) && <Link to={`/post/${_id}`}>
-                        <Divider orientation="left">
-                            {comments?.length ? `View ${comments.length} comments` : 'No comments'}
-                        </Divider>
-                    </Link>}
-                    {comments.slice(0, 2).map(c => <CommentPostFeed key={c._id} comment={c} />)}
-                </>
-                : <Link to={`/post/${_id}`}>
-                    <Divider orientation="left">
-                        {comments?.length ? `View ${comments.length} comments` : 'No comments'}
-                    </Divider>
-                </Link>
-        }
-        <CFieldCommentSend id={_id} setOpen={() => { }} />
-    </>
-
-const Post = ({ postData: { _id, text, title, owner, images, createdAt = '', comments, likes, collections } }) =>
-    <div className='Post'>
-        <Card
-            title={<CPostTitle owner={owner} postId={_id} />}
-            cover={<PostImage images={images} />}
-        >
-            <CPostUserPanel postId={_id}
-                likes={likes}
-                collections={collections}
-                styleFontSize='1.7em' />
-            <PostDescription title={title} description={text} date={createdAt} />
-            <CommentSPostFeed comments={comments} _id={_id} />
-        </Card>
-    </div>
-
-
-const MainPostsFeed = ({ posts, postsFollowing, clearState, following }) => {
-
-    const [checkScroll, setCheckScroll] = useState(true)
-
-    useEffect(() => {
-        if (checkScroll && following.length !== 0) {
-            postsFollowing()
-            setCheckScroll(false)
-        }
-    }, [checkScroll, following])
-
-    useEffect(() => {
-        document.addEventListener('scroll', scrollHandler)
-        return () => {
-            document.removeEventListener('scroll', scrollHandler)
-            clearState()
-
-        }
-    }, [])
-
-    const scrollHandler = (e) => {
-        if (e.target.documentElement.scrollHeight - (e.target.documentElement.scrollTop + window.innerHeight) < 500) {
-            setCheckScroll(true)
-        }
-    }
-
-    return (
-        <Container>
-            <CPreloader promiseName='followingPosts' />
-            {Array.isArray(posts) && posts.length
-                ? posts.map(p => <Post key={p._id} postData={p} />)
-                : <Title level={4}>
-                    The tape is empty. Subscribe to users to see them
-                    posts or create your own
-                </Title>}
-        </Container>
-    )
-}
-
-export const CMainPostsFeed = connect(state => ({
-    posts: state?.post?.posts || [],
-    following: state?.myData?.following || []
-}), {
-    postsFollowing: actionPostsFeed,
-    clearState: actionRemovePostAC,
-})(MainPostsFeed)

+ 57 - 0
src/pages/PostOnePage.jsx

@@ -0,0 +1,57 @@
+import React from 'react'
+import { Divider } from 'antd';
+import { connect } from 'react-redux'
+import Text from 'antd/lib/typography/Text';
+import PostImageCover from '../components/post/PostImageCover';
+import { CEditMyPostBtn, PostHeader } from '../components/post/PostHeader';
+import { CPostDescription } from '../components/post/PostDescription';
+import { CPostOneUserPanel } from '../components/post/PostUserPanel';
+import { CCommentFieldPostOne } from '../components/CommentField';
+import { CPostOneComments } from '../components/post/PostOneComment';
+import { CEditPostPage } from './EditPostPage';
+import { CPreloader } from '../components/Preloader';
+
+
+const PostOnePageDescrption = ({ data: { _id, likes } }) =>
+    <div className='PostOne__description-inner'>
+        <div className='PostOne__description-top'>
+            <CPostDescription />
+            <Divider plain>
+                <Text type='secodary'>Comments</Text>
+            </Divider>
+            <div className='PostOne__comments'>
+                <CPostOneComments />
+            </div>
+        </div>
+        <div className='PostOne__description-bottom'>
+            <Divider />
+            <CPostOneUserPanel likes={likes} postId={_id}
+                styleFontSize='1.3em' />
+            <CCommentFieldPostOne id={_id} setOpen={() => { }} />
+        </div>
+    </div>
+
+
+const CPostOnePageDescrption = connect(state => ({ data: state?.postOne || {} }))(PostOnePageDescrption)
+
+
+const PostOnePage = ({ data: { _id, images, owner } }) =>
+    < div className='PostOne' >
+        <CPreloader promiseName='postOne' />
+        <div className='PostOne__inner' >
+            <div className='PostOne__image'>
+                <PostImageCover images={images} />
+            </div>
+            <div className='PostOne__title'>
+                <PostHeader owner={owner}>
+                    <CEditMyPostBtn owner={owner} postId={_id} />
+                </PostHeader>
+            </div>
+            <div className='PostOne__description'>
+                <CPostOnePageDescrption />
+            </div>
+        </div >
+    </div >
+
+
+export const CPostOnePage = connect(state => ({ data: state?.postOne || {} }))(PostOnePage)

+ 0 - 57
src/pages/PostPage.jsx

@@ -1,57 +0,0 @@
-import React from 'react'
-import { Divider } from 'antd';
-import { connect } from 'react-redux'
-import PostImage from '../components/main/postsFeed/PostImage'
-import Text from 'antd/lib/typography/Text';
-import { CFieldCommentSend } from '../components/main/postsFeed/FieldComment';
-import { CPostUserPanel } from '../components/main/postsFeed/PostUserPanel';
-import { CPostTitle } from '../components/main/post/PostTitle';
-import { CPreloader } from './Preloader';
-import { CPostComments } from '../components/main/post/PostComment';
-import { PostDescription } from './MainPostsFeed';
-
-
-
-const PostPageTitle = ({ data: { owner }, postId }) =>
-    <CPostTitle owner={owner} postId={postId} />
-
-const CPostPageTitle = connect(state => ({ data: state?.post?.posts || {}, postId: state?.post?.posts?._id }))(PostPageTitle)
-
-const PostPageDescrption = ({ data: { _id, likes, text, title, createdAt, } }) =>
-    <div className='PostOne__description-inner'>
-        <div className='PostOne__description-top'>
-            <PostDescription title={title} description={text} date={createdAt} />
-            <Divider plain><Text type='secodary'>Comments</Text></Divider>
-            <div className='PostOne__comments'>
-                <CPostComments />
-            </div>
-        </div>
-        <div className='PostOne__description-bottom'>
-            <Divider />
-            <CPostUserPanel likes={likes} postId={_id}
-                styleFontSize='1.3em' />
-            <CFieldCommentSend id={_id} setOpen={() => { }} /> {/* setOpen - функция заглушка для пропса компонента*/}
-        </div>
-    </div>
-
-
-const CPostPageDescrption = connect(state => ({ data: state?.post?.posts || {} }))(PostPageDescrption)
-
-
-const PostPage = ({ data: { images } }) =>
-    <div className='PostOne'>
-        <CPreloader promiseName='postOne' />
-        <div className='PostOne__inner'>
-            <div className='PostOne__image'>
-                <PostImage images={images} />
-            </div>
-            <div className='PostOne__title'>
-                <CPostPageTitle />
-            </div>
-            <div className='PostOne__description'>
-                <CPostPageDescrption />
-            </div>
-        </div>
-    </div>
-
-export const CPostPage = connect(state => ({ data: state?.post?.posts || {} }))(PostPage)

+ 77 - 0
src/pages/PostsTapeMyFollowing.jsx

@@ -0,0 +1,77 @@
+import { Card } from 'antd'
+import React, { useEffect, useState } from 'react'
+import { connect } from 'react-redux'
+import Title from 'antd/lib/typography/Title'
+import { Container } from '../components/Container'
+import { actionClearPostsTapeAC, actionGetPostsTapeSagaAC } from '../actions/actonsCreators'
+import { PostHeader } from '../components/post/PostHeader'
+import PostImageCover from '../components/post/PostImageCover'
+import { CPostTapeUserPanel } from '../components/post/PostUserPanel'
+import { PostDescription } from '../components/post/PostDescription'
+import { CommentsPostInTape } from '../components/post/CommentsPostInTape'
+import { CPreloader } from '../components/Preloader'
+
+
+const Post = ({ postData: { _id, text, title, owner, images, createdAt = '', comments, likes, collections } }) =>
+    <div className='Post'>
+        <Card
+            title={<PostHeader owner={owner} />}
+            cover={<PostImageCover images={images} />}
+        >
+            <CPostTapeUserPanel
+                postId={_id}
+                likes={likes}
+                collections={collections}
+                styleFontSize='1.7em' />
+            <PostDescription title={title} description={text} date={createdAt} />
+            <CommentsPostInTape comments={comments} _id={_id} />
+        </Card>
+    </div>
+
+
+const PostsTapeMyFollowing = ({ posts, onGetPostsTape, clearPostsTape, following, status }) => {
+
+    const [checkScroll, setCheckScroll] = useState(true)
+
+    useEffect(() => {
+        if (checkScroll && following.length !== 0) {
+            onGetPostsTape()
+            setCheckScroll(false)
+        } 
+    }, [checkScroll, following])
+
+    useEffect(() => {
+        document.addEventListener('scroll', scrollHandler)
+        return () => {
+            document.removeEventListener('scroll', scrollHandler)
+            clearPostsTape()
+        }
+    }, [])
+
+    const scrollHandler = (e) => {
+        if (e.target.documentElement.scrollHeight - (e.target.documentElement.scrollTop + window.innerHeight) < 500) {
+            setCheckScroll(true)
+        }
+    }
+
+    return (
+        <Container>
+            <CPreloader promiseName='followingPosts' />
+            {posts.length
+                ? posts.map(p => <Post key={p._id} postData={p} />)
+                : <Title level={4}>
+                    The tape is empty. Subscribe to users to see them
+                    posts or create your own
+                </Title>}
+        </Container>
+    )
+}
+
+export const CPostsTapeMyFollowing = connect(state => ({
+    posts: state?.postsTape?.posts || [],
+    following: state?.aboutMe?.following || [],
+    status: state?.promise?.followingPosts
+}), {
+    onGetPostsTape: actionGetPostsTapeSagaAC,
+    clearPostsTape: actionClearPostsTapeAC,
+})(PostsTapeMyFollowing)

+ 119 - 71
src/pages/ProfilePage.jsx

@@ -2,100 +2,147 @@ import React, { useEffect, useState } from 'react'
 import { Button, Col, Row } from 'antd'
 import { Button, Col, Row } from 'antd'
 import { connect } from 'react-redux'
 import { connect } from 'react-redux'
 import { Link } from 'react-router-dom'
 import { Link } from 'react-router-dom'
-import { actionProfilePageData, actionRemovePostAC, actionSubscribe, actionUnSubscribe } from '../actions'
-import { CModalFollowers, CModalFollowing } from '../components/main/profilePage/ModalFollow'
-import { DateCreated } from '../components/main/DateCreated'
+import { actionChangeSubscribeSagaAC, actionClearPostsTapeAC, actionClearProfileDataAC, actionProfileDataSagaAC } from '../actions/actonsCreators'
+import { Container } from '../components/Container'
+import { UserAvatar } from '../components/UserAvatar'
+import { DateCreated } from '../components/post/PostDescription'
 import Text from 'antd/lib/typography/Text'
 import Text from 'antd/lib/typography/Text'
-import { Container } from './Content'
-import { CPosts } from '../components/main/Posts'
-import { UserAvatar } from '../components/header/UserAvatar'
-import { CPreloader } from './Preloader'
+import { CModalFollowers, CModalFollowing } from '../components/ModalFollow'
+import { CGalleryMediaPostsUser } from '../components/GalleryMediaPostsUser'
+import { CPreloader } from '../components/Preloader'
 
 
-const ProfileFollowButton = ({ myID, userId, followers, onSubsuscribe, onUnSubsuscribe }) => {
+
+const ProfileFollowButton = ({ myID, userId, followers, onChangeSubscribe }) => {
     const followCheck = followers.find(f => f._id === myID && true)
     const followCheck = followers.find(f => f._id === myID && true)
     return (
     return (
         <Col className='Profile__setting'>
         <Col className='Profile__setting'>
             {!!followCheck ?
             {!!followCheck ?
-                <Button onClick={() => onUnSubsuscribe(userId)}>UnSubscribe</Button> :
-                <Button onClick={() => onSubsuscribe(userId)} type="primary">Subscribe</Button>}
+                <Button onClick={() => onChangeSubscribe(userId, followCheck)}>UnSubscribe</Button> :
+                <Button onClick={() => onChangeSubscribe(userId, followCheck)} type="primary">Subscribe</Button>}
         </Col>
         </Col>
     )
     )
 }
 }
 
 
-export const CProfileFollowButton = connect(state => ({
-    myID: state?.auth?.payload?.sub.id,
-    followers: state?.post?.userData?.followers || []
-}), { onSubsuscribe: actionSubscribe, onUnSubsuscribe: actionUnSubscribe })(ProfileFollowButton)
+
+const CProfileFollowButton = connect(state => (
+    {
+        myID: state?.aboutMe._id,
+        followers: state?.dataProfile?.followers || []
+    }),
+    {
+        onChangeSubscribe: actionChangeSubscribeSagaAC
+    })(ProfileFollowButton)
+
+
+const ProfilePageName = ({ myID, data: { _id, login, nick } }) =>
+    <Row align='top' justify='space-between' className='Profile__name'>
+        <Col>
+            <h1>{nick || login || 'No Name'}</h1>
+            <span className='Profile__login'>{login || '----'}</span>
+        </Col>
+        <Col >
+            {myID !== _id
+                ? <CProfileFollowButton userId={_id} />
+                : <Button type=''>
+                    <Link to={`/my-settings`}>Settings</Link>
+                </Button>}
+        </Col>
+    </Row>
+
+const CProfilePageName = connect(state => ({
+    myID: state?.aboutMe?._id,
+    data: state?.dataProfile
+}))(ProfilePageName)
+
+
+const ProfilePageCreateAt = ({ myID, data: { _id, createdAt } }) =>
+    <Row align='middle' justify='space-between'>
+        <Col className='Profile__created'>
+            <Text type='secondary'>
+                Account created: <DateCreated date={createdAt} />
+            </Text>
+        </Col>
+        {myID !== _id &&
+            <Col offset={1}>
+                <Link className='Profile__link-message' to='/message'>
+                    Send message
+                </Link>
+            </Col>
+        }
+    </Row>
+
+const CProfilePageCreateAt = connect(state => ({
+    myID: state?.aboutMe?._id,
+    data: state?.dataProfile
+}))(ProfilePageCreateAt)
 
 
 
 
-const ProfilePageData = ({ myID, data: { _id, avatar, login, nick, createdAt = '', followers, following }, count, setFollowing, setFollowers }) =>
+const ProfilePageStatistic = ({ count, data: { followers, following } }) => {
+    const [openFollowers, setOpenFollowers] = useState(false)
+    const [openFollowing, setOpenFollowing] = useState(false)
+    return (
+        <Row className='Profile__count' align='middle' justify='space-between' >
+            <Col >
+                <strong>{count || '0'}</strong>
+                <span>Posts</span>
+            </Col>
+            <Col >
+                <Button type="link" onClick={() => setOpenFollowers(true)}>
+                    <strong>{followers?.length || '0'}</strong>
+                    <span>Followers</span>
+                </Button>
+            </Col>
+            <Col >
+                <Button type="link" onClick={() => setOpenFollowing(true)}>
+                    <strong>{following?.length || '0'}</strong>
+                    <span>Following</span>
+                </Button>
+            </Col>
+            {openFollowers && < CModalFollowers statusModal={setOpenFollowers} title={'Followers'} />}
+            {openFollowing && < CModalFollowing statusModal={setOpenFollowing} title={'Following'} />}
+        </ Row>
+    )
+}
+
+const CProfilePageStatistic = connect(state => ({
+    data: state?.dataProfile,
+    count: state?.postsTape?.count
+}))(ProfilePageStatistic)
+
+
+const ProfilePageData = ({ children }) =>
+    <>{children} </>
+
+
+const ProfilePageDataContainer = ({ avatar }) =>
     <Row className='Profile' >
     <Row className='Profile' >
         <Col flex={'150px'}>
         <Col flex={'150px'}>
             <UserAvatar avatarSize={'150px'} avatar={avatar} />
             <UserAvatar avatarSize={'150px'} avatar={avatar} />
         </Col>
         </Col>
         <Col className='Profile__data' flex={'auto'} offset={2}>
         <Col className='Profile__data' flex={'auto'} offset={2}>
-            <Row align='top' justify='space-between' className='Profile__name'>
-                <Col>
-                    <h1>{nick || login || 'No Name'}</h1>
-                    <span className='Profile__login'>{login || '----'}</span>
-                </Col>
-                <Col >
-                    {myID !== _id
-                        ? <CProfileFollowButton userId={_id} />
-                        : <Button type=''><Link to={`/my-settings`}>Settings</Link></Button>}
-                </Col>
-            </Row>
-            <Row align='middle' justify='space-between'>
-                <Col className='Profile__created'>
-                    <Text type='secondary'>Account created: <DateCreated date={createdAt} /></Text>
-                </Col>
-                {myID !== _id && <Col offset={1}>
-                    <Link className='Profile__link-message' to='/message'>Send message</Link>
-                </Col>}
-            </Row>
-            <Row className='Profile__count' align='middle' justify='space-between'>
-                <Col >
-                    <strong>{count || '0'}</strong>
-                    <span>Posts</span>
-                </Col>
-                <Col >
-                    <Button type="link" onClick={() => setFollowers(true)}>
-                        <strong>{followers?.length || '0'}</strong>
-                        <span>Followers</span>
-                    </Button>
-                </Col>
-                <Col >
-                    <Button type="link" onClick={() => setFollowing(true)}>
-                        <strong>{following?.length || '0'}</strong>
-                        <span>Following</span>
-                    </Button>
-                </Col>
-            </Row>
-        </Col >
+            <ProfilePageData>
+                <CProfilePageName />
+                <CProfilePageCreateAt />
+                <CProfilePageStatistic />
+            </ProfilePageData>
+        </Col>
     </Row >
     </Row >
 
 
+const CProfilePageData = connect(state => ({ avatar: state?.dataProfile?.avatar }))(ProfilePageDataContainer)
 
 
-const CProfilePageData = connect(state => ({
-    myID: state.auth.payload.sub.id || '',
-    data: state?.post?.userData || {},
-    count: state?.post?.count || null
-}))(ProfilePageData)
 
 
 
 
+const ProfilePage = ({ match: { params: { _id } }, getProfileUser, clearProfileData, clearPostsTape }) => {
 
 
-
-const ProfilePage = ({ match: { params: { _id } }, getProfileUser, clearDataProfile }) => {
-    const [followers, setFollowers] = useState(false)
-    const [following, setFollowing] = useState(false)
     const [checkScroll, setCheckScroll] = useState(true)
     const [checkScroll, setCheckScroll] = useState(true)
 
 
-
     useEffect(() => {
     useEffect(() => {
         document.addEventListener('scroll', scrollHandler)
         document.addEventListener('scroll', scrollHandler)
         return () => {
         return () => {
             document.removeEventListener('scroll', scrollHandler)
             document.removeEventListener('scroll', scrollHandler)
             setCheckScroll(true)
             setCheckScroll(true)
-            clearDataProfile()
+            clearProfileData()
+            clearPostsTape()
         }
         }
     }, [_id])
     }, [_id])
 
 
@@ -115,14 +162,15 @@ const ProfilePage = ({ match: { params: { _id } }, getProfileUser, clearDataProf
     return (
     return (
         <Container>
         <Container>
             <CPreloader promiseName='userOneDataPosts'/>
             <CPreloader promiseName='userOneDataPosts'/>
-            <CProfilePageData setFollowing={setFollowing} setFollowers={setFollowers} />
-            {followers && < CModalFollowers statusModal={setFollowers} title={'Followers'} />}
-            {following && < CModalFollowing statusModal={setFollowing} title={'Following'} />}
-            <CPosts />
+            <CProfilePageData />
+            <CGalleryMediaPostsUser />
         </Container>
         </Container>
     )
     )
 }
 }
 
 
-export const CProfilePage = connect(state => ({
-    posts: state?.post?.posts || []
-}), { getProfileUser: actionProfilePageData, clearDataProfile: actionRemovePostAC })(ProfilePage)
+export const CProfilePage = connect(null,
+    {
+        getProfileUser: actionProfileDataSagaAC,
+        clearProfileData: actionClearProfileDataAC,
+        clearPostsTape: actionClearPostsTapeAC,
+    })(ProfilePage)

+ 48 - 23
src/pages/SettingsPage.jsx

@@ -1,12 +1,13 @@
 import React, { useEffect, useState } from 'react';
 import React, { useEffect, useState } from 'react';
-import { Container } from './Content';
-import { CEditAvatar } from '../components/main/profilePage/EditAvatar'
 import { Button, Col, Divider, Input, message, Row, Space } from 'antd'
 import { Button, Col, Divider, Input, message, Row, Space } from 'antd'
 import Title from 'antd/lib/typography/Title';
 import Title from 'antd/lib/typography/Title';
-import { connect } from 'react-redux';
-import { EditOutlined, LogoutOutlined } from '@ant-design/icons';
 import Text from 'antd/lib/typography/Text';
 import Text from 'antd/lib/typography/Text';
-import { actionAuthLogout, actionFullAboutMeUpsert, actionRemoveMyDataAC } from '../actions';
+import { EditOutlined, LogoutOutlined } from '@ant-design/icons';
+import { connect } from 'react-redux';
+import { Container } from '../components/Container';
+import { actionAboutMeUpsertSagaAC, actionAuthLogoutAC, actionClearAboutMeDataAC } from '../actions/actonsCreators';
+import { CChangeAvatar } from '../components/ChangeAvatar';
+
 
 
 
 
 const ContainerSettingsPage = ({ children }) =>
 const ContainerSettingsPage = ({ children }) =>
@@ -17,13 +18,13 @@ const EditMyDataIput = ({ title, propValue, propHandler, error, setError, setChe
     const [value, setValue] = useState(propValue);
     const [value, setValue] = useState(propValue);
     const [editMode, setEditMode] = useState(false);
     const [editMode, setEditMode] = useState(false);
 
 
-
     useEffect(() => {
     useEffect(() => {
         setValue(propValue)
         setValue(propValue)
     }, [propValue]);
     }, [propValue]);
 
 
     const addValueHandler = () => {
     const addValueHandler = () => {
         const valid = /^[A-Z][a-z0-9_]{1,15}$/
         const valid = /^[A-Z][a-z0-9_]{1,15}$/
+
         if (valid.test(value)) {
         if (valid.test(value)) {
             propHandler(value)
             propHandler(value)
             setEditMode(false)
             setEditMode(false)
@@ -42,14 +43,19 @@ const EditMyDataIput = ({ title, propValue, propHandler, error, setError, setChe
         <label onDoubleClick={() => setEditMode(true)}>
         <label onDoubleClick={() => setEditMode(true)}>
             <Title level={4}>{title} :</Title>
             <Title level={4}>{title} :</Title>
             <div className='EditMyData__lable-box'>
             <div className='EditMyData__lable-box'>
-                {error && <Text type='danger'> First letter is capitalized!!!</Text>}
+                {error &&
+                    <Text type='danger'>
+                        No spaces,First letter is capitalized!!!
+                    </Text>}
                 {!editMode
                 {!editMode
-                    ? <Text className='EditMyData__lable-text'>{value}
+                    ?
+                    <Text className='EditMyData__lable-text'>{value}
                         <EditOutlined
                         <EditOutlined
                             onClick={() => setEditMode(true)}
                             onClick={() => setEditMode(true)}
                             style={{ fontSize: '1.1em', color: '#1890ff ' }} />
                             style={{ fontSize: '1.1em', color: '#1890ff ' }} />
                     </Text>
                     </Text>
-                    : <Input className={error && '--error'} value={value}
+                    :
+                    <Input className={error && '--error'} value={value}
                         onBlur={addValueHandler}
                         onBlur={addValueHandler}
                         onChange={onChangeInput}
                         onChange={onChangeInput}
                         onPressEnter={addValueHandler}
                         onPressEnter={addValueHandler}
@@ -105,31 +111,50 @@ const EditMyData = ({ myData, status, onUpsert }) => {
     )
     )
 }
 }
 
 
-const CEditMyData = connect(state => ({ myData: state?.myData, status: state?.promise?.upsertAboutMe?.status }), { onUpsert: actionFullAboutMeUpsert })(EditMyData)
+const CEditMyData = connect(state => ({
+    myData: state?.aboutMe,
+    status: state?.promise?.upsertAboutMe?.status
+}), {
+    onUpsert: actionAboutMeUpsertSagaAC
+})(EditMyData)
+
+
+const SettingsPageInner = () =>
+    <Row >
+        <Col flex={1}>
+            <CChangeAvatar />
+        </Col>
+        <Col flex={4} offset={1} className='EditMyData'>
+            <CEditMyData />
+        </Col>
+    </Row>
+
 
 
-const SettingsPage = ({ onLogOut, removeMydata }) => {
+const SettingsPage = ({ onLogOut, clearMydata }) => {
     const handlerExitBtn = () => {
     const handlerExitBtn = () => {
         onLogOut()
         onLogOut()
-        removeMydata()
+        clearMydata()
     }
     }
     return (
     return (
         <Container>
         <Container>
             <ContainerSettingsPage>
             <ContainerSettingsPage>
-                <Divider><Title level={2}>Profile Settings</Title></Divider>
-                <Row >
-                    <Col flex={1}>
-                        <CEditAvatar />
-                    </Col>
-                    <Col flex={4} offset={1} className='EditMyData'>
-                        <CEditMyData />
-                    </Col>
-                </Row>
+                <Divider>
+                    <Title level={2}>
+                        Profile Settings
+                    </Title>
+                </Divider>
+                <SettingsPageInner />
                 <Space className='Exit-box__btn'>
                 <Space className='Exit-box__btn'>
-                    <Button onClick={handlerExitBtn}><LogoutOutlined /> Exit</Button>
+                    <Button onClick={handlerExitBtn}><LogoutOutlined />
+                        Exit
+                    </Button>
                 </Space>
                 </Space>
             </ContainerSettingsPage>
             </ContainerSettingsPage>
         </Container>
         </Container>
     )
     )
 }
 }
 
 
-export const CSettingsPage = connect(null, { onLogOut: actionAuthLogout, removeMydata: actionRemoveMyDataAC })(SettingsPage)
+export const CSettingsPage = connect(null, {
+    onLogOut: actionAuthLogoutAC,
+    clearMydata: actionClearAboutMeDataAC
+})(SettingsPage)

+ 18 - 0
src/redux/reducers/aboutMe-reducer.js

@@ -0,0 +1,18 @@
+
+export const aboutMeReducer = (state = {}, { type, data }) => {
+    const types = {
+        'ABOUTME-DATA-ADD': () => ({ ...state, ...data }),
+
+        'CHANGE-ABOUTME-AVATAR': () =>  ({ ...state, avatar: { ...data } }),
+
+        'UPDATE-MY-FOLLOWING': () => ({ ...state, following: [...data] }),
+
+        'UPSERT-COLLECTION': () => ({...state, collection:data }),
+        
+        'CLEAR-ABOUTME': () => ({})
+    }
+    if (type in types) {
+        return types[type]()
+    }
+    return state
+}

+ 10 - 1
src/redux/reducers/auth-reducer.js

@@ -1,5 +1,14 @@
-import { jwtDecode } from '../../helpers'
 
 
+const jwtDecode = (token) => {
+    try {
+        let arrToken = token.split('.')
+        let base64Token = atob(arrToken[1])
+        return JSON.parse(base64Token)
+    }
+    catch (e) {
+        console.log('Ой, ошибочка вышла ' + e);
+    }
+}
 
 
 export const authReducer = (state, { type, token, remember }) => {
 export const authReducer = (state, { type, token, remember }) => {
     if (!state) {
     if (!state) {

+ 0 - 22
src/redux/reducers/myProfile-reducer.js

@@ -1,22 +0,0 @@
-
-export const myProfileReducer = (state = {}, { type, data }) => {
-    const types = {
-        'ABOUTME-DATA-ADD': () => {
-            return { ...state, ...data }
-        },
-        'ABOUTME-UPDATE-AVATAR': () => {
-            return { ...state, avatar: { ...data } }
-        },
-        'UPDATE-MY-FOLLOWING': () => {
-            return { ...state, following: [...data] }
-        },
-        'UPSERT-COLLECTION': () => ({
-            ...state, collections: data
-        }),
-        'REMOVE-MYDATA': () => ({})
-    }
-    if (type in types) {
-        return types[type]()
-    }
-    return state
-}

+ 0 - 96
src/redux/reducers/post-reducer.js

@@ -1,96 +0,0 @@
-export const postReducer = (state = {}, { type, findId, newResult, userData = {}, count = null }) => {
-
-    const { posts } = state
-
-    const upsertSubComments = (commentList, id, nR, find) => {
-        return commentList.map(c => {
-            if (c._id === id) {
-                return { ...c, [find]:  nR }
-            } else if (c?.answers?.length) {
-                return {
-                    ...c,
-                    answers: upsertSubComments(c.answers, id, nR, find)
-                }
-            } else {
-                return { ...c }
-            }
-        })
-    }
-
-    const types = {
-
-        'ADD-POSTS': () => ({
-            ...state,
-            posts: Array.isArray(newResult)
-                ? [...posts, ...newResult]
-                : { ...posts, ...newResult },
-            count
-        }),
-
-        'ADD-PROFILE-DATA': () => ({
-            ...state,
-            posts: !!posts ? [...posts, ...newResult] : [...newResult],
-            userData,
-            count
-        }),
-
-        'REMOVE-POSTS': () => ({
-            ...state,
-            posts: [],
-            userData: {},
-            count: 0,
-            subComments: {},
-        }),
-
-        'ADD-POST-LIKE': () => ({
-            ...state,
-            posts: Array.isArray(posts)
-                ? posts.map(p => p._id === findId ? p = { ...p, likes: [...newResult] } : p)
-                : { ...state.posts, likes: [...newResult] },
-        }),
-
-        'REMOVE-POST-LIKE': () => ({
-            ...state,
-            posts: Array.isArray(posts)
-                ? posts.map(p => p._id === findId ? p = { ...p, likes: [...newResult] } : p)
-                : { ...state.posts, likes: [...newResult] },
-        }),
-
-        'ADD-COMMENT': () => ({
-            ...state,
-            posts: Array.isArray(posts)
-                ? posts.map(p => p._id === findId ? p = { ...p, comments: [...newResult] } : p)
-                : { ...state.posts, comments: [...newResult] }
-        }),
-
-        'UPDATE-SUBCOMMENT': () => ({
-            ...state, posts: { ...state.posts, comments: upsertSubComments(posts.comments, findId, newResult, 'answers') }
-        }),
-
-        'EDIT-COMMENT': () => ({
-            ...state, posts: { ...state.posts, comments: upsertSubComments(posts.comments, findId, newResult.text, 'text') }
-        }),
-
-        'UPSERT-LIKE-COMMENT': () => ({
-            ...state, posts: {
-                ...state.posts, comments: upsertSubComments(posts.comments, findId, newResult, 'likes')
-            }
-        }),
-
-        'UPDATE-FOLLOWERS': () => ({
-            ...state,
-            userData: { ...state.userData, followers: [...newResult] }
-        }),
-    }
-    
-    if (type in types) {
-        return types[type]()
-    }
-
-    return state
-}
-
-
-
-
-

+ 53 - 0
src/redux/reducers/postOne-reducer.js

@@ -0,0 +1,53 @@
+export const postOneReducer = (state = {}, { type, commentId, newResult, userData = {}, count = null }) => {
+
+    const changeComments = (commentList, id, nR, find) =>
+        commentList.map(c => {
+            if (c._id === id) {
+                return { ...c, [find]: nR }
+            } else if (c?.answers?.length) {
+                return {
+                    ...c,
+                    answers: changeComments(c.answers, id, nR, find)
+                }
+            } else {
+                return { ...c }
+            }
+        })
+
+
+    const types = {
+
+        'POST-ONE-DATA': () => ({ ...newResult }),
+
+        'CLEAR-POST-ONE': () => ({}),
+
+        'POST-ONE-LIKE': () => ({ ...state, likes: [...newResult] }),
+
+        'POST-ONE-ADD-COMMENT': () => ({ ...state, comments: [...newResult] }),
+
+        'UPDATE-COMMENT': () => ({
+            ...state,
+            comments: changeComments(state.comments, commentId, newResult, 'answers')
+        }),
+
+        'EDIT-COMMENT': () => ({
+            ...state,
+            comments: changeComments(state.comments, commentId, newResult.text, 'text')
+        }),
+
+        'LIKE-COMMENT': () => ({
+            ...state, comments: changeComments(state.comments, commentId, newResult, 'likes')
+        }),
+    }
+
+    if (type in types) {
+        return types[type]()
+    }
+
+    return state
+}
+
+
+
+
+

+ 40 - 0
src/redux/reducers/postsTape-reducer.js

@@ -0,0 +1,40 @@
+export const postsTapeReducer = (state = {}, { type, newResult, count, postId }) => {
+
+    const { posts } = state
+
+    const types = {
+
+        'POSTS-TAPE': () => ({
+            ...state,
+            posts: [...posts || [], ...newResult],
+            count: count ? count : state.count
+        }),
+
+        'CLEAR-POSTS-TAPE': () => ({
+            ...state,
+            posts: [],
+            count: 0,
+        }),
+
+        'POSTS-TAPE-LIKE': () => ({
+            ...state,
+            posts: posts.map(p => p._id === postId ? p = { ...p, likes: [...newResult] } : p)
+        }),
+
+        'ADD-COMMENT-POST-TAPE': () => ({
+            ...state,
+            posts: posts.map(p => p._id === postId ? p = { ...p, comments: [...newResult] } : p)
+        }),
+    }
+
+    if (type in types) {
+        return types[type]()
+    }
+
+    return state
+}
+
+
+
+
+

+ 14 - 0
src/redux/reducers/profileData-reducer.js

@@ -0,0 +1,14 @@
+
+export const profileDataReducer = (state = {}, { type, data }) => {
+    const types = {
+        'PROFILE-DATA': () => ({ ...state, ...data }),
+
+        'UPDATE-USER-FOLLOWERS': () => ({ ...state, followers: [...data] }),
+
+        'CLEAR-PROFILE-DATA': () => ({})
+    }
+    if (type in types) {
+        return types[type]()
+    }
+    return state
+}

+ 0 - 5
src/redux/reducers/route-reducer.js

@@ -1,5 +0,0 @@
-export const routeReducer = (state = {}, { type, match }) => {
-    if (type === 'ROUTE')
-        return match
-    return state
-}

+ 13 - 9
src/redux/redux-store.js

@@ -1,26 +1,30 @@
 import { createStore, combineReducers, applyMiddleware } from 'redux';
 import { createStore, combineReducers, applyMiddleware } from 'redux';
 import { authReducer } from './reducers/auth-reducer';
 import { authReducer } from './reducers/auth-reducer';
-import { myProfileReducer } from './reducers/myProfile-reducer';
-import { postReducer } from './reducers/post-reducer';
-import { promiseReducer } from './reducers/promise-reducer';
+// import { postReducer } from './reducers/post-reducer';
 import createSagaMiddleware from 'redux-saga'
 import createSagaMiddleware from 'redux-saga'
+import { promiseReducer } from './reducers/promise-reducer';
 import { rootSaga } from './saga';
 import { rootSaga } from './saga';
-import { actionFullAboutMe } from '../actions'
-import { routeReducer } from './reducers/route-reducer';
+import { actionAboutMeSagaAC } from '../actions/actonsCreators';
+import { aboutMeReducer } from './reducers/aboutMe-reducer';
+import { postsTapeReducer } from './reducers/postsTape-reducer';
+import { profileDataReducer } from './reducers/profileData-reducer';
+import { postOneReducer } from './reducers/postOne-reducer';
+
 
 
 const sagaMiddleware = createSagaMiddleware()
 const sagaMiddleware = createSagaMiddleware()
 
 
 const store = createStore(combineReducers({
 const store = createStore(combineReducers({
     auth: authReducer,
     auth: authReducer,
     promise: promiseReducer,
     promise: promiseReducer,
-    myData: myProfileReducer,
-    post: postReducer,
-    route: routeReducer,
+    aboutMe: aboutMeReducer,
+    postsTape: postsTapeReducer,
+    postOne: postOneReducer,
+    dataProfile: profileDataReducer,
 }),
 }),
     applyMiddleware(sagaMiddleware))
     applyMiddleware(sagaMiddleware))
 
 
 sagaMiddleware.run(rootSaga)
 sagaMiddleware.run(rootSaga)
 
 
-store.dispatch(actionFullAboutMe())
+store.dispatch(actionAboutMeSagaAC())
 
 
 export default store;
 export default store;

File diff suppressed because it is too large
+ 143 - 158
src/redux/saga/index.js