LenDoc 2 years ago
parent
commit
e0d88da51a

+ 17 - 19
package-lock.json

@@ -13,7 +13,7 @@
         "@testing-library/react": "^12.1.2",
         "@testing-library/user-event": "^13.5.0",
         "antd": "^4.18.6",
-        "antd-img-crop": "^4.1.0",
+        "antd-img-crop": "^4.2.3",
         "array-move": "^4.0.0",
         "cors": "^2.8.5",
         "emoji-mart": "^3.0.1",
@@ -4409,12 +4409,11 @@
       }
     },
     "node_modules/antd-img-crop": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/antd-img-crop/-/antd-img-crop-4.1.0.tgz",
-      "integrity": "sha512-41wH5kvn00fdWF1doN0MAXpTWjawUWbiOyDVuQGM8NIffs6YQ2ihgoVhaBMnbs9VCswrCAAHdo3nYL8B8Rg0tA==",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/antd-img-crop/-/antd-img-crop-4.2.3.tgz",
+      "integrity": "sha512-YZgsUdfHnkBCOQ1sLXTwfVRgBdMRM//joddFnSlWe/QU52m8PPbBxtgt0YdEf+UTPXOAx6RQJp1gUjAmMU2knA==",
       "dependencies": {
-        "@babel/runtime": "^7.16.7",
-        "react-easy-crop": "^4.0.1"
+        "react-easy-crop": "^4.1.5"
       },
       "peerDependencies": {
         "antd": ">=4.0.0",
@@ -11494,7 +11493,7 @@
     "node_modules/normalize-wheel": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
-      "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
+      "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA=="
     },
     "node_modules/npm-run-path": {
       "version": "4.0.1",
@@ -14081,9 +14080,9 @@
       }
     },
     "node_modules/react-easy-crop": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-4.0.1.tgz",
-      "integrity": "sha512-cREis2557y/ZkvgiNaLlFrzjduUSUvEYYxbglwggpo2gnxCjBQZeRgAPoedvXX0e0BgyGAI0zD3motVucJGhzA==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-4.2.0.tgz",
+      "integrity": "sha512-NJdeG6JPlOvXPNcQlmyEyjuseTiZVDa0M5X6BwTxSPR30MG3ROsSHKeGl5SQdI3TfmsoEgvl7MbM+AjFGj+faw==",
       "dependencies": {
         "normalize-wheel": "^1.0.1",
         "tslib": "2.0.1"
@@ -20355,12 +20354,11 @@
       }
     },
     "antd-img-crop": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/antd-img-crop/-/antd-img-crop-4.1.0.tgz",
-      "integrity": "sha512-41wH5kvn00fdWF1doN0MAXpTWjawUWbiOyDVuQGM8NIffs6YQ2ihgoVhaBMnbs9VCswrCAAHdo3nYL8B8Rg0tA==",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/antd-img-crop/-/antd-img-crop-4.2.3.tgz",
+      "integrity": "sha512-YZgsUdfHnkBCOQ1sLXTwfVRgBdMRM//joddFnSlWe/QU52m8PPbBxtgt0YdEf+UTPXOAx6RQJp1gUjAmMU2knA==",
       "requires": {
-        "@babel/runtime": "^7.16.7",
-        "react-easy-crop": "^4.0.1"
+        "react-easy-crop": "^4.1.5"
       }
     },
     "anymatch": {
@@ -25525,7 +25523,7 @@
     "normalize-wheel": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
-      "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
+      "integrity": "sha512-1OnlAPZ3zgrk8B91HyRj+eVv+kS5u+Z0SCsak6Xil/kmgEia50ga7zfkumayonZrImffAxPU/5WcyGhzetHNPA=="
     },
     "npm-run-path": {
       "version": "4.0.1",
@@ -27249,9 +27247,9 @@
       }
     },
     "react-easy-crop": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-4.0.1.tgz",
