Volddemar4ik 2 rokov pred
rodič
commit
26a5e0e7ee

+ 36 - 24
js/Project/project/src/App.js

@@ -5,7 +5,7 @@ import { Router, Route, Link, Redirect, Switch, useParams } from 'react-router-d
 import { createStore, combineRedusers, applyMiddleware } from 'redux';
 import thunk from 'redux-thunk';
 import { Provider, connect, useDispatch, useSelector } from 'react-redux';
-import Feed from './components/feed';
+// import Feed from './components/feed';
 import User from './components/user';
 
 // импорт страниц
@@ -13,6 +13,8 @@ import AsideMenu from './components/pages/structure/aside_menu';
 
 
 import { ReduxFeed } from './components/feed';
+import { CComments } from './components/post';
+import { CreatePost } from './components/pages/create_post';
 
 
 
@@ -33,11 +35,8 @@ function promiseReducer(state = {}, { type, status, payload, error, nameOfPromis
 
 // акшоны для promiseReducer
 const actionPending = nameOfPromise => ({ nameOfPromise, type: 'PROMISE', status: 'PENDING' })
-
 const actionFulfilled = (nameOfPromise, payload) => ({ nameOfPromise, type: 'PROMISE', status: 'FULFILLED', payload })
-
 const actionRejected = (nameOfPromise, error) => ({ nameOfPromise, type: 'PROMISE', status: 'REJECTED', error })
-
 const actionPromise = (nameOfPromise, promise) =>
     async dispatch => {
         dispatch(actionPending(nameOfPromise)) //сигнализируем redux, что промис начался
@@ -102,7 +101,7 @@ const actionfindPosts = () => actionPromise('PostsFind', gql(`query AllPostsFind
 }))
 
 // запрос на конкретный пост
-const actionFindPostOne = _id => actionPromise('PostFindOne', gql(`query OnePostFind ($postOne: String){
+export const actionFindPostOne = _id => actionPromise('PostFindOne', gql(`query OnePostFind ($postOne: String){
   PostFindOne (query: $postOne) {
     _id createdAt title text likesCount
     images {
@@ -168,10 +167,7 @@ const Registration = () =>
         Регистрация
     </div>
 
-const CreatePost = () =>
-    <div>
-        Страницв создания поста
-    </div>
+
 
 const PageAbout = () =>
     <div>
@@ -184,28 +180,44 @@ const Page404 = () =>
     </div>
 
 
+
+
+
+
+
+
+
 // ==================================================
 // страница одного поста
-const CComments = connect(state => ({ post: state?.PostFindOne?.payload }), { loadPost: actionFindPostOne })(Comments)
+// const CComments = connect(state => ({ post: state?.PostFindOne?.payload }), { loadPost: actionFindPostOne })(Comments)
+
+
+// function Comments({ post = {}, loadPost }) {
+
+//     const { postId } = useParams() // отслеживаем изменения в урле
+//     // const post2 = useSelector(state => state?.CategoryGoodsAndSubCategoryGoods?.payload)
+//     console.log(66, postId)
+
+//     useEffect(() => { loadPost(postId) }, [postId]) // перезапускаем loadPost, если произошло изменение в урле
+
+//     // console.log(post)
+
+//     return (
+//         <div>
+//             {/* <div>{user} and {postId}</div> */}
+//             тут будут отображаться все комментарии под постом
+//             <h2>{post.createdAt}</h2>
+//         </div>
+//     )
+// }
+
+
+
 
-function Comments({ post = {}, loadPost }) {
 
-    const { postId } = useParams() // отслеживаем изменения в урле
-    // const post2 = useSelector(state => state?.CategoryGoodsAndSubCategoryGoods?.payload)
-    console.log(66, postId)
 
-    useEffect(() => { loadPost(postId) }, [postId]) // перезапускаем loadPost, если произошло изменение в урле
 
-    // console.log(post)
 
-    return (
-        <div>
-            {/* <div>{user} and {postId}</div> */}
-            тут будут отображаться все комментарии под постом
-            <h2>{post.createdAt}</h2>
-        </div>
-    )
-}
 
 // ==================================================
 // страница юзера

+ 66 - 0
js/Project/project/src/components/pages/create_post/index.js

@@ -0,0 +1,66 @@
+import * as React from 'react';
+import { useState } from 'react';
+
+import Box from '@mui/material/Box';
+import TextField from '@mui/material/TextField';
+import Stack from '@mui/material/Stack';
+import Button from '@mui/material/Button';
+import CssBaseline from '@mui/material/CssBaseline';
+import Container from '@mui/material/Container';
+
+
+export const CreatePost = () => {
+
+    const [titleValue, setTitleValue] = useState('')
+    const [textValue, setTextValue] = useState('')
+
+
+    return (
+        <Container maxWidth="80%">
+            <div>
+                поле добавления фотографий
+            </div>
+
+            <Box
+                component="form"
+                sx={{
+                    '& > :not(style)': { m: 1, width: '80%', marginBottom: '20px' },
+                }}
+            >
+                <TextField
+                    id="title"
+                    label="Название поста"
+                    variant="standard"
+                    onChange={e => setTitleValue(e.target.value)}
+                />
+            </Box>
+
+            <Box
+                component="form"
+                sx={{
+                    '& .MuiTextField-root': { m: 1, width: '80%', marginBottom: '20px' },
+                }}
+            >
+                <TextField
+                    id="text"
+                    label="Описание поста"
+                    multiline
+                    rows={2}
+                    variant="standard"
+                    onChange={e => setTextValue(e.target.value)}
+                />
+            </Box>
+
+            <Stack spacing={2} direction="row">
+                <Button variant="outlined" onClick={e => { console.log('click') }}>
+                    Опубликовать пост
+                </Button>
+            </Stack>
+        </Container>
+
+
+    )
+
+
+}
+

+ 0 - 2
js/Project/project/src/components/pages/structure/aside_menu.js

@@ -4,8 +4,6 @@ const AsideMenu = () =>
     <aside style={{ width: '15%', minHeight: '100vh', backgroundColor: '#ffdbdb' }}>
         <Link to="/">Главная(она же Лента)</Link>
         <br />
-        <Link to="/profile">Профиль</Link>
-        <br />
         <Link to="/createpost">Создание поста</Link>
         <br />
         <Link to="/direct">Директ</Link>

+ 8 - 2
js/Project/project/src/components/post/index.js

@@ -1,15 +1,18 @@
 import { useEffect, useState } from 'react';
 import { useParams } from 'react-router';
+import { connect } from 'react-redux';
 
+import { actionFindPostOne } from '../redux/action';
 
-export default function Comments({ post = {}, loadPost }) {
+
+function Comments({ post = {}, loadPost }) {
 
     const { postId } = useParams() // отслеживаем изменения в урле
     // const post2 = useSelector(state => state?.CategoryGoodsAndSubCategoryGoods?.payload)
 
     useEffect(() => { loadPost(postId) }, [postId]) // перезапускаем loadPost, если произошло изменение в урле
 
-    // console.log(post)
+    console.log(post)
 
 
     return (
@@ -23,3 +26,6 @@ export default function Comments({ post = {}, loadPost }) {
 
 
 // store.dispatch(actionFindPostOne())
+
+
+export const CComments = connect(state => ({ post: state?.PostFindOne?.payload }), { loadPost: actionFindPostOne })(Comments)

+ 92 - 0
js/Project/project/src/components/redux/action.js

@@ -0,0 +1,92 @@
+// ==============================================================================
+// создание promiseReducer
+function promiseReducer(state = {}, { type, status, payload, error, nameOfPromise }) {
+    if (type === 'PROMISE') {
+        return {
+            ...state,
+            [nameOfPromise]: { status, payload, error }
+        }
+    }
+    return state
+}
+
+// акшоны для promiseReducer
+const actionPending = nameOfPromise => ({ nameOfPromise, type: 'PROMISE', status: 'PENDING' })
+const actionFulfilled = (nameOfPromise, payload) => ({ nameOfPromise, type: 'PROMISE', status: 'FULFILLED', payload })
+const actionRejected = (nameOfPromise, error) => ({ nameOfPromise, type: 'PROMISE', status: 'REJECTED', error })
+const actionPromise = (nameOfPromise, promise) =>
+    async dispatch => {
+        dispatch(actionPending(nameOfPromise)) //сигнализируем redux, что промис начался
+        try {
+            const payload = await promise //ожидаем промиса
+            dispatch(actionFulfilled(nameOfPromise, payload)) //сигнализируем redux, что промис успешно выполнен
+            return payload //в месте запуска store.dispatch с этим thunk можно так же получить результат промиса
+        }
+        catch (error) {
+            dispatch(actionRejected(nameOfPromise, error)) //в случае ошибки - сигнализируем redux, что промис несложился
+        }
+    }
+
+// =============================================================
+// функция getGql
+function getGql(endpoint) {
+    return async function gql(query, variables = {}) {
+
+        let headers = {
+            'Content-Type': 'application/json;charset=utf-8',
+            'Accept': 'application/json',
+        }
+        if (('authToken' in localStorage)) {
+            headers.Authorization = 'Bearer ' + localStorage.authToken
+        }
+
+        let result = await fetch(endpoint, {
+            method: 'POST',
+            headers,
+            body: JSON.stringify({
+                query,
+                variables
+            })
+        }).then(res => res.json())
+
+        if (('errors' in result) && !('data' in result)) {
+            throw new Error(JSON.stringify(result.errors))
+        }
+
+        result = Object.values(result.data)[0]
+
+        return result
+    }
+}
+
+const gql = getGql('http://hipstagram.node.ed.asmer.org.ua/graphql')
+
+
+
+export const actionFindPostOne = _id => actionPromise('PostFindOne', gql(`query OnePostFind ($postOne: String){
+  PostFindOne (query: $postOne) {
+    _id createdAt title text likesCount
+    images {
+      url
+    }
+    comments {
+      _id createdAt text answers {
+        _id createdAt text likes {
+          _id
+        }
+        likesCount owner {
+          _id login nick  avatar {
+            _id url
+          }
+        }
+      }
+      likesCount
+    }
+    owner {
+      _id login nick
+    }
+    
+  }
+}`, {
+    postOne: JSON.stringify([{ _id }])
+}))

+ 1 - 1
js/Project/project/src/components/user/avatar.js

@@ -4,7 +4,7 @@ import Stack from '@mui/material/Stack';
 
 export default function ImageAvatars({ userData }) {
     return (
-        <Stack direction="row" spacing={2}>
+        <Stack direction="row" spacing={1}>
             <Avatar alt={userData.login} src={userData.avatar?.url} sx={{ width: 100, height: 100 }} />
         </Stack>
     );

+ 19 - 33
js/Project/project/src/components/user/user_data.js

@@ -1,6 +1,5 @@
 import * as React from 'react';
 import Box from '@mui/material/Box';
-import Card from '@mui/material/Card';
 import CardContent from '@mui/material/CardContent';
 import Typography from '@mui/material/Typography';
 
@@ -22,40 +21,27 @@ function UptadeProfile() {
 export default function BasicCard({ userData }) {
 
     return (
-        <Card sx={{ width: '100%' }}>
-            <CardContent>
-                <Stack direction="row" spacing={5}>
-                    <Typography variant="h5" component="div">
-                        {userData.login}
-                    </Typography>
-                    <UptadeProfile />
-                </Stack>
-                <Stack direction="row" spacing={5}>
-                    <Typography color="text.secondary">
-                        NaN Публикаций
-                    </Typography>
-                    <Typography color="text.secondary">
-                        {userData.followers?.length} подписчиков
-                    </Typography>
-                    <Typography color="text.secondary">
-                        {userData.following?.length || '0'} подписок
-                    </Typography>
-                </Stack>
-
-                <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
-                    hhhhhh
+        <CardContent sx={{ width: '100%', paddingTop: 0 }}>
+            <Stack direction="row" spacing={5}>
+                <Typography variant="h5" component="div">
+                    {userData.login}
                 </Typography>
-
-                <Typography sx={{ mb: 1.5 }} color="text.secondary">
-                    adjective
+                <UptadeProfile />
+            </Stack>
+            <Stack direction="row" spacing={5} paddingTop={3}>
+                <Typography color="text.secondary">
+                    NaN Публикаций
                 </Typography>
-                <Typography variant="body2">
-                    well meaning and kindly.
-                    <br />
-                    {'"a benevolent smile"'}
+                <Typography color="text.secondary">
+                    {userData.followers?.length} подписчиков
                 </Typography>
-            </CardContent>
-
-        </Card>
+                <Typography color="text.secondary">
+                    {userData.following?.length || '0'} подписок
+                </Typography>
+            </Stack>
+            <Typography sx={{ mb: 1.5 }} variant="body1">
+                {userData.nick || 'Jhon Snow'}
+            </Typography>
+        </CardContent>
     );
 }