Переглянути джерело

added page edit / create post - end

makstravm 2 роки тому
батько
коміт
1a0f30384e

+ 9 - 14
src/App.js

@@ -13,7 +13,7 @@ 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 { CEditorPostPage, CEntityEditorPost } from './pages/EntityEditorPost';
 
 export const history = createHistory()
 
@@ -30,28 +30,23 @@ const AppContent = ({ isToken }) =>
                 <Redirect from='/*' to='/auth/login' />
             </Switch>
             :
-
             <Content>
                 <HeaderComponent />
                 <Main>
-                    <Container>
+                    <Switch>
                         <Route path='/' component={CMainPostsFeed} exact />
                         <Route path='/profile/:_id' component={CProfilePage} />
                         <Route path='/message' component={Aside} />
                         {/* <Route path='/add' component={CAdd} /> */}
-                        <Route path='/add' component={CEntityEditorPost} />
-                        <CRRoute path='/all' component={CAllPosts} />
-                    </Container>
-                    <CRRoute path='/post/:id' component={CPostPage} />
-                    {/* <Redirect from='/*' to='/' /> */}
+                        <Route path='/edit/post/:_id' component={CEntityEditorPost} />
+                        <Route path='/all' component={CAllPosts} />
+                        <CRRoute path='/post/:id' component={CPostPage} />
+                        <Redirect from='/*' to='/' />
+                        {/* <Redirect from='/*' to='/post/:id' /> */}
+                    </Switch>
+                    {/*  */}
                 </Main>
             </Content >
-
-
-            // <Switch>
-            //     <Route path='/' component={Content} exact />
-            //     <Redirect from='/auth/*' to='/' />
-            // </Switch>
         }
     </Router >
 

+ 34 - 14
src/App.scss

