3 Commits 5cd754ac44 ... d642a71e7c

Autor SHA1 Mensagem Data
  makstravm d642a71e7c added view video, edited redux edit page post 2 anos atrás
  makstravm a306007125 Merge branch 'master' of https://github.com/makstravm/SocialGram 2 anos atrás
  Maksym 85f887e74e Merge pull request #1 from makstravm/saga 2 anos atrás

+ 24 - 3
src/App.scss

@@ -55,7 +55,11 @@ body {
     background-color: #f9f9f9;
     color: $defaultColorB;
 }
-
+video {
+    width: 100%;
+    margin: 0 auto;
+    max-height: 500px;
+}
 .Header {
     display: flex;
     background-color: #ececec;
@@ -201,6 +205,8 @@ body {
         width: 100%;
         margin: 0 auto;
         padding: 1px;
+        max-height: 600px;
+        object-fit: contain;
     }
     &__dots.slick-dots {
         bottom: -14px;
@@ -316,6 +322,7 @@ body {
     }
     li {
         padding-left: 35px;
+        padding-right: 35px;
     }
 }
 
@@ -381,7 +388,8 @@ body {
         div {
             padding: 0;
         }
-        img {
+        img,
+        video {
             width: 100%;
             height: 100%;
             max-height: 175px;
@@ -396,6 +404,17 @@ body {
             top: 0;
             right: 0;
         }
+        &-icon--video {
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            font-size: 2.5em;
+            svg {
+                fill: $defaultColorW;
+                stroke: $defaultColorB;
+            }
+        }
     }
 }
 
@@ -518,6 +537,7 @@ body {
     border-radius: 4px;
     background-color: rgba($defaultColorB, 0.5);
     opacity: 0;
+    z-index: 2;
     transition: 0.3s;
     button {
         svg {
@@ -536,7 +556,8 @@ body {
         align-items: center;
         justify-content: center;
         box-shadow: 0 0 6px 2px rgba($defaultColorB, 0.3);
-        img {
+        img,
+        video {
             width: 100%;
             object-fit: cover;
             max-height: 150px;

+ 1 - 1
src/actions/actionQueries.js

@@ -4,7 +4,7 @@ export const queries = {
         query: `query post($id:String!) {
                     PostFindOne(query:$id) {
                         _id createdAt title text 
-                        images{_id url text}
+                        images{_id url originalFileName}
                         comments {
                             _id createdAt text 
                             likes { _id owner {_id}}   

+ 17 - 18
src/actions/index.js

@@ -36,7 +36,6 @@ export const actionRegister = (login, password) =>
 
 
 export const actionAboutMeAC = (data) => ({ type: 'ABOUTME-DATA-ADD', data })
-
 export const actionFullAboutMe = () => ({ type: 'ABOUT_ME' })
 
 export const actionFullAboutMeUpsert = (nick, login) => ({ type: 'ABOUT_ME_UPSERT', nick, login })
@@ -75,7 +74,7 @@ export const actionPostsMyFollowing = (skip, myFollowing) =>
                 _id, text, title
                 owner{_id, nick, login, avatar {url}}
                 likes { _id owner {_id}}   
-                images{url _id}
+                images{ url _id originalFileName }
                 comments{_id}
                 createdAt
         }
@@ -103,7 +102,7 @@ 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 actionFindPostOne = (_id) => ({ type: 'FIND_POST_ONE', _id })
 
 export const actionProfileData = (_id) =>
     actionPromise('userOneData', gql(` query userOned($id:String!){
@@ -118,7 +117,7 @@ export const actionProfileData = (_id) =>
 
 export const actionProfilePagePost = (_id, skip) => actionPromise('userOneDataPosts', gql(` query userOned($id:String!){
                 PostFind(query:$id){
-                    _id   images{url _id}
+                    _id   images{ url _id originalFileName }
                 }
                 }`, {
     id: JSON.stringify([{
@@ -131,16 +130,6 @@ 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' })
@@ -148,7 +137,7 @@ export const actionAllPosts = () => ({ type: 'ALL_POSTS' })
 export const actionGetAllPosts = (skip) =>
     actionPromise('allPosts', gql(` query allPosts($id:String!){
                 PostFind(query:$id){
-                    _id   images{url _id}
+                    _id   images{url _id originalFileName}
                 }
             }`, {
         id: JSON.stringify([{}, {
@@ -359,7 +348,6 @@ export const actionGetAvatar = (id) =>
         }
     }`, { myID: JSON.stringify([{ _id: id }]) }))
 
-
 //****************--- Find FOllowing/Follovwrs---*************************//
 
 export const actionFindFollowing = (_id) => ({ type: 'FIND_FOLLOWING', _id })
@@ -372,6 +360,7 @@ export const actionGetFindFollowing = (_id) =>
                             following {
                                 _id nick login
                                 avatar { _id url }
+                                followers{_id}
                             }
                 }
             } `, { id: JSON.stringify([{ _id }]) }))
@@ -382,6 +371,7 @@ export const actionGetFindFollowers = (_id) =>
                             followers {
                                 _id  nick login
                                 avatar { _id url }
+                                followers{_id}
                             }
                 }
             } `, { id: JSON.stringify([{ _id }]) }))
@@ -403,6 +393,15 @@ export const actionFullSentPost = (images, title, text) => ({ type: 'CREATE_POST
 export const actionSentPost = (upSertPostObj) =>
     actionPromise('sentPost', gql(`mutation sentPost($post: PostInput){
               PostUpsert(post: $post){
-                    _id images{_id url}
+                    _id images{_id url originalFileName}
                 }
-            }`, { post: upSertPostObj }))
+            }`, { post: upSertPostObj }))
+
+
+
+
+        //запросить все коменты этого псота с ансвер (айди)
+        // по ансверс.файди найти дочерные коменты и засунуть в массив ансверс как елементы
+        // таким оюразом получтьь дерево
+        // отдать в рекувсивный компонкнт на отрисовку дерева.
+        // каждый лист дерева приконектить к экшонам лайк и добавление дочернего коммета.Там жк=е должен быть известен пост.айди для создания комментов

+ 17 - 13
src/components/main/Posts.jsx

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

+ 1 - 1
src/components/main/post/PostTitle.js

@@ -6,7 +6,7 @@ import { UserAvatar } from '../../header/UserAvatar'
 
 const MenuOverlay = ({ postId }) =>
     <Menu>
-        <Menu.Item>
+        <Menu.Item key={'1'}>
             <Link to={`/edit/post/${postId}`}> Edit post</Link>
         </Menu.Item>
     </Menu >

+ 18 - 15
src/components/main/postsFeed/PostImage.jsx

@@ -2,8 +2,7 @@ import { LeftCircleOutlined, RightCircleOutlined } from "@ant-design/icons";
 import { Carousel, Empty } from "antd";
 import React, { createRef } from "react";
 import nodata from '../../../images/nodata.png'
-import { backURL } from '../../../helpers/index'
-
+import { backURL, videoRegExp } from '../../../helpers/index'
 
 
 class PostImage extends React.Component {
@@ -43,19 +42,23 @@ class PostImage extends React.Component {
                 infinite={false}
                 dots={{ className: 'Post__dots' }
                 }>
-                {!!images ?
-                    images.map((i, index) => i?.url ? <div
-                        key={i._id}
-                        onMouseEnter={() => this.moveOnDivArray(images.length, index)}
-                        onMouseLeave={this.downOnDivArray}>
-                        <button onClick={() => this.handlePrev()}
-                            className={`Post__prev Post__btn ${this.state.movePrev ? '--active' : ''}`}><LeftCircleOutlined /></button>
-                        <button onClick={() => this.handleNext()}
-                            className={`Post__next Post__btn ${this.state.moveNext ? '--active' : ''}`}><RightCircleOutlined /></button>
-                        <img src={backURL + '/' + i.url} />
-                    </div> :
-                        <Empty key={i._id} image={nodata} description={false} />) :
-                    <Empty image={nodata} description={false} />
+                {!!images ? images.map((i, index) => i?.url ? <div
+                    key={i._id}
+                    onMouseEnter={() => this.moveOnDivArray(images.length, index)}
+                    onMouseLeave={this.downOnDivArray}>
+                    <button onClick={() => this.handlePrev()}
+                        className={`Post__prev Post__btn ${this.state.movePrev ? '--active' : ''}`}><LeftCircleOutlined /></button>
+                    <button onClick={() => this.handleNext()}
+                        className={`Post__next Post__btn ${this.state.moveNext ? '--active' : ''}`}><RightCircleOutlined /></button>
+                    {videoRegExp.test(i.originalFileName)
+                        ? <video controls loop preload="true" height="500">
+                            <source src={backURL + '/' + i.url} />
+                        </video>
+                        : <img src={backURL + '/' + i.url} />
+                    }
+                </div>
+                    : <Empty key={i._id} image={nodata} description={false} />)
+                    : <Empty image={nodata} description={false} />
                 }
             </Carousel >
         );

+ 7 - 2
src/components/uploadPhoto/EditPhotos.js

@@ -8,7 +8,7 @@ import {
     SortableElement,
     SortableHandle
 } from "react-sortable-hoc";
-import { backURL, propsUploadFile } from "../../helpers";
+import { backURL, propsUploadFile, videoRegExp } from "../../helpers";
 
 
 const SortableItemMask = ({ removePhotosItem, setVisible, id }) =>
@@ -27,7 +27,12 @@ const Handle = SortableHandle(({ tabIndex, value, removePhotosItem }) => {
     return (
         <div className="Handle" tabIndex={tabIndex} >
             <SortableItemMask id={value._id} setVisible={setVisible} removePhotosItem={removePhotosItem} />
-            <img src={`${backURL + '/' + value.url}`} alt="avatar" style={{ width: '100%' }} />
+            {videoRegExp.test(value.originalFileName)
+                ? <video controls loop preload="true" height="500">
+                    <source src={backURL + '/' + value.url} />
+                </video>
+                : <img src={backURL + '/' + value.url} />
+            } 
             <Image className="hidden-item"
                 width={200}
                 style={{ display: 'none' }}

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

@@ -34,7 +34,6 @@ export const EditTitlePost = ({ titleSend, setTitleSend }) => {
 
     const onKeyPressAdd = (e) => e.charCode === 13 && addValueHandler()
 
-
     return (
         <>
             <Divider orientation="left" orientationMargin="0">

+ 3 - 0
src/helpers/index.js

@@ -3,8 +3,11 @@ import { useEffect } from 'react';
 import { connect } from 'react-redux';
 import { Route } from 'react-router-dom';
 
+
 export const backURL = 'http://hipstagram.asmer.fs.a-level.com.ua'
 
+export const videoRegExp = (/\.(mp4|mov|avi|wmv|flv|flv|3gp|mpg)$/i)
+
 export const propsUploadFile = {
     name: 'photo',
     action: `${backURL}/upload`,

+ 10 - 16
src/pages/EntityEditorPost.jsx

@@ -1,8 +1,8 @@
-import { Button, Divider,  message } from "antd"
+import { Button, Divider, message } from "antd"
 import Title from "antd/lib/typography/Title"
 import { useEffect, useState } from "react"
 import { connect } from "react-redux"
-import { actionFindPostOne, actionFullSentPost, actionRemovePostsFeedAC } from "../actions"
+import { actionFullSentPost, } from "../actions"
 import { EditPhotos } from "../components/uploadPhoto/EditPhotos"
 import { EditDescriptionPost } from "../components/uploadPhoto/EditDescriptionPost"
 import { EditTitlePost } from "../components/uploadPhoto/EditTitlePost"
@@ -18,20 +18,16 @@ const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, on
     const [photos, setPhotos] = useState(entity?.images || []);
     const [titleSend, setTitleSend] = useState(entity?.title || '')
     const [description, setDescription] = useState(entity?.text || '');
-
     useEffect(() => {
-        if (_id !== 'new')
-            findPostOne(_id)
-        return () => {
-            clearState()
-        };
+        console.log();
+        if (Array.isArray(entity)) {
+            let newEntity = entity.find(e => e._id === _id)
+            setPhotos(newEntity?.images || [])
+            setTitleSend(newEntity?.title || '')
+            setDescription(newEntity?.text || '')
+        } else if (!Object.keys(entity = {}).length) history.push('/edit/post/new')
     }, []);
 
-    useEffect(() => {
-        setPhotos(entity?.images || [])
-        setTitleSend(entity?.title || '')
-        setDescription(entity?.text || '')
-    }, [entity]);
 
     useEffect(() => {
         if (status === "RESOLVED") {
@@ -59,11 +55,9 @@ const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, on
 
 export const CEntityEditorPost = connect(state => ({
     myID: state?.auth?.payload?.sub?.id,
-    entity: state?.postsFeed?.posts,
+    entity: state?.postsFeed.posts,
     status: state?.promise?.sentPost?.status
 }),
     {
         onSave: actionFullSentPost,
-        findPostOne: actionFindPostOne,
-        clearState: actionRemovePostsFeedAC,
     })(EntityEditorPost)

+ 1 - 1
src/pages/Header.jsx

@@ -48,7 +48,7 @@ const UserNavIcon = ({ userData: { _id, avatar, login } }) =>
             <Link to='/all'><CompassOutlined /></Link>
         </Col>
         <Col>
-            <Popover placement="bottomRight" content={<CProfileDropMenu myID={_id} />} trigger={'click'}>
+            <Popover placement="bottomRight" content={<CProfileDropMenu myID={_id} />} trigger={['focus', 'hover']}>
                 <></>
                 <UserAvatar avatar={avatar} login={login} avatarSize={'45px'} />
             </Popover>

+ 0 - 1
src/pages/MainPostsFeed.jsx

@@ -65,7 +65,6 @@ const MainPostsFeed = ({ posts, postsFollowing, clearState, following }) => {
         return () => {
             document.removeEventListener('scroll', scrollHandler)
             clearState()
-
         }
     }, [])
 

+ 1 - 1
src/pages/ProfilePage.jsx

@@ -21,7 +21,7 @@ const ProfileFollowButton = ({ myID, userId, followers, onSubsuscribe, onUnSubsu
     )
 }
 
-const CProfileFollowButton = connect(state => ({
+export const CProfileFollowButton = connect(state => ({
     myID: state?.auth?.payload?.sub.id,
     followers: state?.postsFeed?.userData?.followers || []
 }), { onSubsuscribe: actionSubscribe, onUnSubsuscribe: actionUnSubscribe })(ProfileFollowButton)

+ 1 - 1
src/pages/SettingsPage.jsx

@@ -24,7 +24,7 @@ const EditMyDataIput = ({ title, propValue, propHandler, check }) => {
 
     const addValueHandler = () => {
         const valid = /^[A-Z][a-z0-9_]{1,15}$/
-        if (valid.test(value)) {
+        if (!valid.test(value)) {
             propHandler(value)
             setEditMode(false)
             check(false)

+ 61 - 81
src/redux/reducers/postFeed-reducer.js

@@ -2,90 +2,70 @@ 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: Array.isArray(posts) === Array.isArray(newResult)
-                    ? [...posts, ...newResult]
-                    : { ...posts, ...newResult },
-                count
-            }
-        },
-        'GET-POST': () => {
-            return { ...state, posts: { ...newResult } }
-        },
-        'ADD-PROFILE-DATA': () => {
-            return {
-                ...state,
-                posts: !!posts ? [...posts, ...newResult] : [...newResult],
-                userData,
-                count
-            }
-        },
-        'REMOVE-POSTS-FEED': () => {
-            return {
-                ...state,
-                posts: [],
-                userData: {},
-                count: 0,
-                subComments: {},
-                editPost: {}
-            }
-        },
-        'ADD-POST-LIKE': () => {
-            return {
-                ...state,
-                posts: Array.isArray(posts)
-                    ? posts.map(p => p._id === findId ? p = { ...p, likes: [...newResult] } : p)
-                    : { ...state.posts, likes: [...newResult] },
-            }
-        },
-        'REMOVE-POST-LIKE': () => {
-            return {
-                ...state,
-                posts: Array.isArray(posts)
-                    ? posts.map(p => p._id === findId ? p = { ...p, likes: [...newResult] } : p)
-                    : { ...state.posts, likes: [...newResult] },
-            }
-        },
-        'ADD-COMMENT': () => {
-            return {
-                ...state,
-                posts: { ...state.posts, comments: [...newResult] }
-            }
-        },
-        'UPDATE-SUBCOMMENT': () => {
-            return {
-                ...state,
-                subComments: { ...state?.subComments, ...{ ['subComments#' + findId]: [...newResult] } }
-            }
-        },
-        'ADD-LIKE-COMMENT': () => {
-            return {
-                ...state,
-                posts: {
-                    ...state.posts,
-                    comments: posts.comments.map(c => c._id === findId ? c = { ...c, likes: [...newResult] } : c)
-                }
-            }
-        },
-        'REMOVE-LIKE-COMMENT': () => {
-            return {
-                ...state,
-                posts: {
-                    ...state.posts,
-                    comments: posts.comments.map(c => c._id === findId ? c = { ...c, likes: [...newResult] } : c)
-                }
+        'ADD-POSTS-FEED': () => ({
+            ...state,
+            posts: Array.isArray(posts) === Array.isArray(newResult)
+                ? [...posts, ...newResult]
+                : { ...posts, ...newResult },
+            count
+        }),
+        'GET-POST': () => ({ ...state, posts: { ...newResult } }),
+        'ADD-PROFILE-DATA': () => ({
+            ...state,
+            posts: !!posts ? [...posts, ...newResult] : [...newResult],
+            userData,
+            count
+        }),
+        'REMOVE-POSTS-FEED': () => ({
+            ...state,
+            posts: [],
+            userData: {},
+            count: 0,
+            subComments: {},
+            editPost: {}
+        }),
+        'ADD-POST-LIKE': () => ({
+            ...state,
+            posts: Array.isArray(posts)
+                ? posts.map(p => p._id === findId ? p = { ...p, likes: [...newResult] } : p)
+                : { ...state.posts, likes: [...newResult] },
+        }),
+        'REMOVE-POST-LIKE': () => ({
+            ...state,
+            posts: Array.isArray(posts)
+                ? posts.map(p => p._id === findId ? p = { ...p, likes: [...newResult] } : p)
+                : { ...state.posts, likes: [...newResult] },
+
+        }),
+        'ADD-COMMENT': () => ({
+            ...state, posts: { ...state.posts, comments: [...newResult] }
+
+        }),
+        'UPDATE-SUBCOMMENT': () => ({
+            ...state,
+            subComments: { ...state?.subComments, ...{ ['subComments#' + findId]: [...newResult] } }
+        }),
+        'ADD-LIKE-COMMENT': () => ({
+            ...state,
+            posts: {
+                ...state.posts,
+                comments: posts.comments.map(c => c._id === findId ? c = { ...c, likes: [...newResult] } : c)
+
             }
-        },
-        'UPDATE-FOLLOWERS': () => {
-            return {
-                ...state,
-                userData: { ...state.userData, followers: [...newResult] }
+        }),
+        'REMOVE-LIKE-COMMENT': () => ({
+            ...state,
+            posts: {
+                ...state.posts,
+                comments: posts.comments.map(c => c._id === findId ? c = { ...c, likes: [...newResult] } : c)
             }
-        }
+        }),
+        'UPDATE-FOLLOWERS': () => ({
+            ...state,
+            userData: { ...state.userData, followers: [...newResult] }
+        })
+
     }
     if (type in types) {
         return types[type]()

Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 13
src/redux/saga/index.js