-      "integrity": "sha512-cREis2557y/ZkvgiNaLlFrzjduUSUvEYYxbglwggpo2gnxCjBQZeRgAPoedvXX0e0BgyGAI0zD3motVucJGhzA==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-4.2.0.tgz",
+      "integrity": "sha512-NJdeG6JPlOvXPNcQlmyEyjuseTiZVDa0M5X6BwTxSPR30MG3ROsSHKeGl5SQdI3TfmsoEgvl7MbM+AjFGj+faw==",
       "requires": {
         "normalize-wheel": "^1.0.1",
         "tslib": "2.0.1"

+ 2 - 2
package.json

@@ -2,14 +2,14 @@
   "name": "hipstagram",
   "version": "0.1.0",
   "private": true,
-  "proxy": "http://hipstagram.node.ed.asmer.org.ua",
+  "proxy": "http://localhost:5000",
   "dependencies": {
     "@ant-design/icons": "^4.7.0",
     "@testing-library/jest-dom": "^5.16.2",
     "@testing-library/react": "^12.1.2",
     "@testing-library/user-event": "^13.5.0",
     "antd": "^4.18.6",
-    "antd-img-crop": "^4.1.0",
+    "antd-img-crop": "^4.2.3",
     "array-move": "^4.0.0",
     "cors": "^2.8.5",
     "emoji-mart": "^3.0.1",

+ 8 - 4
src/App.js

@@ -36,8 +36,11 @@ const Main = () => (
     <Switch>
       <Route path="/" exact component={PageMain} />
       <Route path="/profile/:_id" component={CPageAboutUser} />
-      <Route path="/edit/post" component={PageCreatePost} />
+      <Route path="/edit/post/:_id" component={PageCreatePost} />
+      <Route path="/edit/post/new" component={PageCreatePost} />
+
       <Route path="/post/:_id" component={CPost} />
+
       <Route path="/feed" component={CPostForFeed} />
       <Route path="/editProfile" component={CUserEdit} />
     </Switch>
@@ -76,7 +79,7 @@ const CProtectedRoute = connect((state) => ({
   auth: state.auth?.payload?.sub.acl,
 }))(ProtectedRoute)
 
-const history = createHistory()
+export const history = createHistory()
 
 function App() {
   if (store.getState().auth?.token) {
@@ -91,6 +94,8 @@ function App() {
 else {
     console.log("Скролла нет");
 }
+
+
   return (
     <Router history={history}>
       <Provider store={store}>
@@ -109,5 +114,4 @@ else {
     </Router>
   )
 }
-
-export default App
+export default App

+ 11 - 8
src/App.scss

@@ -26,11 +26,12 @@ body{
 }
 .Header{
   display: flex;
-  float: right;
 position: fixed;
+margin: 40px;
 padding: 20px;
- z-index: 4;
-  width: 100%; 
+//  z-index: 4;
+  width: 60%; 
+  right:0;
  top: 0;
  background-color: white;
 }
@@ -41,7 +42,7 @@ padding: 20px;
   margin-left: 20px;
 }
 .User{
-  padding: 10px;
+  // padding: 10px;
 }
 .Feed{
   margin-right: 20px;  
@@ -72,9 +73,11 @@ main{
 .Title{
   text-align: left;
 }
-.Input{
-  display: flex;
-  width: 100%;
+.Input{ 
+
+  // display: flex;
+  width: 50%;
+
 }
 .AboutMe{
   
@@ -207,4 +210,4 @@ Link:hover{
   max-height: 500px;
   padding: 15px 0;
   overflow: auto;
-}
+}

+ 33 - 32
src/actions/index.js

@@ -1,4 +1,4 @@
-import { actionFullProfilePageUser, actionFullProfilePage,actionFeedType,actionClearFeedPosts } from '../reducers'
+import { actionFullProfilePageUser,actionProfilePageDataTypeUser, actionFullProfilePage,actionFeedType,actionClearFeedPosts } from '../reducers'
 
 export const actionAuthLogin = (token) => ({ type: 'AUTH_LOGIN', token })
 export const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })
@@ -89,7 +89,7 @@ export const actionRegister = (login, password) =>
     'register',
     gql(
       `mutation register($login: String!, $password: String!) {
-                UserUpsert(user: {login: $login, password: $password, nick: $login}) {
+        createUser (login: $login, password: $password) {
                   _id login
                 }
               }`,
@@ -123,23 +123,21 @@ export const actionUploadFiles = (files) =>
     Promise.all(files.map((file) => uploadFile(file))),
   )
 
-export const actionAvatar = (imageId) => async (dispatch, getState) => {
-  await dispatch(
-    actionPromise(
-      'setAvatar',
-      gql(
-        `mutation setAvatar($imageId:ID, $userId:String){
+export const actionAvatar = (imageId, myId) =>
+  actionPromise(
+    'setAvatar',
+    gql(
+      `mutation setAvatar($imageId:ID, $userId:String){
     UserUpsert(user:{_id: $userId, avatar: {_id: $imageId}}){
     _id, avatar{
         _id
     }
     }
     }`,
-        { imageId, userId: getState().auth?.payload?.sub?.id },
-      ),
+      { imageId, userId:  myId  },
     ),
-  )
-}
+      )
+
 
 // export const actionChangeLogin = (imageId) => async (dispatch, getState) => {
 //   await dispatch(
@@ -388,6 +386,7 @@ export const actionAddSubComment = (commentId, comment) => async (dispatch) => {
 //   }
 // }
 
+
 export const actionAddFullComment = (postId, comment) => async (
   dispatch,
   getState,
@@ -540,15 +539,16 @@ export const actionDeleteLike = (likeId, postId) => async (dispatch) => {
 //   _id: $postId
 // }
 // query:"[{\"_id\": \"62068eaaad55d22f3e2fb250\"}]")
-export const actionSetAvatar = (file) => async (dispatch) => {
-  let result = await dispatch(actionUploadFile(file))
-  if (result) {
-    await dispatch(actionAvatar(result._id))
-    // await dispatch(actionAvatar(result._id))
 
-    await dispatch(actionAboutMe())
-  }
+export const actionSetAvatar = (file, myId)  => async (dispatch) => {
+   const avatar = await dispatch(actionAvatar(file, myId));
+  console.log('AVATAR', avatar)
+  if(avatar)
+  await dispatch(actionFullProfilePage(myId))
+  
+  
 }
+
 // let following =  getState().promise.aboutUser?.payload?.following
 // let result =  await dispatch (actionAboutMe())
 export const actionPostsFeed = (myFollowing,skip) => 
@@ -589,11 +589,14 @@ export const actionPostsFeed = (myFollowing,skip) =>
       const {
         feed: { postsFeed = [] },
       } = getState();
-      const myFollowing =  getState().promise.aboutMe?.payload?.following.map(
-        ({ _id }) => _id,
-      )
-      
-      let postsUsers = await dispatch(actionPostsFeed(myFollowing,postsFeed?.length));
+      const myFollowing =
+        getState().promise.aboutMe?.payload?.following.map(
+        ({ _id }) => _id
+        )
+
+      const myId = getState().profileData?.aboutMe?._id;
+          console.log('MY ID FOR FEED ', myId)
+      let postsUsers = await dispatch(actionPostsFeed([...myFollowing, myId], postsFeed?.length));
       if (postsUsers) {
         dispatch(actionFeedType(postsUsers));
       }
@@ -672,8 +675,7 @@ export const actionSearchUser = (userName) => async (dispatch) => {
   )
 }
 
-export const actionUserUpsert = (user) => async (dispatch, getState) => {
-  await dispatch(
+export const actionUserUpsert = (user) => 
     actionPromise(
       'userUpsert',
       gql(
@@ -684,14 +686,12 @@ export const actionUserUpsert = (user) => async (dispatch, getState) => {
               }`,
         {
           user: {
-            ...user,
-            _id: JSON.stringify([{ _id: getState().auth?.payload?.sub?.id }]),
-          },
+            ...user
+          }
         },
       ),
-    ),
-  )
-}
+    )
+
 
 export const actionAboutUser = (_id) =>
   actionPromise(
@@ -824,6 +824,7 @@ export const actionUserUpdate = (user = {}) => async (dispatch, getState) => {
   await dispatch(actionAboutMe())
 }
 
+
 export const actionFindSubComment = (findId) =>
   actionPromise(
     'subComments',

+ 81 - 0
src/components/EditAvatar.js

@@ -0,0 +1,81 @@
+import { EditOutlined } from '@ant-design/icons'
+import { connect } from 'react-redux'
+import { Upload, message, Avatar, Button } from 'antd'
+import { actionAvatar, actionUploadFile,actionSetAvatar } from '../actions'
+import ImgCrop from 'antd-img-crop'
+import React, { useMemo, useState, useEffect } from 'react'
+import { Basic } from '../helpers'
+import user from '../materials/user1.png'
+import { ConstructorModal } from '../helpers'
+import { Image, Divider, Radio } from 'antd'
+
+export const propsUploadFile = {
+  name: 'photo',
+  action: `/upload`,
+  headers:
+    localStorage.authToken || sessionStorage.authToken
+      ? {
+          Authorization:
+            'Bearer ' + (localStorage.authToken || sessionStorage.authToken),
+        }
+      : {},
+}
+const EditInfo = ({ info, onSave, onFileDrop, fileStatus, myId }) => {
+  console.log('info ', info)
+  const [state, setState] = useState(info)
+  console.log('БЛЯХА ТУТ ЖЕ МОЙ АЙДИ  ', myId)
+
+  // if (fileStatus?.status === 'FULFILLED') {
+  //     message.success(`${fileStatus.name} file uploaded successfully`);
+  // } else if (fileStatus?.status=== 'REJECTED') {
+  //     message.error(`${fileStatus.name} file upload failed.`);
+  // }
+
+  console.log('state my ', state)
+  useEffect(() => {
+    fileStatus?.status == 'FULFILLED' &&
+      message.success(` file uploaded successfully`) &&
+      setState({
+        ...state,
+        ...state?.avatar,
+        ...fileStatus?.payload
+      })
+  }, [fileStatus])
+
+  // const onChangeLogin = (event) =>
+  //   setState({
+  //     ...state,
+  //     login: event.target.value,
+  //   })
+
+  if (fileStatus?.status == 'FULFILLED') console.log('fullfilled', fileStatus)
+
+  return (
+    <>
+      <Basic onLoad={onFileDrop}/>
+      {fileStatus?.payload?.url && (
+        <Image
+          style={{ marginRight: '20px', maxWidth: '200px', maxHeight: '200px' }}
+          src={'/' + fileStatus?.payload?.url}
+        />
+      )}
+        <br/>
+      <Button style={{}}
+        disabled={state?.images?.length == 0}
+        onClick={() => onSave(state?._id,myId)}>
+        Save
+      </Button>
+    </>
+  )
+}
+export const CEditInfo = connect(
+    (state) => ({
+      myId:state?.auth.payload.sub?.id,
+    fileStatus: state.promise?.uploadFile,
+    info: state?.profileData?.aboutMe?.avatar,
+  }),
+  {
+    onSave: actionSetAvatar,
+    onFileDrop: actionUploadFile,
+  },
+)(EditInfo)

+ 8 - 9
src/components/Header.js

@@ -6,6 +6,7 @@ import { Link } from 'react-router-dom'
 import { connect } from 'react-redux'
 import {  AddPost } from '../components/NewPost'
 import React, { useEffect } from 'react'
+import { CLoginForm,CRegisterForm,CLogout } from '../components/LoginRegisterLogout'
 
 export const Feed = ({ aboutMe, onAllFollowing, onPostsFeed, postsFeed }) => {
   console.log('POST FEED', postsFeed)
@@ -24,12 +25,7 @@ export const CFeed = connect((state) => ({
   aboutMe: state?.profileData?.aboutMe,
 }))(Feed)
 
-const Likes = () => (
-  <Button size="large" className="Likes">
-    {' '}
-    Likes{' '}
-  </Button>
-)
+
 
 const Recommendations = () => (
   <Button size="large" className="Recomendations">
@@ -41,14 +37,15 @@ const User = ({ my_Id, aboutMe: { _id, login, avatar } = {}, onMyPage }) => {
   useEffect(() => onMyPage(_id), [_id])
   return (
     <Link className="User" to={`/profile/${_id}`}>
-      {avatar?.url ? <Avatar src={'/' + avatar?.url} /> : <Avatar src={user} />}
+      {avatar?.url ? <Avatar src={'/' + avatar?.url} style={{ marginLeft: '20px',width:'45px', height:'45px'}} /> :
+        <Avatar src={user} style={{ marginLeft: '20px',width:'45px', height:'45px'}}/>}
     </Link>
   )
 }
 
 const CUser = connect(
   (state) => ({
-    my_Id: state.auth.payload.sub.id || '',
+    my_Id: state.auth.payload?.sub?.id || '',
     aboutMe: state.profileData.aboutMe,
   }),
   { onMyPage: actionFullProfilePageUser },
@@ -57,11 +54,13 @@ const CUser = connect(
 export const Header = () => {
   return (
     <section className="Header">
+        <CLogout className='Link'/>
+    <Link className='Link' to={`/login`}> Sign In </Link>
       <CSearch />
       <CFeed />
       <AddPost />
       <Recommendations />
-      <Likes />
+ 
       <CUser />
     </section>
   )

+ 20 - 0
src/components/LinkToUser.js

@@ -0,0 +1,20 @@
+import user from '../materials/user.png'
+import { Link} from 'react-router-dom'
+import { Avatar, Col} from 'antd'
+
+export const LinkToUser = (owner, size) => {
+    return <Col className="gutter-row" span={6}>
+        <Link to={`/profile/${owner?._id}`} style={{ display: 'flex', flexDirection: 'row' }}>
+        {owner?.avatar ? (
+            <Avatar
+               size={size}
+                src={'/' + owner?.avatar?.url}
+            />
+        ) : (
+            <Avatar size={size} src={user} />
+        )}
+        <h1> {owner?.login || 'Anon'}</h1>
+        </Link>
+    </Col>
+}
+export default LinkToUser

+ 158 - 0
src/components/LoginRegisterLogout.js

@@ -0,0 +1,158 @@
+import {
+  actionFullLogin,
+  actionFullRegister,
+  actionAuthLogout,
+} from '../actions'
+import React, { useState } from 'react'
+import { connect } from 'react-redux'
+import { Upload, Button, DatePicker, Input,Checkbox, Form } from 'antd'
+import {
+    EyeOutlined,EyeInvisibleOutlined
+} from '@ant-design/icons';
+import { Link } from 'react-router-dom'
+  
+
+
+
+const LoginForm = ({ onLogin, children }) => {
+  const [login, setLogin] = useState('')
+  const [password, setPassword] = useState('')
+const [checked, setChecked] = useState(false)
+  console.log('checked ', checked)
+    return (
+      <>
+        <Form size="large"
+              name="basic"
+              style={{marginTop:'200px'}}
+              labelCol={{ span: 4 }}
+                wrapperCol={{ span: 10 }} 
+
+      initialValues={{ remember: true }}  autoComplete="off">
+              <h1 style={{marginLeft:'400px'}}> {children} </h1>
+      <Form.Item
+        label="Login"
+        name="login" size="large"
+        rules={[{ required: true, message: 'Please input login!' }]}>
+                  <Input value={login} size="large" onChange={(e) => setLogin(e.target.value)} />
+                  
+      </Form.Item>
+
+      <Form.Item
+        label="Password"
+        name="password" size="large"
+        rules={[{ required: true, message: 'Please input your password!' }]}
+      >
+         <Input size="large"
+            type={checked ? 'password' : 'text'}
+            value={password}
+            onChange={(e) => setPassword(e.target.value)}
+                  />
+                  
+      </Form.Item>
+
+              <Form.Item name="remember" valuePropName="checked" wrapperCol={{ offset: 4, span: 10 }}>
+              <Checkbox checked={checked} onChange={(e) => {
+                      setChecked(e.target.checked)
+                  }} size="large">
+                      See the password
+                      </Checkbox>
+                  
+                       </Form.Item>
+        
+      <Form.Item wrapperCol={{ offset: 4, span: 10 }}>
+        <Button size="large"type="primary" htmlType="submit"  className="Btn"
+            disabled={login.length < 5 || password.length < 5}
+            onClick={() => onLogin(login, password)}>
+          {children}
+        </Button>
+      </Form.Item>
+    </Form>
+      {/* <div>
+        <h1 style={{ marginTop: '50px' }}> {children}</h1>
+          <strong> You must enter at least 5 characters </strong>
+          <h2> Login</h2>
+          <Input value={login} onChange={(e) => setLogin(e.target.value)} />
+          <h2> Password </h2>
+          <Input
+            type={checked ? 'password' : 'text'}
+            value={password}
+            onChange={(e) => setPassword(e.target.value)}
+          />
+          <Input
+            type="checkbox"
+            checked={checked}
+            onChange={(e) => {
+              setChecked(e.target.checked)
+            }}
+          />
+          <br />
+          <Button
+            className="Btn"
+            disabled={login.length < 5 || password.length < 5}
+            onClick={() => onLogin(login, password)}
+          >
+            {children}
+          </Button>
+          {<CAuth />}
+      </div> */}
+    </>
+  )
+}
+export const CLoginForm = connect(
+  (state) => ({
+    children: `Sign In`,
+  }),
+  {
+    onLogin: actionFullLogin,
+  },
+)(LoginForm)
+
+export const CRegisterForm = connect(
+  (state) => ({
+    children: `Register`,
+  }),
+  {
+    onLogin: actionFullRegister,
+  },
+)(LoginForm)
+
+export const CLogout = connect(
+  (state) => ({
+    children: `Logout (${state.auth.payload?.sub?.login || 'Anon'})`,
+  }),
+  { onClick: actionAuthLogout },
+)('a')
+
+// export const InputForm = ({}) =>
+
+//         <div>
+//             если есть акк выберите сигн ин, если нету регистр
+//         {console.log('шото есть сук')}
+//             <Button> Sign In </Button>
+//             <Button> Register </Button>
+
+//         </div>
+ 
+// // CForm
+
+export const InputForm = ({ onLogin, children }) => {
+    const [login, setLogin] = useState('')
+    const [password, setPassword] = useState('')
+  const [checked, setChecked] = useState(false)
+    console.log('checked ', checked)
+      return (
+          <>
+              {/* display:'flex', flexDirection:'row', */}
+           <div style={{ background:'cyan', top:'0',position:'fixed'}}>
+          <h1>  если есть акк выберите сигн ин, если нету регистр</h1>
+         {console.log('шото есть сук')}
+                      <Link className='Link' to={`/login`}> Sign In </Link>  
+            
+                      <Link className='Link' to={`/register`}> Register </Link> 
+
+         </div>
+      </>
+    )
+  }
+export const CInputForm= connect(
+  )(InputForm)

+ 43 - 13
src/components/NewPost.js

@@ -2,15 +2,17 @@ import React, { useMemo, useState, useEffect } from 'react'
 import { Router, Route, Link, Redirect, Switch } from 'react-router-dom'
 import { Provider, connect } from 'react-redux'
 import { actionUploadFile, actionUploadFiles, actionPostUpsert,actionUserUpdate} from '../actions'
-import { Upload, Button, DatePicker, Space } from 'antd'
+import {actionClearPostsOneAC} from '../reducers'
+
+import { Upload, Button, DatePicker, Space,message  } from 'antd'
 import {Basic, SortableContainer, SortableItem , ImageDemo} from '../components/DropZone'
 import { arrayMove, arrayMoveImmutable, arrayMoveMutable } from 'array-move'
 import { ConsoleSqlOutlined } from '@ant-design/icons'
 import ReactDOM from 'react-dom';
-
+import { history } from '../App'
 const defaultPost = {
-  title: 'Bmw',
-  text: 'Bmw',
+  title: '',
+  text: '',
   images: [
     // {_id: '6231c4292be7e42fbc9096c4',
     //  url: 'images/d2438e8c6502eb5da60ecc8f7a6b8aff'}
@@ -41,7 +43,7 @@ export const AddPost = ({ children }) => {
   
     return (
       <>
-        <Link to={`/edit/post`}>
+        <Link to={`/edit/post/new`}>
           <Button onClick={() => setState(!state)}> + </Button>
           {!state && children}
         </Link>
@@ -67,16 +69,38 @@ export const AddPost = ({ children }) => {
 //   }
 
 
-const PostEditor = ({ post=defaultPost, onSave, onFileDrop, fileStatus, userUpdate }) => {
-    console.log('filestatus ', fileStatus)
-    const [state, setState] = useState(post)
+  // match: { params: { _id } }
+  // console.log('PARAMS ', match?.params?._id)
+  const PostEditor = ({myID,post={}, match: { params: { _id } },
+    onSave, onFileDrop, fileStatus, clearPostOne }) => {
+ 
+  console.log('PARAMS ', _id)
+  console.log('post ', post)
+
+  console.log('filestatus ', fileStatus)
+const [state, setState] = useState(post)
+//   useEffect(() => {
+//     if (_id === 'new') {
+//         clearPostOne()
+//       setState(defaultPost)
+//     }
+// }, [_id]);
+
+useEffect(() => {
+  if ( fileStatus?.status== 'FULFILLED') {
+      message.success(`post published, can create a new one`)
+      history.push(`/profile/${myID}`)
+  } else if (fileStatus?.status === "REJECTED") {
+      message.error('Error')
+  }
+}, [fileStatus?.status])  
     useEffect(() => {
       fileStatus?.status == 'FULFILLED' &&
         setState({
           ...state,
           images: [
-            ...state.images,
-            ...fileStatus.payload
+            ...state?.images,
+            ...fileStatus?.payload
           ],
         })
     }, [fileStatus])
@@ -108,7 +132,7 @@ const PostEditor = ({ post=defaultPost, onSave, onFileDrop, fileStatus, userUpda
       <section className="Post">
         <Basic onLoad={onFileDrop} />
         <SortableContainer onSortEnd={onSortEnd}>
-          {(state.images || []).map(({ _id, url }, index) => (
+          {(state?.images || []).map(({ _id, url }, index) => (
           <div >
           <SortableItem key={`item-${_id}`} index={index} url={url} /> 
               <button onClick={() => onRemoveImage(_id)}> x </button> 
@@ -130,9 +154,15 @@ const PostEditor = ({ post=defaultPost, onSave, onFileDrop, fileStatus, userUpda
     )
   }
  export const CPostEditor = connect(
-    (state) => ({ fileStatus: state.promise?.uploadFiles, }),
+   (state) => ({
+     fileStatus: state.promise?.uploadFiles,
+     post:state?.onePost?.payload,
+     myID: state?.aboutMe?._id,
+   
+   }),
     {
       onSave: actionPostUpsert,
-      onFileDrop: actionUploadFiles
+      onFileDrop: actionUploadFiles,
+      clearPostOne: actionClearPostsOneAC
     },
   )(PostEditor)

+ 48 - 9
src/components/Post.js

@@ -12,10 +12,32 @@ import { Row, Col } from 'antd';
 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 { CComments, AddComment } from '../components/Post_Comment'
+import { CPostEditor } from '../components/NewPost'
+
 import { ConstructorModal} from '../helpers'
 import React, { useMemo, useState, useEffect } from 'react'
 // const postId="625afa1d069dca48a822ffb0"
+const EditMyPost = ({ open, children }) =>{
+const [opened, setOpened] = useState(open)
+return (
+  <>
+    {/* <Link to={`/editProfile`}> */}
+    <button style={{ width: '100px' }}
+      onClick={() => {
+        setOpened(!opened)
+      }}
+    >
+      Edit Post
+    </button>
+    {opened && children}
+    {/* </Link> */}
+  </>
+)
+}
+  
+
+
 export const Card = ({ post, onPost }) => (
   <>
     {/* <Link to={`/post/${postId}`} onClick={() => onPost(postId)}> */}
@@ -211,22 +233,34 @@ const Like = ({ my_Id, postId, addLike, deleteLike, likes=[], children }) =>
 export const PagePost = ({ my_Id, onePost, likes, addComment,
   addCommentReply, addLike, findSubComment, deleteLike,
   match: { params: { _id } },
-  aboutUser: { avatar, login } = {}, onPost }) => {
+  aboutUser = {}, onPost }) =>
+{
+  const [isModalVisible, setIsModalVisible] = useState(false);
 
+  const showModal = () => {
+    setIsModalVisible(true);
+  };
   useEffect(() => {
     onPost(_id)
     console.log('ONE POST _ID',onePost?._id)
   }, [_id])
+
   return (
     <>
+         
      <Row>
-      <Col span={14}>
+        <Col span={14}>
+        <ConstructorModal title={'Edit post'} isModalVisible={isModalVisible}
+                  setIsModalVisible={setIsModalVisible}>
+           <CPostEditor/>
+          </ConstructorModal>
+          
       {/* <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)}
           </h3>
-          <div style={{marginLeft:'100px'}}>
+          <div style={{ marginLeft: '100px' }}>
           {/* <Col span={3} offset={2}> */}
           <Like my_Id={my_Id} addLike={addLike} deleteLike={deleteLike} likes={onePost?.likes} postId={onePost?._id}>
               <Likes likes={onePost?.likes} />
@@ -236,19 +270,24 @@ export const PagePost = ({ my_Id, onePost, likes, addComment,
     </Col>
 <Col span={8}>
 <div  style={{display: 'flex', flexDirection:'row'}}>
-
-      {avatar ? (
+       
+      {aboutUser?.avatar ? (
         <Avatar
           style={{ width: '50px', height: '50px' }}
-          src={ '/' + avatar?.url}
+          src={ '/' + aboutUser?.avatar?.url}
         />
       ) : (
         <Avatar style={{ width: '50px', height: '50px' }} src={user} />
       )
       }
+            <h1 style={{ marginLeft: '20px' }}> {aboutUser?.login || 'Anon'}</h1>
+            <Row span={1}>
+              {my_Id === aboutUser?._id && <Link  to={`/edit/post/${_id}`}> Edit post </Link>
 
-      <h1 style={{ marginLeft:'20px'}}> {login}</h1>
-      </div>
+             }
+            </Row>
+          </div>
+  
       <Divider/>
       <h2> Title: {onePost?.title || ''} </h2>
 

+ 2 - 11
src/components/PostFeed.js

@@ -13,6 +13,7 @@ import user from '../materials/user.png'
 import { Avatar, Image, Divider, Radio } from 'antd'
 import { CPost, MyCarousel } from './Post'
 import { Row, Col } from 'antd';
+import LinkToUser from './LinkToUser'
 
 const MyPostFeed = ({ postsFeed = [], onPostsFeed, clearDataProfile }) => {
   const [checkScroll, setCheckScroll] = useState(true);
@@ -52,17 +53,7 @@ const MyPostFeed = ({ postsFeed = [], onPostsFeed, clearDataProfile }) => {
             {
               (postsFeed || []).map(({ images, title, text, owner }) => (
                 <div className='PostFeed'>
-                  <Link to={`/profile/${owner?._id}`} >
-                    {owner?.avatar ? (
-                      <Avatar
-                        style={{ width: '50px', height: '50px' }}
-                        src={'/' + owner?.avatar?.url}
-                      />
-                    ) : (
-                      <Avatar style={{ width: '50px', height: '50px' }} src={user} />
-                    )}
-                    <h1> {owner?.login || 'anon'}</h1>
-                  </Link>
+                <LinkToUser owner={owner} size='50px'/>
   
                   <MyCarousel images={images} style={{ marginTop: '60px' }} />
                   <h1> Title: {title || ''}</h1>

+ 1 - 1
src/components/Search_Users.js

@@ -67,7 +67,7 @@ export const ResultUserFind = ({ my_Id, userFind = [], onPageData, size,handleCa
             userFind={searchUser} />}
             trigger="focus"
         >
-          <Search 
+          <Search style={{width:'30%'} }
             placeholder="Input search user"
             allowClear
             enterButton="Search"

+ 29 - 81
src/components/User.js

@@ -1,6 +1,6 @@
 import {
-  actionAllPosts, actionOnePost, actionAboutMe, actionUploadFile,actionFullUnSubscribe, actionUserUpsert,
-  actionAddFullSubscribe,actionFullSubscribe,actionPostsCount,
+  actionAllPosts, actionOnePost, actionAboutMe, actionUploadFile,actionFullUnSubscribe,
+  actionAddFullSubscribe,actionFullSubscribe,actionPostsCount,actionUserUpsert,
   actionSetAvatar, actionAvatar} from '../actions'
 import user from '../materials/user1.png'
 import React, { useMemo, useState, useEffect } from 'react'
@@ -17,36 +17,10 @@ import { useDropzone } from 'react-dropzone'
 import { Upload, Button, DatePicker, Space } from 'antd'
 import { UploadOutlined, SearchOutlined } from '@ant-design/icons'
 import { Row, Col } from 'antd';
-
+import { CEditInfo } from '../components/EditAvatar'
 import { useDispatch } from "react-redux";
 import { useParams } from "react-router-dom";
 
-export function Basic({ onLoad }) {
-  const { acceptedFiles, getRootProps, getInputProps } = useDropzone()
-  const files = acceptedFiles.map((file) => (
-    <li key={file.path}>
-      {file.path} - {file.size} bytes
-    </li>
-  ))
-  console.log('acceptedFiles', acceptedFiles)
-  useEffect(() => {
-    acceptedFiles[0] && onLoad(acceptedFiles[0])
-  }, [acceptedFiles])
-  return (
-    <section className="container">
-      <div {...getRootProps({ className: 'Dropzone' })}>
-        <input {...getInputProps()} />
-        <Button icon={<UploadOutlined />}>
-          Drag 'n' drop some files here, or click to select files
-        </Button>
-      </div>
-      <aside>
-        <h4 style={{ color: 'black' }}>Files</h4>
-        <ul>{files}</ul>
-      </aside>
-    </section>
-  )
-}
 
 export const EditAccount = ({ open, children }) => {
   const [opened, setOpened] = useState(open)
@@ -54,9 +28,9 @@ export const EditAccount = ({ open, children }) => {
     <>
       {/* <Link to={`/editProfile`}> */}
       <button style={{ width: '100px' }}
-        onClick={() => {
+        onClick={
           setOpened(!opened)
-        }}
+        }
       >
         Edit account
       </button>
@@ -74,47 +48,7 @@ const Input = ({ state, onChangeText }) => (
     onChange={onChangeText}
   />
 )
-const EditInfo = ({ info = {}, onSave, onFileDrop, fileStatus }) => {
-  console.log('filestatus ', fileStatus)
-  const [state, setState] = useState(info)
-  useEffect(() => {
-    fileStatus?.status == 'FULFILLED' &&
-      setState({
-        ...state,
-        ...state.avatar,
-        ...fileStatus.payload,
-        // _id: fileStatus?.payload._id,
-        // url: fileStatus?.payload.url
-      })
-  }, [fileStatus])
 
-  const onChangeLogin = (event) =>
-    setState({
-      ...state,
-      login: event.target.value,
-    })
-  console.log('state my ', state)
-  return (
-    <section>
-      <Basic onLoad={onFileDrop} />
-      <Input state={state.login || ''} onChangeText={onChangeLogin} />
-      <h1 className="Title"> LOGIN </h1>
-      <button
-        disabled={state?.images?.length == 0}
-        onClick={() => onSave(state._id)}
-      >
-        Save
-      </button>
-    </section>
-  )
-}
-export const CEditInfo = connect(
-  (state) => ({ fileStatus: state.promise?.uploadFile }),
-  {
-    onSave: actionAvatar,
-    onFileDrop: actionUploadFile,
-  },
-)(EditInfo)
 
 
 export const PageAboutUser = ({ match: { params: { _id } },
@@ -157,6 +91,7 @@ export const PageAboutUser = ({ match: { params: { _id } },
   const showModalFollowing = () => {
     setIsModalVisibleFollowing(true);
   };
+
   const [isModalVisibleFollowers, setIsModalVisibleFollowers] = useState(false);
 
   const showModalFollowers = () => {
@@ -168,6 +103,13 @@ export const PageAboutUser = ({ match: { params: { _id } },
   const handleCancelFollowers = () => {
     setIsModalVisibleFollowers(false);
   };
+  const [isModalVisibleEdit, setIsModalVisibleEdit] = useState(false);
+
+  const showModalEdit = () => {
+    setIsModalVisibleEdit(true);
+  };
+
+
   return (
   
     <>
@@ -229,14 +171,12 @@ export const PageAboutUser = ({ match: { params: { _id } },
         </div>
               <h3> nick: {nick == null ? login : nick}</h3>
               {
-                checkMyId ?
-                  <EditAccount>
-          <div>
-            <h2>Edit login</h2>
-            <p>Edit avatar</p>
-            <CEditInfo />
-          </div>
-                </EditAccount>
+                  checkMyId ?
+                    <>
+                      <button onClick={showModalEdit}>
+                      EDIT
+                      </button>
+             </>
                     :
                     <Subscribe my_Id={my_Id} deleteSubscribe={deleteSubscribe}
                       followId={followId} addSubscribe={addSubscribe} aboutMeFollowing={aboutMeFollowing} />
@@ -263,6 +203,14 @@ export const PageAboutUser = ({ match: { params: { _id } },
                 
       </ConstructorModal>
               
+                
+      <ConstructorModal title={'Edit avatar'}
+                isModalVisible={isModalVisibleEdit}
+                setIsModalVisible={setIsModalVisibleEdit}>
+                          <CEditInfo />
+                </ConstructorModal>
+                
+
               </div>
               </Row>
         </section>
@@ -310,10 +258,10 @@ const Subscribe = ({ my_Id, postId, addLike, deleteLike, following = [], deleteS
   aboutMeFollowing=[], aboutUserFollowing, addSubscribe, followId, children }) =>
 {
 
- const checkFollowId =()=> aboutMeFollowing?.find(follower => follower?._id === followId)?._id
+ const checkFollowId = aboutMeFollowing?.find(follower => follower?._id === followId)?._id
 
  // console.log(' _id', aboutMeFollowing?.find(f => f._id === followId && true))
-  console.log('FOLLOWING ') 
+  console.log('FOLLOWING ', checkFollowId) 
   // const [isModalVisible, setIsModalVisible] = useState(false);
 
   // const showModal = () => {

+ 33 - 1
src/helpers/index.js

@@ -1,5 +1,9 @@
 import { Modal } from 'antd';
 // import React, { useState } from 'react'
+import { useDropzone } from 'react-dropzone'
+import { Upload, Button, DatePicker, Space } from 'antd'
+import React, { useMemo, useState, useEffect } from 'react'
+import { UploadOutlined, SearchOutlined } from '@ant-design/icons'
 
 export const ConstructorModal = ({title, children, isModalVisible, setIsModalVisible }) =>
 {
@@ -20,4 +24,32 @@ export const ConstructorModal = ({title, children, isModalVisible, setIsModalVis
     </>
   )
 }
-  
+
+
+export function Basic({ onLoad }) {
+  const { acceptedFiles, getRootProps, getInputProps } = useDropzone()
+  const files = acceptedFiles.map((file) => (
+    <li key={file.path}>
+      {file.path} - {file.size} bytes
+    </li>
+  ))
+  console.log('acceptedFiles', acceptedFiles)
+  useEffect(() => {
+    acceptedFiles[0] && onLoad(acceptedFiles[0])
+  }, [acceptedFiles])
+  return (
+    <section className="container">
+      <div {...getRootProps({ className: 'Dropzone' })}>
+        <input {...getInputProps()} />
+        <Button icon={<UploadOutlined />}>
+          Drag 'n' drop some files here, or click to select files
+        </Button>
+      </div>
+      <aside>
+        <h4 style={{ color: 'black' }}>File</h4>
+        <ul>{files}</ul>
+        {/* <img src={files.}/> */}
+      </aside>
+    </section>
+  )
+}

+ 73 - 20
src/reducers/index.js

@@ -32,6 +32,11 @@ export const actionProfilePageData = (id) => ({ type: 'DATA_PROFILE', id })
   export const actionProfilePageDataType= (aboutMe) =>
   ({ type: 'PROFILE-PAGE', aboutMe })
 
+  export const actionAvatarUpdate= (aboutUser) =>
+  ({ type: 'CHANGE-AVATAR-USER', aboutUser })
+
+  
+
 export const actionFullProfilePageUser = (_id) =>
   async dispatch => {
     const aboutUser = await dispatch(actionAboutUser(_id))
@@ -42,13 +47,28 @@ export const actionFullProfilePageUser = (_id) =>
       await dispatch(actionProfilePageDataTypeUser(aboutUser, allPosts))
     }
   }
+
+  export const actionFullSetAvatar = (_id) =>
+  async dispatch => {
+    const aboutUser = await dispatch(actionAboutUser(_id))
+    console.log('ABOUTUSER ', aboutUser)
+    const allPosts = await dispatch(actionAllPostsUser(_id))
+    console.log('ALLPOSTS ', allPosts )
+    if (aboutUser && allPosts) {
+      await dispatch(actionProfilePageDataTypeUser(aboutUser, allPosts))
+    }
+  }
+
   export const actionFullProfilePage = (_id) =>
   async dispatch => {
-    const aboutMe= await dispatch(actionAboutMe(_id))
+    const aboutMe = await dispatch(actionAboutMe(_id))
+    console.log('actionFullProfilePage ', actionFullProfilePage)
     // const allPostsMe = await dispatch(actionAllPosts(_id))
     if (aboutMe) {
       await dispatch(actionProfilePageDataType(aboutMe))
     }
+
+
   }
   export const actionRemoveDataUser= () =>
   ({ type: 'REMOVE-DATA' })
@@ -62,9 +82,13 @@ export const profileUserReducer = (state = {}, { type, aboutUser, allPosts }) =>
     },
     'REMOVE-DATA': () => {
       return {
-        ...state={},
-        aboutUser:{},
-        allPosts:[]
+        ...state = {},
+        aboutUser: {},
+        allPosts: []
+      }
+    },
+      'CHANGE-AVATAR-USER': () => { return {
+        ...state, aboutUser
       }
   }
   
@@ -85,20 +109,6 @@ export const profileUserReducer = (state = {}, { type, aboutUser, allPosts }) =>
     console.log('postsFeed ', postsFeed)
     const postsFeedCount = await dispatch(actionPostsFeedCount(getState))
     console.log('postsFeedCount ', postsFeedCount)
-
-    // const allPosts = await dispatch(actionAllPostsUser(_id))
-    // console.log('ALLPOSTS ', allPosts )
-
-    // if (postsFeed?.length !== (postsFeedCount ? postsFeedCount : 1)) {
-    //   const postsFeedNew = await dispatch(actionPostsFeed(_id))
-    //   console.log('postsFeedNew ', postsFeedNew)
-    //   const postsFeedCountNew = await dispatch(actionPostsFeedCount(_id))
-    //   console.log('postsFeedCountNew ', postsFeedCountNew)
-   
-   
-        // if (postsFeed && postsFeedCount)
-        // await dispatch(actionFeedType(postsFeed, postsFeedCount))
-      
       if (skip < postsFeedCount)
       {
         console.log('SKIIIP ', skip)
@@ -112,13 +122,31 @@ export const profileUserReducer = (state = {}, { type, aboutUser, allPosts }) =>
         }
      
     }
+    export const actionOnePost= (onePost) =>
+    ({ type: 'ONE-POST', onePost })
+  
   export const actionClearFeedPosts = () => ({ type: 'DELETE-POSTS' });
 
   export const actionFullClearFeedPosts = () => (dispatch) => {
     return dispatch(actionClearFeedPosts())
   }
+  export const actionFullOnePost = () =>
+    async (dispatch, getState) => {
   
-  
+  const onePost = await dispatch(actionOnePost(getState))
+    //  const skip = postsFeed.length
+    // console.log('postsFeed ', postsFeed)
+    // const postsFeedCount = await dispatch(actionPostsFeedCount(getState))
+    // console.log('postsFeedCount ', postsFeedCount)
+      // if (skip < postsFeedCount)
+      // {
+      //   console.log('SKIIIP ', skip)
+      //   const newPosts = await dispatch(actionPostsFeed(getState, skip))
+        if (onePost) {
+          dispatch(actionOnePost(onePost));
+          console.log('onePost ', onePost)
+        }
+      }
 export const feedReducer = (state = {}, {skip, type, newPosts=[], postsFeed,postsFeedCount }) => {
   const types = {
     'ADD-POSTS': () => {
@@ -140,6 +168,27 @@ export const feedReducer = (state = {}, {skip, type, newPosts=[], postsFeed,post
     }
     return state
   }
+  export const postReducer = (state = {}, {skip, type, newPosts=[], postsFeed,postsFeedCount }) => {
+    const types = {
+      'ADD-POSTS': () => {
+        return {
+          ...state,
+         onePost: state?.onePost
+        }
+      },
+      'CLEAR-POST-ONE': () => {
+        return {
+          ...state,
+          onePost: {}
+        }
+    }
+    
+      }
+      if (type in types) {
+          return types[type]()
+      }
+      return state
+    }
 
 export const profileReducer = (state = {}, { type, aboutMe, newResult }) => {
   const types = {
@@ -156,6 +205,7 @@ export const profileReducer = (state = {}, { type, aboutMe, newResult }) => {
   return state
 }
 
+
   function authReducer(state, { type, token }) {
     if (state === undefined && localStorage.authToken) {
       token = localStorage.authToken
@@ -173,13 +223,16 @@ export const profileReducer = (state = {}, { type, aboutMe, newResult }) => {
     }
     return state || {}
   }
+  export const actionClearPostsOneAC = () => ({ type: 'CLEAR-POST-ONE' })
+
  export const store = createStore(
     combineReducers({
       promise: promiseReducer,
       auth: authReducer,
       profileData: profileReducer,
       profilePage: profileUserReducer,
-      feed:feedReducer
+      feed:feedReducer,
+      post:postReducer
       
     }),
     applyMiddleware(thunk),