Browse Source

Add in modal window list of followers and following (link to profiles) + profileUserReducer

LenDoc 2 years ago
parent
commit
906023d3aa

+ 28 - 43
src/App.js

@@ -3,7 +3,7 @@ import { Provider, connect } from 'react-redux'
 import { Router, Route, Link, Redirect, Switch } from 'react-router-dom'
 import createHistory from 'history/createBrowserHistory'
 import React, { useMemo, useState, useEffect } from 'react'
-import { store } from './reducers'
+import { actionAboutUser, actionFullProfilePageUser, store } from './reducers'
 import { Basic } from './components/DropZone'
 import { CPageAboutUser, PageAboutUser } from './components/User'
 import { PageCreatePost, AddPost } from './components/NewPost'
@@ -32,14 +32,10 @@ import { UploadOutlined, SearchOutlined } from '@ant-design/icons'
 import ImgCrop from 'antd-img-crop'
 import { Avatar, Image, Divider, Radio } from 'antd'
 import { UserOutlined } from '@ant-design/icons'
-import user from './materials/user.png'
+import user from './materials/user1.png'
 import photoNotFound from './materials/photoNotFound.png'
 // import "react-responsive-carousel/lib/styles/carousel.min.css"; // requires a loader
 // import { Carousel } from 'react-responsive-carousel';
-import { Carousel, Popover } from 'antd'
-import { LeftCircleFilled, RightCircleFilled } from '@ant-design/icons'
-import { Input, Select } from 'antd'
-import { PagePost } from './components/Post'
 import { CPostForFeed,Feed } from './components/PostFeed'
 import { CSearch } from './components/Search_Users'
 
@@ -80,37 +76,12 @@ const Main = () => (
       <Route path="/post/:_id" component={CPost} />
       <Route path="/feed" component={CPostForFeed} />
       <Route path="/editProfile" component={CUserEdit} />
-      <Route path="/followers" component={CUserFollowers} />
 
       {/* <CBasic /> */}
     </Switch>
   </main>
 )
