Преглед изворни кода

added preloader and messege added error message when login or password is not correct

makstravm пре 2 година
родитељ
комит
0e77954743

+ 1 - 0
package.json

@@ -4,6 +4,7 @@
     "private": true,
     "dependencies": {
         "@ant-design/icons": "^4.7.0",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3",
         "@testing-library/jest-dom": "^5.16.1",
         "@testing-library/react": "^12.1.2",
         "@testing-library/user-event": "^13.5.0",

+ 2 - 1
src/App.js

@@ -8,12 +8,13 @@ import { Content, Main } from './pages/Content';
 import { CProfilePage } from './pages/ProfilePage';
 import HeaderComponent from './pages/Header';
 import { CMainPostsFeed } from './pages/MainPostsFeed';
-import { CRRoute } from './helpers';
+import { CRRoute, promiseName } from './helpers';
 import { CPostPage } from './pages/PostPage';
 import { CAllPosts } from './pages/AllPosts';
 import { CEntityEditorPost } from './pages/EntityEditorPost';
 import { SettingsPage } from './pages/SettingsPage';
 import { Authorization } from './pages/Authorization';
+import { CPreloader } from './pages/Preloader';
 
 export const history = createHistory()
 

+ 14 - 0
src/App.scss

@@ -112,6 +112,19 @@ video {
     }
 }
 