@@ -326,6 +326,12 @@ body {
     h1 {
         line-height: 1;
     }
+    a {
+        display: inline-block;
+    }
+    &__data {
+        padding-top: 10px;
+    }
     &__name {
         padding-bottom: 10px;
     }
@@ -341,6 +347,10 @@ body {
         span {
             font-size: 1.2em;
         }
+        button {
+            padding: 0;
+            border: none;
+        }
     }
     button {
         color: $defaultColorB;
@@ -363,6 +373,9 @@ body {
             background: #40a9ff;
         }
     }
+    &__created {
+        padding: 10px 0;
+    }
     &__post {
         padding: 2px;
         div {
@@ -388,7 +401,7 @@ body {
 
 .PostOne {
     max-width: 1250px;
-    padding: 0 15px;
+    padding: 40px 15px 0;
     margin: 0 auto;
 
     &__inner {
@@ -419,7 +432,8 @@ body {
         background-color: rgb(87, 87, 87);
         img {
             max-width: 100%;
-            max-height: 650px;
+            max-height: 550px;
+            min-height: 450px;
             margin: 0 auto;
             object-fit: cover;
         }
@@ -445,7 +459,7 @@ body {
         flex-direction: column;
         justify-content: space-between;
         height: 100%;
-        max-height: 565px;
+        max-height: 475px;
     }
     &__description-top {
         flex-grow: 1;
@@ -462,7 +476,7 @@ body {
     font-weight: 500;
 }
 
-.ContainErditorPost {
+.ContainEditorPost {
     width: 100%;
     background-color: $defaultColorW;
     padding: 15px 25px;
@@ -474,7 +488,7 @@ body {
         display: inline-block;
     }
     .description {
-        white-space: pre;
+        white-space: break-spaces;
     }
 }
 .EditPhotos {
@@ -489,6 +503,7 @@ body {
     display: grid;
     grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
     grid-gap: 10px;
+    justify-items: center;
 }
 
 .SortableItemMask {
@@ -510,15 +525,6 @@ body {
             fill: $defaultColorW;
         }
     }
-    .hiden-item,
-    .ant-image-mask {
-        position: absolute;
-        top: 0;
-        left: 0;
-        clip: rect(0 0 0);
-        pointer-events: none;
-        padding: 10px;
-    }
 }
 .SortableItem {
     .Handle {
@@ -538,6 +544,17 @@ body {
             opacity: 1;
         }
     }
+    .hiden-item,
+    .ant-image-mask,
+    .ant-image {
+        display: none;
+        position: absolute;
+        top: 0;
+        left: 0;
+        clip: rect(0 0 0);
+        pointer-events: none;
+        padding: 10px;
+    }
 }
 .ant-image-preview-img-wrapper {
     display: flex;
@@ -547,3 +564,6 @@ body {
         max-height: 60vh;
     }
 }
+.ant-dropdown {
+    box-shadow: 0 0 2px 0 $defaultColorB;
+}

+ 17 - 6
src/actions/index.js

@@ -7,7 +7,7 @@ import { gql } from "../helpers";
 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 })
 
 
@@ -40,13 +40,13 @@ export const actionAboutMeAC = (data) => ({ type: 'ABOUTME-DATA-ADD', data })
 export const actionFullAboutMe = () => ({ type: 'ABOUT_ME' })
 
 export const actionAboutMe = (id) =>
-    actionPromise('aboutMe', gql(`query userOned($myID:String!){
+actionPromise('aboutMe', gql(`query userOned($myID:String!){
                         UserFindOne(query: $myID){
                             _id  login nick
                             avatar { _id url }
                             following{ _id}
                         }
-                }`, { myID: JSON.stringify([{ ___owner: id }]) }))
+                }`, { myID: JSON.stringify([{ _id: id }]) }))
 
 
 //*************** Action Posts Feed ******************//
@@ -93,6 +93,8 @@ export const actionProfileDataAC = (postsData, count, userData) => ({ type: 'ADD
 
 export const actionProfilePageData = (id) => ({ type: 'DATA_PROFILE', id })
 
+export const actionFindPostOne = (_id) => ({ type: 'FIND_POST_ONE', _id })
+
 export const actionProfileData = (_id) =>
     actionPromise('userOneData', gql(` query userOned($id:String!){
                         UserFindOne(query: $id){
@@ -120,6 +122,15 @@ export const actionProfilePagePost = (_id, skip) => actionPromise('userOneDataPo
 }))
 
 
+export const actionPostOneEdit = (_id) =>
+    actionPromise('postOneEdit', gql(`query post($id:String!) {
+                    PostFindOne(query:$id) {
+                        _id title text 
+                        images { _id url}
+                  
+                        }
+                    }`, { id: JSON.stringify([{ _id }]) }))
+
 //****************---All FIND POSTS---*************************//
 
 export const actionAllPosts = () => ({ type: 'ALL_POSTS' })
@@ -377,11 +388,11 @@ export const actionGetFindLiked = (_id) =>
 
 //****************---Create Post ---*************************/
 
-export const actionsentPost = (_id = '', photos, text, title) => ({ type: 'CREATE_POST', photos, text, title })
+export const actionFullSentPost = (images, title, text) => ({ type: 'CREATE_POST', images, text, title })
 
-export const actionSentPost = (photos, title, text, id = "undefined") =>
+export const actionSentPost = (upSertPostObj) =>
     actionPromise('sentPost', gql(`mutation sentPost($post: PostInput){
               PostUpsert(post: $post){
                     _id images{_id url}
                 }
-            }`, { post: { text, title, images: { _id: photos._id } } }))
+            }`, { post: upSertPostObj }))

+ 2 - 2
src/components/Posts.jsx

@@ -1,8 +1,8 @@
 import { connect } from "react-redux"
 import { Card, Col, Row } from 'antd'
-import postNoData from '../images/profile-post-no.jpeg'
-import { backURL, CircularGalleryIcon } from '../helpers'
+import postNoData from '../../images/profile-post-no.jpeg'
 import { Link } from "react-router-dom"
+import { backURL, CircularGalleryIcon } from "../../helpers"
 
 const Posts = ({ posts }) =>
     <Row gutter={[15, 15]}>

+ 0 - 4
src/components/main/new/styles.css

@@ -1,4 +0,0 @@
-.App {
-  font-family: sans-serif;
-  text-align: center;
-}

+ 0 - 45
src/components/main/new/styles.scss

@@ -1,45 +0,0 @@
-// .App {
-//     font-family: sans-serif;
-//     text-align: center;
-// }
-
-// .handle {
-//     display: block;
-//     width: 18px;
-//     height: 18px;
-//     margin-right: 20px;
-//     overflow: hidden;
-
-//     > svg {
-//         opacity: 0.3;
-//     }
-
-//     cursor: grab;
-// }
-// .qq {
-//     float: left;
-//     padding-left: 8px;
-//     padding-right: 8px;
-//     width: calc(25% - 16px);
-//     .content {
-//         padding: 8px 12px;
-//         background-color: #ddd;
-//         height: 150px;
-//         background-color: blue;
-//     }
-// }
-// .ww {
-//     background-color: #ddd;
-//     margin-left: -8px;
-//     margin-right: -8px;
-//     white-space: nowrap;
-//     &:after {
-//         content: "";
-//         clear: both;
-//         display: table;
-//     }
-// }
-// .rrr {
-//     width: 600px;
-//     margin: 0 auto;
-// }

+ 32 - 0
src/components/main/post/PostTitle.js

@@ -0,0 +1,32 @@
+import { Col, Row, Button, Dropdown, Menu } from 'antd'
+import { MoreOutlined } from '@ant-design/icons'
+import { Link } from 'react-router-dom'
+import { connect } from 'react-redux'
+import { UserAvatar } from '../../../pages/Header'
+
+const MenuOverlay = ({ postId }) =>
+    <Menu>
+        <Menu.Item>
+            <Link to={`/edit/post/${postId}`}> Edit post</Link>
+        </Menu.Item>
+    </Menu >
+
+export const PostTitle = ({ owner, myID, postId }) =>
+    <Row justify="space-between" align='middle'>
+        <Col>
+            <Link to={`/profile/${owner?._id}`} className='owner'>
+                <UserAvatar avatar={owner?.avatar} avatarSize={'45px'} />
+                <span className='nick'>{owner?.nick ? owner.nick : owner?.login ? owner.login : 'Null'}</span>
+            </Link >
+        </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>}
+    </Row>
+
+
+
+export const CPostTitle = connect(state => ({ myID: state?.auth?.payload?.sub?.id || '' }))(PostTitle)

+ 2 - 4
src/components/main/postsFeed/PostUserPanel.jsx

@@ -20,15 +20,13 @@ const HeartLike = ({ styleFontSize, likeStatus, changeLike }) =>
 
 const PostUserPanel = ({ myID, postId = '', likes = [], styleFontSize, addLikePost, removeLikePost }) => {
     const [open, setOpen] = useState(false)
-    let likeStatus
+    let likeStatus =false
     let likeId
     likes.find(l => {
         if (l?.owner?._id === myID) {
             likeStatus = true
             likeId = l._id
-        } else {
-            likeStatus = false
-        }
+        } 
     })
 
     const changeLike = () => likeStatus ? removeLikePost(likeId, postId) : addLikePost(postId)

+ 71 - 0
src/components/uploadPhoto/EditDescriptionPost.js

@@ -0,0 +1,71 @@
+import { EditOutlined } from "@ant-design/icons";
+import { Button, Divider } from "antd";
+import TextArea from "antd/lib/input/TextArea";
+import Paragraph from "antd/lib/typography/Paragraph";
+import Text from "antd/lib/typography/Text";
+import Title from "antd/lib/typography/Title";
+import { useEffect, useState } from "react";
+
+
+
+export const EditDescriptionPost = ({ description, setDescription }) => {
+    const [text, setText] = useState(description || 'Enter descriptin');
+    const [error, setError] = useState(false)
+    const [editMode, setEditMode] = useState(false)
+
+    useEffect(() => {
+        setText(description || 'Enter descriptin')
+    }, [description]);
+    
+
+    const addTaskHandler = () => {
+        if (text.trim() !== '') {
+            setDescription(text)
+            setEditMode(false)
+        } else {
+            setError(true)
+            setDescription('')
+        }
+    }
+    const textInputHandler = () => {
+        setEditMode(true)
+    }
+
+    const textInputHandlerClose = () => {
+        addTaskHandler()
+    }
+
+    const onChangeTask = (e) => {
+        setText(e.currentTarget.value)
+        setError(false)
+    }
+
+    const onKeyPressAddTask = (e) => {
+        if (e.shiftKey && e.charCode === 13) {
+            setText(text += `'\n'`)
+        } else if (e.charCode === 13) {
+            addTaskHandler()
+        }
+    }
+    return (
+        <>
+            <Divider orientation="left" orientationMargin="0">
+                <Title level={3}>Description
+                    <Button type="link" onClick={textInputHandler}><EditOutlined /></Button></Title>
+            </Divider>
+            {error && <Text type="danger">Field must not be empty</Text>}
+            {editMode
+                ? <TextArea
+                    placeholder="Description"
+                    autoSize={{ minRows: 3, maxRows: 5 }}
+                    value={text}
+                    onChange={onChangeTask}
+                    autoFocus onBlur={textInputHandlerClose}
+                    onKeyPress={onKeyPressAddTask}
+                />
+                : <Paragraph className="description" onDoubleClick={textInputHandler}>
+                    {text}
+                </Paragraph>
+            }
+        </>)
+}

+ 67 - 0
src/components/uploadPhoto/EditTitlePost.js

@@ -0,0 +1,67 @@
+import { EditOutlined } from "@ant-design/icons"
+import { Button, Divider, Input } from "antd"
+import Text from "antd/lib/typography/Text"
+import Title from "antd/lib/typography/Title"
+import { useEffect, useState } from "react"
+
+
+
+
+export const EditTitlePost = ({ titleSend, setTitleSend }) => {
+
+    const [title, setTitle] = useState(titleSend || 'Enter title')
+    const [error, setError] = useState(false)
+    const [editMode, setEditMode] = useState(false)
+    useEffect(() => {
+        setTitle(titleSend || 'Enter title')
+    }, [titleSend]);
+
+    const addTaskHandler = () => {
+        if (title.trim() !== '') {
+            setTitleSend(title.trim())
+            setEditMode(false)
+        } else {
+            setError(true)
+            setTitleSend('')
+        }
+    }
+    const titleInputHandler = () => {
+        setEditMode(true)
+    }
+
+    const titleInputHandlerClose = () => {
+        addTaskHandler()
+    }
+
+    const onChangeTask = (e) => {
+        setTitle(e.currentTarget.value)
+        setError(false)
+    }
+
+    const onKeyPressAddTask = (e) => {
+        if (e.charCode === 13) {
+            addTaskHandler()
+        }
+    }
+    return (
+        <>
+            <Divider orientation="left" orientationMargin="0">
+                <Title level={3}>Title
+                    <Button type="link" onClick={titleInputHandler}><EditOutlined /></Button></Title>
+            </Divider>
+            {error && <Text type="danger">Field must not be empty</Text>}
+            {editMode
+                ? <Input
+                    value={title}
+                    placeholder="title"
+                    onChange={onChangeTask}
+                    autoFocus onBlur={titleInputHandlerClose}
+                    onKeyPress={onKeyPressAddTask}
+                />
+                : <Title level={5} onDoubleClick={titleInputHandler}>
+                    {title}
+                </Title>
+            }
+   
+        </>)
+}

+ 25 - 9
src/components/uploadPhoto/index.js

@@ -1,5 +1,5 @@
 import { DeleteOutlined, EyeOutlined, InboxOutlined, LoadingOutlined, PlusOutlined } from "@ant-design/icons";
-import { Button, message, Icon, Upload, Image } from "antd";
+import { Button, message, Icon, Upload, Image, Progress } from "antd";
 import Dragger from "antd/lib/upload/Dragger";
 import React, { useState } from "react";
 import ReactDOM from "react-dom";
@@ -45,7 +45,13 @@ const Handle = SortableHandle(({ tabIndex, value, removePhotosItem }) => {
     )
 })
 
-
+//     < Progress
+// strokeColor = {{
+//     '0%': '#108ee9',
+//         '100%': '#87d068',
+//       }}
+// percent = { 99.9}
+//     />
 const SortableItem = SortableElement(props => {
     const { value, removePhotosItem } = props
     return (
@@ -61,7 +67,7 @@ const props = {
     headers: localStorage.authToken || sessionStorage.authToken ? { Authorization: 'Bearer ' + (localStorage.authToken || sessionStorage.authToken) } : {},
 }
 
-const SortableList = SortableContainer(({ items,...restProps }) => {
+const SortableList = SortableContainer(({ items, ...restProps }) => {
     return (
         <div className='SortableList'>
             {items.map((item, index) => (
@@ -78,24 +84,28 @@ const SortableList = SortableContainer(({ items,...restProps }) => {
 
 
 export function EditPhotos({ photos, setPhotos }) {
-
+    const [progress, setProgress] = useState(0);
+    const [loading, setLoading] = useState(false);
     const handlerChange = async ({ file }) => {
-        if (file.status === 'done') {
-
-            setPhotos([...photos, file.response])
+        if (file.status === "uploading") {
+            setLoading(true)
+            setProgress(file.percent)
+        } else if (file.status === 'done') {
             message.success(`${file.name} file uploaded successfully`);
+            setPhotos([...photos, file.response])
         } else if (file.status === 'error') {
             message.error(`${file.name} file upload failed.`);
         }
     }
     const removePhotosItem = (id) => setPhotos(photos.filter(p => p._id !== id))
-
     const onSortEnd = ({ oldIndex, newIndex }) => {
         setPhotos(arrayMove(photos, oldIndex, newIndex));
     };
 
     return (
         <div className="EditPhotos" >
+
+
             {photos.length >= 8 ? null
                 : <Dragger {...props} className="EditPhotos__box"
                     multiple={true}
@@ -108,7 +118,13 @@ export function EditPhotos({ photos, setPhotos }) {
                     <p className="ant-upload-text">Click or drag file to this area to upload</p>
                 </Dragger>
             }
-            <></>
+            {loading && < Progress showInfo={false} percent={progress}
+                strokeColor={{
+                    '0%': '#10136c',
+                    '50%': '#755596',
+                    '100%': '#fdc229',
+                }}
+            />}
             <SortableList
                 shouldUseDragHandle={true}
                 useDragHandle

+ 5 - 2
src/pages/AllPosts.jsx

@@ -1,7 +1,8 @@
 import React, { useEffect, useState } from 'react';
 import { connect } from 'react-redux';
 import { actionAllPosts, actionRemovePostsFeedAC } from '../actions';
-import { CPosts } from '../components/Posts';
+import { CPosts } from '../components/main/Posts';
+import { Container } from './Content';
 
 const AllPosts = ({ posts, onAllPosts, postsRemove }) => {
     const [checkScroll, setCheckScroll] = useState(true)
@@ -28,7 +29,9 @@ const AllPosts = ({ posts, onAllPosts, postsRemove }) => {
     }
 
     return (
-        <CPosts />
+        <Container>
+            <CPosts />
+        </Container>
     )
 }
 

+ 53 - 139
src/pages/EntityEditorPost.jsx

@@ -1,166 +1,80 @@
-import { EditOutlined } from "@ant-design/icons"
-import { Button, Divider, Input } from "antd"
-import TextArea from "antd/lib/input/TextArea"
-import Paragraph from "antd/lib/typography/Paragraph"
-import Text from "antd/lib/typography/Text"
+import { Button, Divider, Input, message } from "antd"
 import Title from "antd/lib/typography/Title"
 import { useEffect, useState } from "react"
 import { connect } from "react-redux"
-import { actionSentPost, actionsentPostAC } from "../actions"
+import { actionFindPostOne, actionFullSentPost, actionRemovePostsFeedAC } from "../actions"
 import { EditPhotos } from "../components/uploadPhoto"
+import { EditDescriptionPost } from "../components/uploadPhoto/EditDescriptionPost"
+import { EditTitlePost } from "../components/uploadPhoto/EditTitlePost"
+import { Container } from "./Content"
+import { history } from '../App'
 
 
-const ContainEditorPost = ({ children }) =>
-    <div className='ContainErditorPost'>{children}</div>
-
 
-const EditTitlePost = ({ titleSend, setTitleSend }) => {
-    const [title, setTitle] = useState(titleSend || 'Enter title')
-    const [error, setError] = useState(false)
-    const [editMode, setEditMode] = useState(false)
 
-    const addTaskHandler = () => {
-        if (title.trim() !== '') {
-            setTitleSend(title.trim())
-            setEditMode(false)
-        } else {
-            setError(true)
-            setTitleSend('')
-        }
-    }
-    const titleInputHandler = () => {
-        setEditMode(true)
-    }
-
-    const titleInputHandlerClose = () => {
-        addTaskHandler()
-    }
+const ContainEditorPost = ({ children }) =>
+    <div className='ContainEditorPost'>{children}</div>
 
-    const onChangeTask = (e) => {
-        setTitle(e.currentTarget.value)
-        setError(false)
-    }
 
-    const onKeyPressAddTask = (e) => {
-        if (e.charCode === 13) {
-            addTaskHandler()
-        }
-    }
-    return (
-        <>
-            <Divider orientation="left" orientationMargin="0">
-                <Title level={3}>Title
-                    <Button type="link" onClick={titleInputHandler}><EditOutlined /></Button></Title>
-            </Divider>
-            {error && <Text type="danger">Field must not be empty</Text>}
-            {editMode
-                ? <Input
-                    value={title}
-                    placeholder="title"
-                    onChange={onChangeTask}
-                    // className={s.input + ' ' + (error && s.error)}
-                    autoFocus onBlur={titleInputHandlerClose}
-                    onKeyPress={onKeyPressAddTask}
-                />
-                : <Title level={5} onDoubleClick={titleInputHandler}>
-                    {title}
-                </Title>
-            }
-        </>)
-}
 
 
-const EditDescriptionPost = ({ description, setDescription }) => {
-    const [text, setText] = useState(description || 'Enter descriptin');
-    const [error, setError] = useState(false)
-    const [editMode, setEditMode] = useState(false)
 
 
-    const addTaskHandler = () => {
-        if (text.trim() !== '') {
-            setDescription(text)
-            setEditMode(false)
-        } else {
-            setError(true)
-            setDescription('')
-        }
-    }
-    const textInputHandler = () => {
-        setEditMode(true)
-    }
+const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, onSave, findPostOne, clearState }) => {
+    const [photos, setPhotos] = useState(entity?.images || []);
+    const [titleSend, setTitleSend] = useState(entity?.title || '')
+    const [description, setDescription] = useState(entity?.text || '');
 
-    const textInputHandlerClose = () => {
-        addTaskHandler()
-    }
+    useEffect(() => {
+        if (_id !== 'new')
+            findPostOne(_id)
+        return () => {
+            clearState()
+        };
+    }, []);
 
-    const onChangeTask = (e) => {
-        setText(e.currentTarget.value)
-        setError(false)
-    }
+    useEffect(() => {
+        setPhotos(entity?.images || [])
+        setTitleSend(entity?.title || '')
+        setDescription(entity?.text || '')
+    }, [entity]);
 
-    const onKeyPressAddTask = (e) => {
-        if (e.shiftKey && e.charCode === 13) {
-            setText(text += `'\n'`)
-        } else if (e.charCode === 13) {
-            addTaskHandler()
+    useEffect(() => {
+        if (status === "RESOLVED") {
+            message.success(`post published, can create a new one`)
+            history.push(`/profile/${myID}`)
         }
-    }
-    return (
-        <>
-            <Divider orientation="left" orientationMargin="0">
-                <Title level={3}>Description
-                    <Button type="link" onClick={textInputHandler}><EditOutlined /></Button></Title>
-            </Divider>
-            {error && <Text type="danger">Field must not be empty</Text>}
-            {editMode
-                ? <TextArea
-                    placeholder="Description"
-                    autoSize={{ minRows: 3, maxRows: 5 }}
-                    value={text}
-                    onChange={onChangeTask}
-                    autoFocus onBlur={textInputHandlerClose}
-                    onKeyPress={onKeyPressAddTask}
-                />
-                : <Paragraph className="description" onDoubleClick={textInputHandler}>
-                    {text}
-                </Paragraph>
-            }
-        </>)
-}
-
-const EntityEditorPost = ({ entity = { array: [] }, onSave }) => {
+    }, [status])
+    const disabledBtn = photos.length && titleSend && description ? false : true
 
-    const [photos, setPhotos] = useState([]);
-    const [titleSend, setTitleSend] = useState('')
-    const [description, setDescription] = useState('');
-    //  photos.length && titleSend && description ? : true
-    const disabledBtn = false
     const sentPost = () => {
-        const [newphotos ]= photos.map(ph => {
-            return { _id: ph._id }
-        })
-
+        onSave(photos, titleSend, description)
 
-        onSave(newphotos, titleSend, description);
     }
-    // const sentPost = () => {
-    //     const newphotos = photos.map(ph => {
-    //         return { _id: ph._id }
-    //     })
 
-    //     console.log(result)
-
-    // }
     return (
-        <ContainEditorPost>
-            <h1 className="title" level={1}>Create / edit Post</h1>
-            <Divider orientation="left" orientationMargin="0"><Title level={3}>Photos</Title></Divider>
-            <EditPhotos photos={photos} setPhotos={setPhotos} />
-            <EditTitlePost titleSend={titleSend} setTitleSend={setTitleSend} />
-            <EditDescriptionPost description={description} setDescription={setDescription} />
-            <Divider orientation="right">   <Button disabled={disabledBtn} type="primary" onClick={sentPost}>Send a Post</Button></Divider>
-        </ContainEditorPost>
+        <Container >
+            <ContainEditorPost>
+                <h1 className="title" level={1}>Create / edit Post</h1>
+                <Divider orientation="left" orientationMargin="0"><Title level={3}>Photos</Title></Divider>
+                <EditPhotos photos={photos} setPhotos={setPhotos} />
+                <EditTitlePost titleSend={titleSend} setTitleSend={setTitleSend} />
+                <EditDescriptionPost description={description} setDescription={setDescription} />
+                <Divider orientation="right">   <Button disabled={disabledBtn} type="primary" onClick={sentPost}>Send a Post</Button></Divider>
+            </ContainEditorPost>
+        </ Container>
     )
 }
 
-export const CEntityEditorPost = connect(null, { onSave: actionSentPost })(EntityEditorPost)
+export const CEntityEditorPost = connect(state => ({
+    myID: state?.auth?.payload?.sub?.id,
+    entity: state?.postsFeed?.posts,
+    status: state?.promise?.sentPost?.status
+}),
+    {
+        onSave: actionFullSentPost,
+        findPostOne: actionFindPostOne,
+        clearState: actionRemovePostsFeedAC,
+    })(EntityEditorPost)
+
+

+ 2 - 2
src/pages/Header.jsx

@@ -38,7 +38,7 @@ const ProfileDropMenu = ({ myID, onLogOut }) =>
             <Link to={`/profile/${myID}`}><UserOutlined /> My Profile</Link>
         </Menu.Item>
         <Menu.Item key={'1'}>
-            <Link to={'/'}><SettingOutlined /> Settings</Link>
+            <Link to={'/my-settigs'}><SettingOutlined /> Settings</Link>
         </Menu.Item>
         <Menu.Divider />
         <Menu.Item key={'2'}>
@@ -58,7 +58,7 @@ const UserNavIcon = ({ userData: { _id, avatar, login } }) =>
             <Link to='/message'><MessageOutlined /></Link>
         </Col>
         <Col >
-            <Link to='/add'><PlusCircleOutlined /></Link>
+            <Link to='/edit/post/new'><PlusCircleOutlined /></Link>
         </Col>
         <Col >
             <Link to='/all'><CompassOutlined /></Link>

+ 14 - 21
src/pages/MainPostsFeed.jsx

@@ -2,21 +2,14 @@ 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 { UserAvatar } from './Header'
 import Paragraph from 'antd/lib/typography/Paragraph'
 import Text from 'antd/lib/typography/Text'
 import { actionPostsFeed, actionRemovePostsFeedAC } from '../actions'
 import { DateCreated } from '../components/main/DateCreated'
 import PostImage from '../components/main/postsFeed/PostImage'
 import { CPostUserPanel } from '../components/main/postsFeed/PostUserPanel'
-
-export const PostTitle = ({ owner }) =>
-    <Row justify="start" align='middle'>
-        <Link to={`/profile/${owner?._id}`} className='owner'>
-            <UserAvatar avatar={owner?.avatar} avatarSize={'45px'} />
-            <span className='nick'>{owner?.nick ? owner.nick : owner?.login ? owner.login : 'Null'}</span>
-        </Link >
-    </Row>
+import { Container } from './Content'
+import { CPostTitle } from '../components/main/post/PostTitle'
 
 
 export const PostDescription = ({ title, description, date }) =>
@@ -31,22 +24,22 @@ export const PostDescription = ({ title, description, date }) =>
                 </Text>
             </Col>
         </Row>
-        <Paragraph ellipsis={true ? { rows: 1, expandable: true, symbol: '...' } : false}>
+        <Paragraph ellipsis={true ? { rows: 1, expandable: true, symbol: '...More' } : false}>
             {description}
         </Paragraph>
     </>
 
 export const Comments = ({ comments = [], _id }) =>
-        <Link to={`/post/${_id}`}>
-            <Divider orientation="left">
-                {comments?.length ? `View ${comments.length} comments` : 'No comments'}
-            </Divider>
-        </Link>
+    <Link to={`/post/${_id}`}>
+        <Divider orientation="left">
+            {comments?.length ? `View ${comments.length} comments` : 'No comments'}
+        </Divider>
+    </Link>
 
 const Post = ({ postData: { _id, text, title, owner, images, createdAt = '', comments, likes } }) =>
     <div className='Post'>
         <Card
-            title={<PostTitle owner={owner} />}
+            title={<CPostTitle owner={owner} postId={_id}/>}
             cover={<PostImage images={images} />}
         >
             <CPostUserPanel postId={_id} likes={likes} styleFontSize='1.7em' />
@@ -56,7 +49,7 @@ const Post = ({ postData: { _id, text, title, owner, images, createdAt = '', com
     </div>
 
 
-const MainPostsFeed = ({ posts, postsFollowing, postsFollowingRemove, following }) => {
+const MainPostsFeed = ({ posts, postsFollowing, clearState, following }) => {
 
     const [checkScroll, setCheckScroll] = useState(true)
 
@@ -71,7 +64,7 @@ const MainPostsFeed = ({ posts, postsFollowing, postsFollowingRemove, following
         document.addEventListener('scroll', scrollHandler)
         return () => {
             document.removeEventListener('scroll', scrollHandler)
-            postsFollowingRemove()
+            clearState()
 
         }
     }, [])
@@ -83,9 +76,9 @@ const MainPostsFeed = ({ posts, postsFollowing, postsFollowingRemove, following
     }
 
     return (
-        <>
+        <Container>
             {Array.isArray(posts) && posts.map(p => <Post key={p._id} postData={p} />)}
-        </>
+        </Container>
     )
 }
 
@@ -94,5 +87,5 @@ export const CMainPostsFeed = connect(state => ({
     following: state?.myData.following || []
 }), {
     postsFollowing: actionPostsFeed,
-    postsFollowingRemove: actionRemovePostsFeedAC,
+    clearState: actionRemovePostsFeedAC,
 })(MainPostsFeed)

+ 4 - 3
src/pages/PostPage.jsx

@@ -12,12 +12,13 @@ import { UserAvatar } from './Header';
 import { Link } from 'react-router-dom';
 import { LikeFilled, LikeOutlined } from '@ant-design/icons';
 import { actionLikeComment, actionDelLikeComment, actionSubComment } from '../actions';
+import { CPostTitle } from '../components/main/post/PostTitle';
 
 
-const PostPageTitle = ({ data: { owner } }) =>
-    <PostTitle owner={owner} />
+const PostPageTitle = ({ data: { owner }, postId }) =>
+    <CPostTitle owner={owner} postId={postId} />
 
-const CPostPageTitle = connect(state => ({ data: state?.postsFeed?.posts || {} }))(PostPageTitle)
+const CPostPageTitle = connect(state => ({ data: state?.postsFeed?.posts || {}, postId: state?.postsFeed?.posts?._id }))(PostPageTitle)
 
 
 const PostCommentAuthor = ({ owner }) => {

+ 25 - 23
src/pages/ProfilePage.jsx

@@ -1,22 +1,19 @@
 import React, { useEffect, useState } from 'react'
-import { Button, Card, Col, Row } from 'antd'
+import { Button, Col, Row } from 'antd'
 import { connect } from 'react-redux'
 import { Link } from 'react-router-dom'
-import {  actionProfilePageData, actionRemovePostsFeedAC, actionSubscribe, actionUnSubscribe } from '../actions'
+import { actionProfilePageData, actionRemovePostsFeedAC, actionSubscribe, actionUnSubscribe } from '../actions'
 import { UserAvatar } from './Header'
 import { CModalFollowers, CModalFollowing } from '../components/main/profilePage/ModalFollow'
 import { DateCreated } from '../components/main/DateCreated'
 import Text from 'antd/lib/typography/Text'
-import { CPosts, CProfilePagePosts } from '../components/Posts'
+import { Container } from './Content'
+import { CPosts } from '../components/main/Posts'
 
-
-
-
-
-const ProfileFollow = ({ myID, userId, followers, onSubsuscribe, onUnSubsuscribe }) => {
+const ProfileFollowButton = ({ myID, userId, followers, onSubsuscribe, onUnSubsuscribe }) => {
     const followCheck = followers.find(f => f._id === myID && true)
     return (
-        <Col className='Profile__seting' offset={4}>
+        <Col className='Profile__setting'>
             {!!followCheck ?
                 <Button onClick={() => onUnSubsuscribe(userId)}>UnSubscribe</Button> :
                 <Button onClick={() => onSubsuscribe(userId)} type="primary">Subscribe</Button>}
@@ -24,34 +21,36 @@ const ProfileFollow = ({ myID, userId, followers, onSubsuscribe, onUnSubsuscribe
     )
 }
 
-const CProfileSetting = connect(state => ({
+const CProfileFollowButton = connect(state => ({
     myID: state?.auth?.payload?.sub.id,
     followers: state?.postsFeed?.userData?.followers || []
-}), { onSubsuscribe: actionSubscribe, onUnSubsuscribe: actionUnSubscribe })(ProfileFollow)
+}), { onSubsuscribe: actionSubscribe, onUnSubsuscribe: actionUnSubscribe })(ProfileFollowButton)
 
 
-const ProfilePageData = ({ data: { _id, avatar, login, nick, createdAt = '', followers, following }, count, setFollowing, setFollowers }) =>
+const ProfilePageData = ({ myID, data: { _id, avatar, login, nick, createdAt = '', followers, following }, count, setFollowing, setFollowers }) =>
     <Row className='Profile' >
-        <Col span={8}>
+        <Col flex={'150px'}>
             <UserAvatar avatarSize={'150px'} avatar={avatar} />
         </Col>
-        <Col span={14} offset={1}>
-            <Row align='top' className='Profile__name'>
+        <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>
-                    <CProfileSetting userId={_id} />
+                <Col >
+                    {myID !== _id
+                        ? <CProfileFollowButton userId={_id} />
+                        : <Button type=''><Link to={`/my-settings`}>Settings</Link></Button>}
                 </Col>
             </Row>
-            <Row align='middle'>
-                <Col >
+            <Row align='middle' justify='space-between'>
+                <Col className='Profile__created'>
                     <Text type='secondary'>Account created: <DateCreated date={createdAt} /></Text>
                 </Col>
-                <Col offset={2}>
+                {myID !== _id && <Col offset={1}>
                     <Link className='Profile__link-message' to='/message'>Send message</Link>
-                </Col>
+                </Col>}
             </Row>
             <Row className='Profile__count' align='middle' justify='space-between'>
                 <Col >
@@ -74,7 +73,9 @@ const ProfilePageData = ({ data: { _id, avatar, login, nick, createdAt = '', fol
         </Col >
     </Row >
 
+
 const CProfilePageData = connect(state => ({
+    myID: state.auth.payload.sub.id || '',
     data: state?.postsFeed?.userData || {},
     count: state?.postsFeed?.count || null
 }))(ProfilePageData)
@@ -87,6 +88,7 @@ const ProfilePage = ({ match: { params: { _id } }, getProfileUser, clearDataProf
     const [following, setFollowing] = useState(false)
     const [checkScroll, setCheckScroll] = useState(true)
 
+
     useEffect(() => {
         document.addEventListener('scroll', scrollHandler)
         return () => {
@@ -111,12 +113,12 @@ const ProfilePage = ({ match: { params: { _id } }, getProfileUser, clearDataProf
     }
 
     return (
-        <>
+        <Container>
             <CProfilePageData setFollowing={setFollowing} setFollowers={setFollowers} />
             {followers && < CModalFollowers statusModal={setFollowers} title={'Followers'} />}
             {following && < CModalFollowing statusModal={setFollowing} title={'Following'} />}
             <CPosts />
-        </>
+        </Container>
     )
 }
 

+ 6 - 3
src/redux/reducers/postFeed-reducer.js

@@ -2,17 +2,19 @@ import React from 'react'
 
 export const postsFeedReducer = (state = {}, { type, findId, newResult, userData = {}, count = null }) => {
     const { posts } = state
+
     const types = {
         'ADD-POSTS-FEED': () => {
             return {
                 ...state,
-                posts: !!posts ? [...posts, ...newResult] : [...newResult],
+                posts: Array.isArray(posts) === Array.isArray(newResult)
+                    ? [...posts, ...newResult]
+                    : { ...posts, ...newResult },
                 count
             }
         },
         'GET-POST': () => {
             return { ...state, posts: { ...newResult } }
-
         },
         'ADD-PROFILE-DATA': () => {
             return {
@@ -28,7 +30,8 @@ export const postsFeedReducer = (state = {}, { type, findId, newResult, userData
                 posts: [],
                 userData: {},
                 count: 0,
-                subComments: {}
+                subComments: {},
+                editPost: {}
             }
         },
         'ADD-POST-LIKE': () => {

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

@@ -5,6 +5,11 @@ export function promiseReducer(state = {}, { type, status, payload, error, name
             ...state,
             [name]: { status, payload, error }
         }
+    } else if (type === 'CLEAR-PROMISE') {
+        return {
+            ...state,
+            [name]: {}
+        }
     }
     return state;
 }

Різницю між файлами не показано, бо вона завелика
+ 26 - 4
src/redux/saga/index.js