-const UserFollowers = ({ followers }) => {
-  console.log('followers ', followers)
-  return (
-    <div>
-      {/* {console.log('start')} */}
-      {(followers || [])?.map(({ _id, login, avatar }) => (
-        <Link to={`/profile/${_id}`}>
-          {console.log('doing something')}
-          <Avatar
-            style={{
-              width: '60px',
-              height: '60px',
-              marginRight: '30px',
-              position: 'absolute',
-            }}
-            src={'/' + avatar?.url || user}
-          />
-          {console.log('followers', login)}
 
-          <h1 style={{ marginLeft: '30px' }}> {login}</h1>
-        </Link>
-      ))}
-    </div>
-  )
-}
 
 {
   /* { console.log('end') } */
@@ -120,17 +91,13 @@ const UserFollowers = ({ followers }) => {
 //   <ResultUserFind userFind={followers} />
 //   {console.log('followers', followers)}
 // </div>
-const CUserFollowers = connect((state) => ({
-  followers: state.promise.aboutMe?.payload?.followers,
-}))(UserFollowers)
-
 
 
 const CUserEdit = connect((state) => ({}), {})(PageAboutUser)
 
 const Header = () => {
   const CFeed = connect((state) => ({
-    aboutMe: state.promise?.aboutMe?.payload,
+    aboutMe: state?.profileData?.aboutMe,
   }))(Feed)
   return (
     <section className="Header">
@@ -161,13 +128,29 @@ const Recommendations = () => (
 
 const CBasic = connect(null, { onLoad: actionSetAvatar })(Basic)
 // const CAddPost =connect(null,{actionPostUpsert})
-const User = ({ aboutMe: { _id, login, avatar } = {} }) => (
-  <Link className="User" to={`/profile/${_id}`}>
-    <Avatar src={'/' + avatar?.url || user} />
-  </Link>
-)
+const User = ({my_Id, aboutMe: { _id, login, avatar } = {}, onMyPage }) => {
+  return (
+    
+    <Link onClick={()=> onMyPage(_id)} className="User" to={`/profile/${_id}`}>
+      {
+        avatar?.url ? <Avatar src={'/' + avatar?.url} />
+          :
+          <Avatar src={user} />
+   }
+     
+      </Link>
+      
+
+  )
+}
 // backendURL
-const CUser = connect((state) => ({ aboutMe: state.promise.aboutMe?.payload }))(
+const CUser = connect((state) => ({
+  my_Id: state.auth.payload.sub.id || '',
+  aboutMe: state.profileData.aboutMe,
+
+}),
+  { onMyPage:actionFullProfilePageUser }
+)(
   User,
 )
 
@@ -208,7 +191,9 @@ function App() {
     // store.dispatch(actionAboutMe(store.getState().auth?.payload?.sub?.id))
     // store.dispatch(actionAllPosts(store.getState().auth?.payload?.sub?.id))
     store.dispatch(actionFullProfilePage(store.getState().auth?.payload?.sub?.id))
-   // actionFullProfilePageData
+    store.dispatch(actionFullProfilePageUser(store.getState().auth?.payload?.sub?.id))
+    
+    // actionFullProfilePageData
     // aboutMeWorker()
   }
   else {

+ 18 - 0
src/App.scss

@@ -175,4 +175,22 @@ main{
 .SpoilerButton{
   right: 30px;
   margin:20px;
+}
+Link{
+  display: flex;
+  align-items: center;
+   justify-content: center;
+   text-decoration: none;
+   font-family: serif;
+   background-color: rgb(174, 172, 240);  
+   border: 2px solid rgb(37, 140, 184);
+   border-radius: 10px;
+   margin: 10px ;
+   padding: 10px;
+   font-weight: bold;
+   color: rgb(10, 9, 58);
+}
+Link:hover{
+  text-decoration: underline; 
+  background-color: rgb(123, 119, 228);  
 }

+ 19 - 1
src/actions/index.js

@@ -182,7 +182,7 @@ mutation PostUpsert($post:PostInput){
 
 export const actionAllPosts = (userId) =>
     actionPromise(
-      'allPosts',
+      'allPostsMe',
       gql(
         `query allPosts($userId:String!){
   PostFind(query:$userId){
@@ -618,6 +618,24 @@ export const actionUserUpsert = (user) => async (dispatch, getState) => {
       )
   );
 };
+export const actionSubscribe = (_id) =>
+  actionPromise(
+    "subscribeTo", gql(
+      `mutation subscribe($_id:String!) {
+        UserUpsert(user: {following:{_id:$_id }}
+        ) {
+          _id following{_id login}
+          followers{
+            _id login
+          }
+        }
+      }
+      `,
+      {
+        _id: _id,
+      }
+    )
+  )
 
 export const actionUserUpdate =
     (user = {}) =>

+ 12 - 22
src/components/Post.js

@@ -13,7 +13,7 @@ import { Divider, Input, Button, Modal } from 'antd';
 import { EditOutlined } from '@ant-design/icons'
 import moment from 'moment';
 import {CComments, AddComment} from '../components/Post_Comment'
-
+import { ConstructorModal} from '../helpers'
 import React, { useMemo, useState, useEffect } from 'react'
 // const postId="625afa1d069dca48a822ffb0"
 export const Card = ({ post, onPost }) => (
@@ -159,7 +159,7 @@ const Likes = ({ likes }) =>
                   />
                 </Col>
                 <Col offset={2}>
-                    <h3 > {login}</h3>
+                    <h3 > {login || 'Anon'}</h3>
                  </Col>
                  </Row>
                 </Link>
@@ -171,23 +171,15 @@ const Likes = ({ likes }) =>
   }
 const Like = ({ my_Id, postId, addLike, deleteLike, likes=[], children }) =>
 {
-  
+
+  const likeId = likes.find(like => like?.owner?._id === my_Id)?._id
+  const changeLike = () => likeId ? deleteLike(likeId, postId) : addLike(postId)
+  // console.log('likeId', likeId)
   const [isModalVisible, setIsModalVisible] = useState(false);
 
   const showModal = () => {
     setIsModalVisible(true);
   };
-
-  const handleOk = () => {
-    setIsModalVisible(false);
-  };
-
-  const handleCancel = () => {
-    setIsModalVisible(false);
-  };
-  const likeId = likes.find(like => like?.owner?._id === my_Id)?._id
-  const changeLike = () => likeId ? deleteLike(likeId, postId) : addLike(postId)
-  // console.log('likeId', likeId)
   return(
     <>
       <div style={{display:'flex'}}>
@@ -203,17 +195,15 @@ const Like = ({ my_Id, postId, addLike, deleteLike, likes=[], children }) =>
         :
         '0 likes'}
       </div>
-      <Modal title="Likes" className="Modal"
-        footer={null}
-        onCancel={handleCancel}
-        visible={isModalVisible}>
+      <ConstructorModal isModalVisible={isModalVisible} setIsModalVisible={setIsModalVisible}>
           <Likes likes={likes}/>
-      </Modal>
+      </ConstructorModal>
     </>
   )
 }
 
-export const PagePost = ({my_Id, onePost,likes, addComment,addCommentReply, addLike, findSubComment, deleteLike, aboutMe: { avatar, login } = {}, onPost }) => {
+export const PagePost = ({ my_Id, onePost, likes, addComment,
+  addCommentReply, addLike, findSubComment, deleteLike, aboutUser: { _id, avatar, login } = {}, onPost }) => {
 
  console.log('onePost ', onePost)
   return (
@@ -221,7 +211,7 @@ export const PagePost = ({my_Id, onePost,likes, addComment,addCommentReply, addL
      <Row>
       <Col span={14}>
 {/* <div  style={{display: 'flex'}}> */}
-    
+
       <MyCarousel style={{position: 'absolute'}} images={onePost?.images} />
       <h3 style={{ textAlign: 'center', padding:'30px'}}>
             Created Post: {new Intl.DateTimeFormat('en-GB').format(onePost?.createdAt)}
@@ -275,7 +265,7 @@ export const PagePost = ({my_Id, onePost,likes, addComment,addCommentReply, addL
 export const CPost = connect((state) => ({
   onePost: state.promise.onePost?.payload,
   my_Id: state.auth.payload.sub.id || '',
-  aboutMe: state.profileData?.aboutMe,
+  aboutUser: state.profilePage?.aboutUser,
   addComment: state.promise?.addComment?.payload,
   addSubComment: state.promise?.addSubComment,
   

+ 49 - 28
src/components/Search_Users.js

@@ -1,8 +1,9 @@
 import { Link } from 'react-router-dom'
 import { connect } from 'react-redux'
-import { Avatar, Input } from 'antd'
+import { Row, Col } from 'antd';
+import { Avatar, Input  } from 'antd'
 import { Carousel, Popover } from 'antd'
-import user from '../materials/user.png'
+import user from '../materials/user1.png'
 
 import {
     actionAboutMe,
@@ -12,36 +13,55 @@ import {
     actionPostsFeed,
     actionAllFollowing,
     actionAllFollowers,
-    actionPostsMyFollowing2,
+  actionPostsMyFollowing2,
+
   actionSearchUser,
  
 } from '../actions'
-  import {actionFullProfilePage} from '../reducers'
-export const ResultUserFind = ({ my_Id, userFind = [], onPageData }) => {
-  
-  const checkMyId = userFind.find(user => user?._id === my_Id)
-
-  checkMyId ? (console.log('да єто мой айди ти чо')) : console.log('ЦЕ НЕ МИЙ АЙДИ')
+  import {actionFullProfilePageUser, actionFullProfilePage} from '../reducers'
+export const ResultUserFind = ({ my_Id, userFind = [], onPageData, size }) => {
   
+  //const checkMyId = userFind.find(user => user?._id === my_Id)
    return(<div>
      {
+
        userFind?.map(({ _id, login, avatar }) => (
-        
         <Link onClick={()=>onPageData(_id)} to={`/profile/${_id}`}>
+       
+              <Row>
+             <Col offset={1}>
+            {avatar?.url ?  <Avatar
+              style={{
+                width: '50px',
+                height: '50px',
+                marginBottom:'10px'
+                 }}
+                //  ('/' + avatar?.url) ||
+              src={ '/' + avatar?.url}
+               />
+                 :
+                 
+                 <Avatar
+                 style={{
+                   width: '50px',
+                   height: '50px',
+                   marginBottom:'10px'
+                    }}
+                   //  ('/' + avatar?.url) ||
+                 src={user}
+                  />
+              }
+           
+              
+                </Col>
+             <Col offset={1}>
+                 <h3 style={{ marginBottom:'20px'}}> {login || 'Anon'}</h3>
+      
+                 </Col>
+                 </Row>
+                </Link>
           
-          {console.log('Login: ', login, '  _id: ', _id)}
-          <Avatar
-            style={{
-              width: '20px',
-              height: '20px',
-              marginRight: '30px',
-              position: 'absolute',
-            }}
-            src={'/' + avatar?.url || user}
-          />
-  
-          <h3 style={{ marginLeft: '30px' }}> {login}</h3>
-        </Link>
+      
       ))}
 </div>)
 }
@@ -53,7 +73,8 @@ export const ResultUserFind = ({ my_Id, userFind = [], onPageData }) => {
       <>
         <Popover
           placement="bottom"
-          content={<ResultUserFind my_Id={my_Id} onPageData={onPageData} userFind={searchUser} />}
+          content={<ResultUserFind my_Id={my_Id} size={'20px'} onPageData={onPageData}
+            userFind={searchUser} />}
           trigger="click"
         >
           <Search
@@ -69,13 +90,13 @@ export const ResultUserFind = ({ my_Id, userFind = [], onPageData }) => {
   }
  export const CSearch = connect(
    (state) => ({
-    aboutMe: state.profileData?.aboutMe,
-     searchUser: state.promise?.searchUser?.payload,
-     my_Id: state.auth.payload.sub.id || '',
+    aboutUser: state.profilePage?.aboutUser,
+    searchUser: state.promise?.searchUser?.payload,
+    my_Id: state.auth.payload.sub.id || '',
    }),
 
    {
      onSearch: actionSearchUser,
-     onPageData:actionFullProfilePage
+     onPageData: actionFullProfilePageUser,
    },
   )(SearchUser)

+ 86 - 24
src/components/User.js

@@ -1,15 +1,17 @@
 import {
   actionAllPosts, actionOnePost, actionAboutMe, actionUploadFile, actionUserUpsert,
   actionSetAvatar, actionAvatar} from '../actions'
-import user from '../materials/user.png'
+import user from '../materials/user1.png'
 import React, { useMemo, useState, useEffect } from 'react'
 import { Card } from '../components/Post'
 // import {Basic} from '../components/DropZone'
 import { Router, Route, Link, Redirect, Switch } from 'react-router-dom'
+import { ResultUserFind } from '../components/Search_Users'
+import { ConstructorModal} from '../helpers'
 
 import { Provider, connect } from 'react-redux'
 import { Avatar, Image, Divider, Radio } from 'antd'
-import { store } from '../reducers'
+import { actionAboutUser, store,actionAllPostsUser,actionFullProfilePageUser } from '../reducers'
 import { useDropzone } from 'react-dropzone'
 import { Upload, Button, DatePicker, Space } from 'antd'
 import { UploadOutlined, SearchOutlined } from '@ant-design/icons'
@@ -109,14 +111,19 @@ export const CEditInfo = connect(
     onFileDrop: actionUploadFile,
   },
 )(EditInfo)
+
+
 export const PageAboutUser = ({
   my_Id,
-  aboutMe: { _id, login, nick, createdAt, avatar, followers, following } = {},
+  aboutUser: { _id, login, nick, createdAt, avatar, followers, following } = {},
   allPosts,
   onPosts,
   onPost,
   onePost,
   onAboutUser,
+  aboutUserFollowers={},
+  onPageData,
+  aboutUserFollowing={},
   post = {},
 }) => {
   useEffect(() => {
@@ -124,20 +131,42 @@ export const PageAboutUser = ({
     // onePost(post?._id)
     // "62361ebb92c08631bc4b0e96")
   }, [])
-  const checkMyId = (_id === my_Id)
+  const checkMyId =(_id === my_Id)
+
+  const [isModalVisibleFollowing, setIsModalVisibleFollowing] = useState(false);
+
+  const showModalFollowing = () => {
+    setIsModalVisibleFollowing(true);
+  };
+  const [isModalVisibleFollowers, setIsModalVisibleFollowers] = useState(false);
+
+  const showModalFollowers = () => {
+    setIsModalVisibleFollowers(true);
+  };
 
   return (
   
     <>
       <Row>
       <Col span={12} offset={6}>
-    <section className="AboutMe">
-      <Avatar
-        style={{ marginRight: '20px', width: '150px', height: '150px' }}
-        src={'/' + avatar?.url || user}
-      />
-      <div className="Info">
-        <h1> {login}</h1>
+          <section className="AboutMe">
+            {avatar?.url ?
+              <Avatar
+                style={{ marginRight: '20px', width: '150px', height: '150px' }}
+                src={'/' + avatar?.url} />
+              :
+              <Avatar
+                style={{ marginRight: '20px', width: '150px', height: '150px' }}
+                src={user} />
+            }
+            <div className="Info">
+              {login ?
+
+                <h1> {login}</h1>
+                :
+                <h1> {'Anon'}</h1>
+              }
+
         <h3>
           Created Account: {new Intl.DateTimeFormat('en-GB').format(createdAt)}
         </h3>
@@ -151,17 +180,26 @@ export const PageAboutUser = ({
           )}
 
           {followers?.length > 0 ? (
-            <Link to={`/followers`}>
-              {' '}
-              <h3 style={{ marginLeft: '20px' }}>
+         
+              
+                  <h3 style={{ cursor: 'pointer', marginLeft: '20px' }}
+                    onClick={showModalFollowers}>
                 {followers.length} followers{' '}
-              </h3>
-            </Link>
+                  </h3>
+          
           ) : (
             <h3 style={{ marginLeft: '20px' }}> 0 followers </h3>
-          )}
-
-          <h3 style={{ marginLeft: '20px' }}>{following?.length} following </h3>
+                )}
+                
+                {following?.length > 0 ? (
+                  <h3 style={{ cursor: 'pointer', marginLeft: '20px' }}
+                    onClick={showModalFollowing}>{following?.length} {' '}
+                    following </h3>)
+                  :
+                (<h3 style={{ marginLeft: '20px' }}> 0 following </h3>
+                )
+                }
+             
         </div>
               <h3> nick: {nick == null ? login : nick}</h3>
               {
@@ -173,9 +211,28 @@ export const PageAboutUser = ({
             <CEditInfo />
           </div>
                 </EditAccount>
-                : null
+                : <button> subscribe</button>
                   
               }
+              {/* <ConstructorModal>
+        <ResultUserFind my_Id={my_Id} size={'40px'} onPageData={onPageData}
+            userFind={aboutUserFollowing} />
+      </ConstructorModal> */}
+
+
+              <ConstructorModal isModalVisible={isModalVisibleFollowing}
+                setIsModalVisible={setIsModalVisibleFollowing}>
+         <ResultUserFind size={'40px'} onPageData={onPageData}
+                  userFind={aboutUserFollowing} />
+                
+              </ConstructorModal>
+              <ConstructorModal isModalVisible={isModalVisibleFollowers}
+                setIsModalVisible={setIsModalVisibleFollowers}>
+         <ResultUserFind size={'40px'} onPageData={onPageData}
+                  userFind={aboutUserFollowers} />
+                
+      </ConstructorModal>
+              
        </div>
         </section>
             
@@ -201,19 +258,24 @@ export const PageAboutUser = ({
      
   )
 }
+
 export const CPageAboutUser = connect(
   (state) => ({
     my_Id: state.auth.payload.sub.id || '',
-    aboutMe: state.profileData?.aboutMe,
-    allPosts: state.profileData?.allPosts,
+    aboutUser: state.profilePage?.aboutUser,
+    aboutUserFollowers: state.profilePage?.aboutUser?.followers,
+    aboutUserFollowing: state.profilePage?.aboutUser?.following,
+
+
+    allPosts: state.profilePage?.allPosts,
     onePost: state.promise?.onePost?.payload,
     // post:state.promise?.onePost?.payload,
     // allPosts: state.promise?.allPosts?.payload,
   }),
   {
-    onPosts: actionAllPosts,
-    onAboutUser: actionAboutMe,
+    onAboutUser: actionFullProfilePageUser,
     onLoad: actionUploadFile,
     onPost: actionOnePost,
+    onPageData: actionFullProfilePageUser,
   },
 )(PageAboutUser)

+ 27 - 0
src/helpers/index.js

@@ -0,0 +1,27 @@
+import { Modal } from 'antd';
+// import React, { useState } from 'react'
+
+export const ConstructorModal = ({ children, isModalVisible, setIsModalVisible }) =>
+{
+ // const [isModalVisible, setIsModalVisible] = useState(false);
+
+  const showModal = () => {
+    setIsModalVisible(true);
+  };
+
+  const handleCancel = () => {
+    setIsModalVisible(false);
+  };
+  return (
+    <>
+        <Modal title="Likes" className="Modal"
+        footer={null}
+        onCancel={handleCancel}
+        visible={isModalVisible}>
+
+        {isModalVisible && children}
+        </Modal>
+    </>
+  )
+}
+  

BIN
src/materials/user1.png


BIN
src/materials/user2.png


+ 81 - 10
src/reducers/index.js

@@ -20,24 +20,93 @@ const jwtDecode = (token) => {
     }
 }
 
-export const actionProfilePageDataType= (aboutMe, allPosts) =>
-  ({ type: 'PROFILE-PAGE', aboutMe, allPosts })
+export const actionProfilePageDataTypeUser= (aboutUser, allPosts) =>
+  ({ type: 'PROFILE-PAGE-USER', aboutUser, allPosts })
 
+  export const actionProfilePageDataType= (aboutMe) =>
+  ({ type: 'PROFILE-PAGE', aboutMe })
 
-export const actionFullProfilePage = (_id) =>
+  export const actionAboutUser = (_id) =>
+  actionPromise(
+  'aboutUser',
+    gql(
+      `query AboutMe($userId:String){
+        UserFindOne(query:$userId)
+        {
+          _id createdAt login nick avatar{_id url} 
+          followers{_id login nick avatar{_id url}} 
+          following{_id login nick avatar{_id url}}
+        }
+      }`,
+      {
+        userId: JSON.stringify([{ _id }]),
+      },
+    ),
+  )
+
+  export const actionAllPostsUser = (userId) =>
+  actionPromise(
+    'allPosts',
+    gql(
+      `query allPosts($userId:String!){
+PostFind(query:$userId){
+         owner{_id} _id title text images{_id url}
+  }
+}`,
+      {
+        userId: JSON.stringify([
+          { ___owner: userId},
+
+          {
+            sort: [{ _id: -1 }],
+            skip: [0],
+            limit: [36]
+          },
+
+        ]),
+      },
+    ),
+  )
+
+export const actionFullProfilePageUser = (_id) =>
+  async dispatch => {
+    const aboutUser = await dispatch(actionAboutUser(_id))
+    const allPosts = await dispatch(actionAllPostsUser(_id))
+    if (aboutUser && allPosts) {
+      await dispatch(actionProfilePageDataTypeUser(aboutUser, allPosts))
+    }
+  }
+  export const actionFullProfilePage = (_id) =>
   async dispatch => {
-    const aboutMe = await dispatch(actionAboutMe(_id))
-    const allPosts = await dispatch(actionAllPosts(_id))
-    if (aboutMe && allPosts) {
-      await dispatch(actionProfilePageDataType(aboutMe, allPosts))
+    const aboutMe= await dispatch(actionAboutMe(_id))
+    // const allPostsMe = await dispatch(actionAllPosts(_id))
+    if (aboutMe) {
+      await dispatch(actionProfilePageDataType(aboutMe))
     }
   }
 
-export const profileReducer = (state = {}, { type, aboutMe,allPosts, newResult }) => {
+export const profileUserReducer = (state = {}, { type, aboutUser, allPosts,
+  newResult }) => {
+    const types = {
+        'PROFILE-PAGE-USER': () => {
+            return {
+                ...state, aboutUser, allPosts
+            }
+        }
+  
+    }
+    if (type in types) {
+        return types[type]()
+    }
+    return state
+  }
+  
+
+export const profileReducer = (state = {}, { type, aboutMe, newResult }) => {
   const types = {
       'PROFILE-PAGE': () => {
           return {
-              ...state, aboutMe, allPosts
+              ...state, aboutMe
           }
       }
 
@@ -69,7 +138,9 @@ export const profileReducer = (state = {}, { type, aboutMe,allPosts, newResult }
     combineReducers({
       promise: promiseReducer,
       auth: authReducer,
-      profileData:profileReducer
+      profileData: profileReducer,
+      profilePage:profileUserReducer
+      
     }),
     applyMiddleware(thunk),
 )