+.PreloaderImg {
+    position: fixed;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 2;
+    background-color: rgba(#fff, 0.6);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
 .ant-popover {
     padding-top: 12px;
     &-arrow {
@@ -190,6 +203,7 @@ video {
 }
 
 .Main {
+    position: relative;
     padding-top: 58px;
     &__inner {
         padding-top: 22px;

+ 21 - 5
src/components/FormAuthorization.jsx

@@ -1,13 +1,29 @@
-import React from 'react'
+import React, { useEffect } from 'react'
 import { connect } from 'react-redux'
-import { Form, Input, Button, Checkbox } from 'antd';
+import { Form, Input, Button, Checkbox, message } from 'antd';
 import { UserOutlined, LockOutlined } from '@ant-design/icons';
 import { actionFullLogIn, actionFullRegister } from '../actions';
 
-const FormAuthorization = ({ buttonTitle, onSignIn }) => {
+const FormAuthorization = ({ buttonTitle, onSignIn, loginChek }) => {
+
+    useEffect(() => {
+        if (loginChek.status === "RESOLVED" && loginChek.payload === null) {
+            console.log(loginChek?.payload);
+            message.error({
+                content: 'Wrong login or password',
+                className: 'custom-class',
+                style: {
+                    marginTop: '20vh',
+                },
+            })
+        }
+    }, [loginChek.status]);
+
+
     const onFinish = ({ login, password, remember }) => {
         onSignIn(login, password, remember)
     };
+
     return (
         <Form
             name="normal_login"
@@ -62,8 +78,8 @@ const FormAuthorization = ({ buttonTitle, onSignIn }) => {
         </Form>
     )
 }
-export const CLoginForm = connect(null, { onSignIn: actionFullLogIn })(FormAuthorization)
-export const CRegisterForm = connect(null, { onSignIn: actionFullRegister })(FormAuthorization)
+export const CLoginForm = connect(state => ({ loginChek: state?.promise?.login || {} }), { onSignIn: actionFullLogIn, })(FormAuthorization)
+export const CRegisterForm = connect(state => ({ status: state?.promise?.login }), { onSignIn: actionFullRegister, })(FormAuthorization)
 
 
 

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

@@ -11,11 +11,11 @@ import {
 import { backURL, propsUploadFile, videoRegExp } from "../../helpers";
 
 
-const SortableItemMask = ({ removePhotosItem, setVisible, id }) =>
+const SortableItemMask = ({ removePhotosItem, chekMedia, setVisible, id }) =>
     <div className="SortableItemMask">
-        <Button type="link" onClick={() => setVisible(true)}>
+        {!chekMedia && <Button type="link" onClick={() => setVisible(true)}>
             <EyeOutlined />
-        </Button>
+        </Button>}
         <Button type="link" onClick={() => removePhotosItem(id)}>
             <DeleteOutlined />
         </Button>
@@ -24,15 +24,16 @@ const SortableItemMask = ({ removePhotosItem, setVisible, id }) =>
 
 const Handle = SortableHandle(({ tabIndex, value, removePhotosItem }) => {
     const [visible, setVisible] = useState(false);
+    const chekMedia = videoRegExp.test(value.originalFileName)
     return (
         <div className="Handle" tabIndex={tabIndex} >
-            <SortableItemMask id={value._id} setVisible={setVisible} removePhotosItem={removePhotosItem} />
-            {videoRegExp.test(value.originalFileName)
-                ? <video controls loop preload="true" height="500">
+            <SortableItemMask id={value._id} setVisible={setVisible} chekMedia={chekMedia} removePhotosItem={removePhotosItem} />
+            {chekMedia
+                ? <video >
                     <source src={backURL + '/' + value.url} />
                 </video>
                 : <img src={backURL + '/' + value.url} />
-            } 
+            }
             <Image className="hidden-item"
                 width={200}
                 style={{ display: 'none' }}

+ 2 - 1
src/helpers/index.js

@@ -14,6 +14,7 @@ export const propsUploadFile = {
     headers: localStorage.authToken || sessionStorage.authToken ? { Authorization: 'Bearer ' + (localStorage.authToken || sessionStorage.authToken) } : {}
 }
 
+
 export const jwtDecode = (token) => {
     try {
         let arrToken = token.split('.')
@@ -53,7 +54,7 @@ const CircularGallerySvg = () =>
     </svg>
 
 export const CircularGalleryIcon = props =>
-    <Icon component={CircularGallerySvg} {...props}/>
+    <Icon component={CircularGallerySvg} {...props} />
 
 const RRoute = ({ action, component: Component, ...routeProps }) => {
     const WrapperComponent = (componentProps) => {

BIN
src/images/preloader.gif


+ 2 - 0
src/pages/AllPosts.jsx

@@ -3,6 +3,7 @@ import { connect } from 'react-redux';
 import { actionAllPosts, actionRemovePostsFeedAC } from '../actions';
 import { CPosts } from '../components/main/Posts';
 import { Container } from './Content';
+import { CPreloader } from './Preloader';
 
 const AllPosts = ({ posts, onAllPosts, postsRemove }) => {
     const [checkScroll, setCheckScroll] = useState(true)
@@ -30,6 +31,7 @@ const AllPosts = ({ posts, onAllPosts, postsRemove }) => {
 
     return (
         <Container>
+            <CPreloader promiseName='allPosts' />
             <CPosts />
         </Container>
     )

+ 12 - 4
src/pages/EntityEditorPost.jsx

@@ -2,7 +2,7 @@ import { Button, Divider, message } from "antd"
 import Title from "antd/lib/typography/Title"
 import { useEffect, useState } from "react"
 import { connect } from "react-redux"
-import { actionFullSentPost, } from "../actions"
+import { actionAddPostsFeedAC, actionFullSentPost, actionRemovePostsFeedAC, } from "../actions"
 import { EditPhotos } from "../components/uploadPhoto/EditPhotos"
 import { EditDescriptionPost } from "../components/uploadPhoto/EditDescriptionPost"
 import { EditTitlePost } from "../components/uploadPhoto/EditTitlePost"
@@ -13,19 +13,23 @@ import { history } from '../App'
 const ContainEditorPost = ({ children }) =>
     <div className='ContainEditPost ContainerInner'>{children}</div>
 
-const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, onSave, findPostOne, clearState }) => {
+const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, onSave, updatePost, clearState }) => {
 
     const [photos, setPhotos] = useState(entity?.images || []);
     const [titleSend, setTitleSend] = useState(entity?.title || '')
     const [description, setDescription] = useState(entity?.text || '');
     useEffect(() => {
-        console.log();
+        let newEntity
         if (Array.isArray(entity)) {
-            let newEntity = entity.find(e => e._id === _id)
+            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')
+        updatePost(newEntity)
+        return () => {
+            clearState()
+        }
     }, []);
 
 
@@ -33,6 +37,8 @@ const EntityEditorPost = ({ match: { params: { _id } }, myID, entity, status, on
         if (status === "RESOLVED") {
             message.success(`post published, can create a new one`)
             history.push(`/profile/${myID}`)
+        }else if(status === "REJECTED"){
+            message.error('Error')
         }
     }, [status])
 
@@ -59,5 +65,7 @@ export const CEntityEditorPost = connect(state => ({
     status: state?.promise?.sentPost?.status
 }),
     {
+        updatePost: actionAddPostsFeedAC,
         onSave: actionFullSentPost,
+        clearState: actionRemovePostsFeedAC,
     })(EntityEditorPost)

+ 4 - 3
src/pages/Header.jsx

@@ -5,17 +5,18 @@ import { CFieldSearch } from '../components/header/Search';
 import { connect } from 'react-redux';
 import { actionAuthLogout } from '../actions';
 import Layout, { Header } from 'antd/lib/layout/layout';
-import {  Col, Menu, Popover, Row } from 'antd';
+import { Col, Menu, Popover, Row } from 'antd';
 import { UserOutlined, CompassOutlined, SettingOutlined, HomeOutlined, ImportOutlined, MessageOutlined, PlusCircleOutlined } from '@ant-design/icons/lib/icons';
 import { UserAvatar } from '../components/header/UserAvatar';
 
+import { history } from '../App'
 const UserNav = () =>
     <div className='UserNav'>
         <CUserNavIcon />
     </div>
 
 
-
+// console.log(history);
 const ProfileDropMenu = ({ myID, onLogOut }) =>
     <Menu className='dropMenu'>
         <Menu.Item key={'0'}>
@@ -66,7 +67,7 @@ const Logo = () =>
 
 const HeaderComponent = () =>
     <Layout>
-        <Header style={{ position: 'fixed', zIndex: 1, width: '100%' }}>
+        <Header style={{ position: 'fixed', zIndex: 3, width: '100%' }}>
             <Row justify="space-between" align="middle" className='Header__inner'>
                 <Col span={8}>
                     <Logo />

+ 5 - 2
src/pages/MainPostsFeed.jsx

@@ -10,6 +10,7 @@ import PostImage from '../components/main/postsFeed/PostImage'
 import { CPostUserPanel } from '../components/main/postsFeed/PostUserPanel'
 import { Container } from './Content'
 import { CPostTitle } from '../components/main/post/PostTitle'
+import { CPreloader } from './Preloader'
 
 
 export const PostDescription = ({ title, description, date }) =>
@@ -39,7 +40,7 @@ export const Comments = ({ comments = [], _id }) =>
 const Post = ({ postData: { _id, text, title, owner, images, createdAt = '', comments, likes } }) =>
     <div className='Post'>
         <Card
-            title={<CPostTitle owner={owner} postId={_id}/>}
+            title={<CPostTitle owner={owner} postId={_id} />}
             cover={<PostImage images={images} />}
         >
             <CPostUserPanel postId={_id} likes={likes} styleFontSize='1.7em' />
@@ -65,6 +66,7 @@ const MainPostsFeed = ({ posts, postsFollowing, clearState, following }) => {
         return () => {
             document.removeEventListener('scroll', scrollHandler)
             clearState()
+
         }
     }, [])
 
@@ -76,6 +78,7 @@ const MainPostsFeed = ({ posts, postsFollowing, clearState, following }) => {
 
     return (
         <Container>
+            <CPreloader promiseName='followingPosts' />
             {Array.isArray(posts) && posts.map(p => <Post key={p._id} postData={p} />)}
         </Container>
     )
@@ -83,7 +86,7 @@ const MainPostsFeed = ({ posts, postsFollowing, clearState, following }) => {
 
 export const CMainPostsFeed = connect(state => ({
     posts: state?.postsFeed?.posts || [],
-    following: state?.myData.following || []
+    following: state?.myData?.following || []
 }), {
     postsFollowing: actionPostsFeed,
     clearState: actionRemovePostsFeedAC,

+ 13 - 11
src/pages/PostPage.jsx

@@ -13,6 +13,7 @@ import { LikeFilled, LikeOutlined } from '@ant-design/icons';
 import { actionLikeComment, actionDelLikeComment, actionSubComment } from '../actions';
 import { CPostTitle } from '../components/main/post/PostTitle';
 import { UserAvatar } from '../components/header/UserAvatar';
+import { CPreloader } from './Preloader';
 
 
 const PostPageTitle = ({ data: { owner }, postId }) =>
@@ -126,18 +127,19 @@ const CPostPageDescrption = connect(state => ({ data: state?.postsFeed?.posts ||
 
 
 const PostPage = ({ data: { images } }) =>
-    <div className='PostOne'>
-        <div className='PostOne__inner'>
-            <div className='PostOne__image'>
-                <PostImage images={images} />
-            </div>
-            <div className='PostOne__title'>
-                <CPostPageTitle />
-            </div>
-            <div className='PostOne__description'>
-                <CPostPageDescrption />
+        <div className='PostOne'>
+            <CPreloader promiseName='postOne' />
+            <div className='PostOne__inner'>
+                <div className='PostOne__image'>
+                    <PostImage images={images} />
+                </div>
+                <div className='PostOne__title'>
+                    <CPostPageTitle />
+                </div>
+                <div className='PostOne__description'>
+                    <CPostPageDescrption />
+                </div>
             </div>
         </div>
-    </div>
 
 export const CPostPage = connect(state => ({ data: state?.postsFeed?.posts || {} }))(PostPage)

+ 20 - 0
src/pages/Preloader.jsx

@@ -0,0 +1,20 @@
+import { message, Spin } from 'antd'
+import { connect } from 'react-redux'
+import preloader from '../images/preloader.gif'
+
+const PreloaderImg = () =>
+    <div className='PreloaderImg'>
+        <Spin size="large" />
+    </div>
+
+const Preloader = ({ promiseName, promiseState, children }) =>
+    <>
+        {promiseState[promiseName]?.status === 'PENDING'
+            ? <PreloaderImg />
+            :
+            promiseState[promiseName]?.status === 'REJECTED'
+                ?
+                message.error(`${promiseState[promiseName]?.error}`) :
+                null}
+    </>
+export const CPreloader = connect(state => ({ promiseState: state.promise }))(Preloader)

+ 2 - 0
src/pages/ProfilePage.jsx

@@ -9,6 +9,7 @@ import Text from 'antd/lib/typography/Text'
 import { Container } from './Content'
 import { CPosts } from '../components/main/Posts'
 import { UserAvatar } from '../components/header/UserAvatar'
+import { CPreloader } from './Preloader'
 
 const ProfileFollowButton = ({ myID, userId, followers, onSubsuscribe, onUnSubsuscribe }) => {
     const followCheck = followers.find(f => f._id === myID && true)
@@ -114,6 +115,7 @@ const ProfilePage = ({ match: { params: { _id } }, getProfileUser, clearDataProf
 
     return (
         <Container>
+            <CPreloader promiseName='userOneDataPosts'/>
             <CProfilePageData setFollowing={setFollowing} setFollowers={setFollowers} />
             {followers && < CModalFollowers statusModal={setFollowers} title={'Followers'} />}
             {following && < CModalFollowing statusModal={setFollowing} title={'Following'} />}

+ 2 - 1
src/redux/reducers/postFeed-reducer.js

@@ -3,9 +3,10 @@ import React from 'react'
 export const postsFeedReducer = (state = {}, { type, findId, newResult, userData = {}, count = null }) => {
     const { posts } = state
     const types = {
+        //=== Array.isArray(newResult)
         'ADD-POSTS-FEED': () => ({
             ...state,
-            posts: Array.isArray(posts) === Array.isArray(newResult)
+            posts: Array.isArray(newResult) 
                 ? [...posts, ...newResult]
                 : { ...posts, ...newResult },
             count

+ 1 - 1
src/redux/reducers/promise-reducer.js

@@ -3,7 +3,7 @@ export function promiseReducer(state = {}, { type, status, payload, error, name
     if (type === 'PROMISE') {
         return {
             ...state,
-            [name]: { status, payload, error }
+            [name]: { status, payload: (status === 'PENDING' && state[name] && state[name].payload) || payload, error }
         }
     } else if (type === 'CLEAR-PROMISE') {
         return {

+ 2 - 2
src/redux/saga/index.js

@@ -355,9 +355,9 @@ function* findFollowWatcher() {
 
 function* sentPostWorker({ images, text, title }) {
     let imagesId = images.map(im => ({ _id: im._id }))
-    const { postsFeed: { posts } } = yield select()
+    const { postsFeed: { posts: {_id} } } = yield select()
     const upSertPostObj = {
-        ...posts,
+        _id,
         images: imagesId,
         text,
         title