Forráskód Böngészése

project 02/03/2023

Volddemar4ik 2 éve
szülő
commit
8ddfc8d333

+ 207 - 0
js/Project/project/package-lock.json

@@ -20,6 +20,8 @@
         "react-dom": "^18.2.0",
         "react-material-ui-carousel": "^3.4.2",
         "react-redux": "^8.0.5",
+        "react-router": "^6.8.2",
+        "react-router-dom": "5.3",
         "react-scripts": "5.0.1",
         "redux": "^4.2.1",
         "redux-thunk": "^2.4.2",
@@ -3514,6 +3516,14 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
+    "node_modules/@remix-run/router": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz",
+      "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==",
+      "engines": {
+        "node": ">=14"
+      }
+    },
     "node_modules/@rollup/plugin-babel": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -9220,6 +9230,19 @@
       "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
       "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
     },
+    "node_modules/history": {
+      "version": "4.10.1",
+      "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+      "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
+      "dependencies": {
+        "@babel/runtime": "^7.1.2",
+        "loose-envify": "^1.2.0",
+        "resolve-pathname": "^3.0.0",
+        "tiny-invariant": "^1.0.2",
+        "tiny-warning": "^1.0.0",
+        "value-equal": "^1.0.1"
+      }
+    },
     "node_modules/hoist-non-react-statics": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -14941,6 +14964,74 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-router": {
+      "version": "6.8.2",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz",
+      "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==",
+      "dependencies": {
+        "@remix-run/router": "1.3.3"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "peerDependencies": {
+        "react": ">=16.8"
+      }
+    },
+    "node_modules/react-router-dom": {
+      "version": "5.3.4",
+      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz",
+      "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.12.13",
+        "history": "^4.9.0",
+        "loose-envify": "^1.3.1",
+        "prop-types": "^15.6.2",
+        "react-router": "5.3.4",
+        "tiny-invariant": "^1.0.2",
+        "tiny-warning": "^1.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=15"
+      }
+    },
+    "node_modules/react-router-dom/node_modules/isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
+    },
+    "node_modules/react-router-dom/node_modules/path-to-regexp": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+      "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+      "dependencies": {
+        "isarray": "0.0.1"
+      }
+    },
+    "node_modules/react-router-dom/node_modules/react-is": {
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+    },
+    "node_modules/react-router-dom/node_modules/react-router": {
+      "version": "5.3.4",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
+      "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
+      "dependencies": {
+        "@babel/runtime": "^7.12.13",
+        "history": "^4.9.0",
+        "hoist-non-react-statics": "^3.1.0",
+        "loose-envify": "^1.3.1",
+        "path-to-regexp": "^1.7.0",
+        "prop-types": "^15.6.2",
+        "react-is": "^16.6.0",
+        "tiny-invariant": "^1.0.2",
+        "tiny-warning": "^1.0.0"
+      },
+      "peerDependencies": {
+        "react": ">=15"
+      }
+    },
     "node_modules/react-scripts": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -15271,6 +15362,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/resolve-pathname": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
+      "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
+    },
     "node_modules/resolve-url-loader": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz",
@@ -16506,6 +16602,16 @@
       "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
       "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
     },
+    "node_modules/tiny-invariant": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz",
+      "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw=="
+    },
+    "node_modules/tiny-warning": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+    },
     "node_modules/tmpl": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -16900,6 +17006,11 @@
         "node": ">=10.12.0"
       }
     },
+    "node_modules/value-equal": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
+      "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
+    },
     "node_modules/vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -20177,6 +20288,11 @@
       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
       "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
     },
+    "@remix-run/router": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz",
+      "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w=="
+    },
     "@rollup/plugin-babel": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -24394,6 +24510,19 @@
       "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
       "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
     },
+    "history": {
+      "version": "4.10.1",
+      "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
+      "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
+      "requires": {
+        "@babel/runtime": "^7.1.2",
+        "loose-envify": "^1.2.0",
+        "resolve-pathname": "^3.0.0",
+        "tiny-invariant": "^1.0.2",
+        "tiny-warning": "^1.0.0",
+        "value-equal": "^1.0.1"
+      }
+    },
     "hoist-non-react-statics": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -28337,6 +28466,64 @@
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
       "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
     },
+    "react-router": {
+      "version": "6.8.2",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz",
+      "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==",
+      "requires": {
+        "@remix-run/router": "1.3.3"
+      }
+    },
+    "react-router-dom": {
+      "version": "5.3.4",
+      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz",
+      "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==",
+      "requires": {
+        "@babel/runtime": "^7.12.13",
+        "history": "^4.9.0",
+        "loose-envify": "^1.3.1",
+        "prop-types": "^15.6.2",
+        "react-router": "5.3.4",
+        "tiny-invariant": "^1.0.2",
+        "tiny-warning": "^1.0.0"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
+        },
+        "path-to-regexp": {
+          "version": "1.8.0",
+          "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+          "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+          "requires": {
+            "isarray": "0.0.1"
+          }
+        },
+        "react-is": {
+          "version": "16.13.1",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+          "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+        },
+        "react-router": {
+          "version": "5.3.4",
+          "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
+          "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
+          "requires": {
+            "@babel/runtime": "^7.12.13",
+            "history": "^4.9.0",
+            "hoist-non-react-statics": "^3.1.0",
+            "loose-envify": "^1.3.1",
+            "path-to-regexp": "^1.7.0",
+            "prop-types": "^15.6.2",
+            "react-is": "^16.6.0",
+            "tiny-invariant": "^1.0.2",
+            "tiny-warning": "^1.0.0"
+          }
+        }
+      }
+    },
     "react-scripts": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -28589,6 +28776,11 @@
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
       "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
     },
+    "resolve-pathname": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
+      "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
+    },
     "resolve-url-loader": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz",
@@ -29495,6 +29687,16 @@
       "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
       "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
     },
+    "tiny-invariant": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz",
+      "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw=="
+    },
+    "tiny-warning": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+    },
     "tmpl": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -29782,6 +29984,11 @@
         "source-map": "^0.7.3"
       }
     },
+    "value-equal": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
+      "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
+    },
     "vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

+ 2 - 0
js/Project/project/package.json

@@ -15,6 +15,8 @@
     "react-dom": "^18.2.0",
     "react-material-ui-carousel": "^3.4.2",
     "react-redux": "^8.0.5",
+    "react-router": "^6.8.2",
+    "react-router-dom": "5.3",
     "react-scripts": "5.0.1",
     "redux": "^4.2.1",
     "redux-thunk": "^2.4.2",

+ 78 - 132
js/Project/project/src/App.js

@@ -2,17 +2,15 @@ import logo from './logo.svg';
 import './App.css';
 import React, { useState, useEffect } from 'react';
 import { Router, Route, Link, Redirect, Switch, useParams } from 'react-router-dom';
-import RecipeReviewCard from './post' // импортируем карточку поста в лентеы
-import Box from '@mui/material/Box';
-import Stack from '@mui/material/Stack';
-import Paper from '@mui/material/Paper';
-import { styled } from '@mui/material/styles';
-
 
 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 Comments from './components/post';
+import User from './components/user';
+
 // import { Provider } from 'react-redux';
 
 import createHistory from "history/createBrowserHistory";
@@ -87,38 +85,72 @@ const gql = getGql('http://hipstagram.node.ed.asmer.org.ua/graphql')
 
 
 // запрос на все посты (для ленты общей)
-const actionfindPosts = () => actionPromise('PostsFind', gql(`query findPosts($allPosts: String){
-    PostFind(query: $allPosts){
-    _id createdAt title text likesCount images {url} owner{_id login nick} comments{
-        _id
+const actionfindPosts = () => actionPromise('PostsFind', gql(`query AllPostsFind ($allPosts: String){
+  PostFind(query: $allPosts){
+    _id createdAt title text likesCount
+    images {
+      url
+    }
+    owner {
+      _id login nick
     }
-  }}`, {
+    
+  }
+}`, {
     allPosts: JSON.stringify([{}])
 }))
 
 
 
 // запрос на конкретный пост
-// const actionFindPostOne = _id => actionPromise('PostFindOne', gql(`
-// query PostFindOne ($postOne: String){
-//   PostFindOne (query: $postOne) {
-//     _id createdAt title text likesCount images {url} owner{_id login nick}
-//   }
-// }`, {
-//     postOne: JSON.stringify([{ _id }])
-// }))
+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 }])
+}))
+
 
 
-// const actionPostsFind = () => actionPromise('PostsFind', gql(`query baseCategory($searchVariablesCategory: String){
-//         PostsFind(query: $searchVariablesCategory){
-//             _id name parent {
-//                 _id
-//                 name
-//             }
-//         }
-//     }`, {
-//     searchVariablesCategory: JSON.stringify([{ parent: null }])
-// }))
+// запрос на конкретного юзера
+const actionFindUserOne = _id => actionPromise('UserFindOne', gql(`query OneUserFind ($userOne: String) {
+  UserFindOne(query: $userOne) {
+    createdAt login nick 
+    avatar {
+      _id url
+    } 
+     followers {
+      _id login nick avatar {_id url}
+    }
+    following {
+       _id login nick avatar {_id url}
+    }
+  }
+}`, {
+    userOne: JSON.stringify([{ _id }])
+}))
+
 
 
 
@@ -128,13 +160,7 @@ store.subscribe(() => console.log(store.getState()))
 
 store.dispatch(actionfindPosts())
 // store.dispatch(actionCategoryFind())
-
-
-
-
-
-
-
+store.dispatch(actionFindUserOne())
 
 
 
@@ -146,77 +172,26 @@ const Autorization = () =>
         Авторизация
     </div>
 
-
 const Registration = () =>
     <div>
         Регистрация
     </div>
 
-
-// const MainPage = () =>
-//     <div>
-//         Главная страница
-//     </div>
-
-
 const Direct = () =>
     <div>
         Direct
     </div>
 
-
-
-
-// ===================================================
-// сам item для поста
-const Item = styled(Paper)(({ theme }) => ({
-    backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
-    width: 500
-}));
-
-// const Feed = ({ posts = arrPosts }) => {
-const Feed = ({ posts = [] }) => {
-    return (
-        <Box sx={{
-            width: '500',
-            height: '600',
-            margin: '10, 20'
-        }}>
-            {/* spacing - это отступ между карточками в ленте */}
-            <Stack spacing={1}>
-                {/* {posts.map(post => <Item key={post._id}><RecipeReviewCard date={post.createdAt} title={post.title} text={post.text} likesCount={post.likesCount} nickName={post.owner.nick} login={post.owner.login} /></Item>)} */}
-                {posts.map(post => <Item key={post._id}><RecipeReviewCard postData={post} /></Item>)}
-            </Stack>
-        </Box >
-    );
-}
-
-const ReduxFeed = connect(state => ({ posts: state.PostsFind.payload }))(Feed)
-
-// ================================================
-
-
-// ==============================================================================
-// страница поста
-
-
-
-
-
-// ===============================================================================
-
-
 const CreatePost = () =>
     <div>
         Страницв создания поста
     </div>
 
-
-const User = () =>
-    <div>
-        Страница юзера
-    </div>
-
+// const User = () =>
+//     // <div>
+//     //     Страница юзера
+//     // </div>
+//     <SimpleContainer />
 
 const PageAbout = () =>
     <div>
@@ -229,44 +204,18 @@ const Page404 = () =>
     </div>
 
 
+// создаем компонент ленты на основе стандартного, который отслеживает все изменения state
+const ReduxFeed = connect(state => ({ posts: state.PostsFind.payload }))(Feed)
+
 // ==================================================
 // страница одного поста
-
-const actionFindPostOne = _id => actionPromise('PostFindOne', gql(`
-query PostFindOne ($postOne: String){
-  PostFindOne (query: $postOne) {
-    _id createdAt title text likesCount images {url} owner{_id login nick}
-  }
-}`, {
-    postOne: JSON.stringify([{ _id }])
-}))
-
-// const Comments = ({ match: { params: { user, postId } } }) =>
-// const Comments = ({ post = {}, loadPost }) => {
-const Comments = ({ post = {}, loadPost }) => {
-
-
-    const { postId } = useParams()
-    // const post2 = useSelector(state => state?.CategoryGoodsAndSubCategoryGoods?.payload)
-
-    useEffect(() => { loadPost(postId) }, [postId])
-
-
-    return (
-        <div>
-            {/* <div>{user} and {postId}</div> */}
-            тут будут отображаться все комментарии под постом
-            <h2>{post.createdAt}</h2>
-        </div>
-    )
-
-}
-
-// store.dispatch(actionFindPostOne())
-
 const CComments = connect(state => ({ post: state?.PostFindOne?.payload }), { loadPost: actionFindPostOne })(Comments)
 // ====================================================
 
+// ==================================================
+// страница юзера
+const CUser = connect(state => ({ user: state?.UserFindOne?.payload }), { loadUser: actionFindUserOne })(User)
+// ====================================================
 
 function App() {
     return (
@@ -298,22 +247,19 @@ function App() {
 
                             <Switch>
                                 <Route path="/autorization" component={Autorization} />
-                                <Route path="/profile" component={User} />
+                                {/* <Route path="/profile" component={User} /> */}
+                                <Route path="/profile" component={CUser} />
+
                                 <Route path="/registration" component={Registration} />
-                                {/* <Route path="/" component={Feed} exact /> */}
                                 <Route path="/" component={ReduxFeed} exact />
                                 <Route path="/createpost" component={CreatePost} />
                                 <Route path="/direct" component={Direct} />
                                 <Route path="/about" component={PageAbout} />
-                                {/* <Route path="/:postId" component={Comments} /> */}
                                 <Route path="/:postId" component={CComments} />
 
 
                                 <Route path="*" component={Page404} />
-                                {/* аналогично */}
-                                {/* <Page404 /> */}
-
-
+                                {/* <Page404 /> - это аналог записи выше */}
                             </Switch>
                         </main>
                         <footer style={{ backgroundColor: '#dbffe7' }}>Hipstagram from Volddemar4ik</footer>

+ 185 - 75
js/Project/project/src/App_test.js

@@ -1,16 +1,121 @@
 import logo from './logo.svg';
 import './App.css';
 import React, { useState, useEffect } from 'react';
-import { Router, Route, Link, Redirect, Switch } from 'react-router-dom';
-import RecipeReviewCard from './post' // импортируем карточку поста в лентеы
+import { Router, Route, Link, Redirect, Switch, useParams } from 'react-router-dom';
+import RecipeReviewCard from './components/Feed' // импортируем карточку поста в лентеы
 import Box from '@mui/material/Box';
 import Stack from '@mui/material/Stack';
 import Paper from '@mui/material/Paper';
 import { styled } from '@mui/material/styles';
 
+
+import { createStore, combineRedusers, applyMiddleware } from 'redux';
+import thunk from 'redux-thunk';
+import { Provider, connect, useDispatch, useSelector } from 'react-redux';
+
+// import { Provider } from 'react-redux';
+
 import createHistory from "history/createBrowserHistory";
 
 
+// ==============================================================================
+// создание 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')
+
+
+// запрос на все посты (для ленты общей)
+const actionfindPosts = () => actionPromise('PostsFind', gql(`query findPosts($allPosts: String){
+    PostFind(query: $allPosts){
+    _id createdAt title text likesCount images {url} owner{_id login nick} comments{
+        _id
+    }
+  }}`, {
+  allPosts: JSON.stringify([{}])
+}))
+
+
+
+// запрос на конкретный пост
+const actionFindPostOne = _id => actionPromise('PostFindOne', gql(`
+query PostFindOne ($postOne: String){
+  PostFindOne (query: $postOne) {
+    _id createdAt title text likesCount images {url} owner{_id login nick}
+  }
+}`, {
+  postOne: JSON.stringify([{ _id }])
+}))
+
+
+const store = createStore(promiseReducer, applyMiddleware(thunk))
+store.subscribe(() => console.log(store.getState()))
+
+store.dispatch(actionfindPosts())
+// store.dispatch(actionCategoryFind())
+
+
 const history = createHistory()
 
 const Autorization = () =>
@@ -18,32 +123,25 @@ const Autorization = () =>
     Авторизация
   </div>
 
-
 const Registration = () =>
   <div>
     Регистрация
   </div>
 
-
-const MainPage = () =>
-  <div>
-    Главная страница
-  </div>
-
-
 const Direct = () =>
   <div>
     Direct
   </div>
 
-
-// блок поста альтернативный
+// ===================================================
+// сам item для поста
 const Item = styled(Paper)(({ theme }) => ({
   backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
   width: 500
 }));
 
-const Feed = () => {
+// const Feed = ({ posts = arrPosts }) => {
+const Feed = ({ posts = [] }) => {
   return (
     <Box sx={{
       width: '500',
@@ -52,33 +150,26 @@ const Feed = () => {
     }}>
       {/* spacing - это отступ между карточками в ленте */}
       <Stack spacing={1}>
-        <Item>
-          <RecipeReviewCard />
-        </Item>
-        <Item>
-          <RecipeReviewCard />
-        </Item>
-        <Item>
-          <RecipeReviewCard />
-        </Item>
+        {/* {posts.map(post => <Item key={post._id}><RecipeReviewCard date={post.createdAt} title={post.title} text={post.text} likesCount={post.likesCount} nickName={post.owner.nick} login={post.owner.login} /></Item>)} */}
+        {posts.map(post => <Item key={post._id}><RecipeReviewCard postData={post} /></Item>)}
       </Stack>
     </Box >
   );
 }
 
+const ReduxFeed = connect(state => ({ posts: state.PostsFind.payload }))(Feed)
 
+// ================================================
 const CreatePost = () =>
   <div>
     Страницв создания поста
   </div>
 
-
 const User = () =>
   <div>
     Страница юзера
   </div>
 
-
 const PageAbout = () =>
   <div>
     Страница "О нас"
@@ -89,61 +180,80 @@ const Page404 = () =>
     NOT FOUND
   </div>
 
-const Comments = ({ match: { params: { user, postId } } }) =>
-  <div>
-    <div>{user} and {postId}</div>
-    тут будут отображаться все комментарии под постом
-  </div>
 
+// ==================================================
+// страница одного поста
+
+const Comments = ({ post = {}, loadPost }) => {
+
+
+  const { postId } = useParams()
+  // const post2 = useSelector(state => state?.CategoryGoodsAndSubCategoryGoods?.payload)
+
+  useEffect(() => { loadPost(postId) }, [postId])
+
+  return (
+    <div>
+      {/* <div>{user} and {postId}</div> */}
+      тут будут отображаться все комментарии под постом
+      <h2>{post.createdAt}</h2>
+    </div>
+  )
+}
+
+// store.dispatch(actionFindPostOne())
+
+const CComments = connect(state => ({ post: state?.PostFindOne?.payload }), { loadPost: actionFindPostOne })(Comments)
+// ====================================================
 
 function App() {
   return (
-    <Router history={history}>
-      <div className="wrapper" style={{ display: 'flex', minHeight: '100hv' }}>
-        <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>
-          <br />
-          <Link to="/about">О нас</Link>
-          <br />
-          <Link to="/registration">Регистрация</Link>
-          <br />
-          <Link to="/autorization">Авторизация</Link>
-        </aside>
-        <section style={{ width: '50%', margin: '0 auto', minHeight: '100hv', display: 'flex', flexDirection: 'column' }}>
-          <header style={{ backgroundColor: '#dbffe7' }}>
-            Тут будут какие-то заголовки или что-то вроде этого
-          </header>
-          <main style={{ backgroundColor: '#dcdbff', flex: '1 1 auto' }}>
-            {/* прописывание редиректа */}
-            {/* <Redirect from='/direct' to='/profile' /> */}
-
-            <Switch>
-              <Route path="/autorization" component={Autorization} />
-              <Route path="/profile" component={User} />
-              <Route path="/registration" component={Registration} />
-              <Route path="/" component={Feed} exact />
-              <Route path="/createpost" component={CreatePost} />
-              <Route path="/direct" component={Direct} />
-              <Route path="/about" component={PageAbout} />
-              <Route path="/:user/:postId" component={Comments} />
-
-              <Route path="*" component={Page404} />
-              {/* аналогично */}
-              {/* <Page404 /> */}
-
-
-            </Switch>
-          </main>
-          <footer style={{ backgroundColor: '#dbffe7' }}>Hipstagram from Volddemar4ik</footer>
-        </section>
-      </div>
-    </Router >
+    <Provider store={store}>
+      <Router history={history}>
+        <div className="wrapper" style={{ display: 'flex', minHeight: '100hv' }}>
+          <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>
+            <br />
+            <Link to="/about">О нас</Link>
+            <br />
+            <Link to="/registration">Регистрация</Link>
+            <br />
+            <Link to="/autorization">Авторизация</Link>
+          </aside>
+          <section style={{ width: '50%', margin: '0 auto', minHeight: '100hv', display: 'flex', flexDirection: 'column' }}>
+            <header style={{ backgroundColor: '#dbffe7' }}>
+              Тут будут какие-то заголовки или что-то вроде этого
+            </header>
+            <main style={{ backgroundColor: '#dcdbff', flex: '1 1 auto' }}>
+              {/* прописывание редиректа */}
+              {/* <Redirect from='/direct' to='/profile' /> */}
+
+              <Switch>
+                <Route path="/autorization" component={Autorization} />
+                <Route path="/profile" component={User} />
+                <Route path="/registration" component={Registration} />
+                <Route path="/" component={ReduxFeed} exact />
+                <Route path="/createpost" component={CreatePost} />
+                <Route path="/direct" component={Direct} />
+                <Route path="/about" component={PageAbout} />
+                <Route path="/:postId" component={CComments} />
+
+
+                <Route path="*" component={Page404} />
+                {/* <Page404 /> - это аналог записи выше */}
+              </Switch>
+            </main>
+            <footer style={{ backgroundColor: '#dbffe7' }}>Hipstagram from Volddemar4ik</footer>
+          </section>
+        </div>
+      </Router >
+    </Provider>
   );
 }
 

+ 2 - 8
js/Project/project/src/post/carousel.js

@@ -1,21 +1,15 @@
 // import React from 'react';
 import Carousel from 'react-material-ui-carousel'
-import { Paper, Button } from '@mui/material'
-
 
 
 
 // сама карусель - ее нужно вынеси в отдельный контенйре
 export const MyCarousel = function Example(props) {
-    var items = [
+    let items = [
         {
-            // name: "Random Name #1",
-            // description: "Probably the most random thing you have ever seen!",
             url: "/images/image.jpeg"
         },
         {
-            // name: "Random Name #2",
-            // description: "Hello World!",
             url: "/images/image2.jpeg"
         },
         {
@@ -24,7 +18,7 @@ export const MyCarousel = function Example(props) {
     ]
 
     return (
-        <Carousel autoPlay={false} indicatorContainerProps={{
+        <Carousel autoPlay={false} cycleNavigation={false} animation={"slide"} indicatorContainerProps={{
             style: {
                 marginTop: '-50px', // 5
                 zIndex: 999,

+ 30 - 98
js/Project/project/src/post/index.js

@@ -15,100 +15,36 @@ import { Link } from 'react-router-dom';
 import TurnedInNotIcon from '@mui/icons-material/TurnedInNot';
 import Grid from '@mui/material/Unstable_Grid2';
 import Box from '@mui/material/Box';
-// import img from '../public/image.jpeg'
-
-
-
-// импорты для слайдер
-// import React from 'react';
-import Carousel from 'react-material-ui-carousel'
-import { Paper, Button } from '@mui/material'
 import { MyCarousel } from './carousel';
+import Stack from '@mui/material/Stack';
+import Paper from '@mui/material/Paper';
+import { styled } from '@mui/material/styles';
 
+// import BasicModal from '../PostOne';
 
-
+// урл бека
 const url = 'http://hipstagram.node.ed.asmer.org.ua/'
 
+// сам item для поста
+const Item = styled(Paper)(({ theme }) => ({
+    backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
+    width: 500
+}))
 
-// export default function RecipeReviewCard({ date, title, text, likesCount, nickName, login }) {
-export default function RecipeReviewCard({ postData }) {
 
+function RecipeReviewCard({ postData }) {
     // формируем дату поста
     const dateofPost = new Date(+postData.createdAt)
-    // console.log(dateofPost)
     const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
     const dateofPostParse = `${dateofPost.getDate() < 10 ? '0' + dateofPost.getDate() : dateofPost.getDate()} ${months[dateofPost.getMonth()]} ${dateofPost.getFullYear()}  ${dateofPost.getHours()}:${dateofPost.getMinutes() < 10 ? '0' + dateofPost.getMinutes() : dateofPost.getMinutes()}`
-    // console.log(dateofPostParse)
 
     // рисуем картинки на постах
-
     let imgOfPost
     if ((postData.images != null) && ((postData.images).length != 0)) {
         imgOfPost = url + postData.images[0].url
-        console.log(imgOfPost)
+        // console.log(imgOfPost)
     }
 
-
-
-
-    // // сама карусель - ее нужно вынеси в отдельный контенйре
-
-    // const MyCarousel = function Example(props) {
-    //     var items = [
-    //         {
-    //             // name: "Random Name #1",
-    //             // description: "Probably the most random thing you have ever seen!",
-    //             url: "/images/image.jpeg"
-    //         },
-    //         {
-    //             // name: "Random Name #2",
-    //             // description: "Hello World!",
-    //             url: "/images/image2.jpeg"
-    //         },
-    //         {
-    //             url: "/images/image4.jpeg"
-    //         }
-    //     ]
-
-    //     return (
-    //         <Carousel autoPlay={false} indicatorContainerProps={{
-    //             style: {
-    //                 marginTop: '-50px', // 5
-    //                 zIndex: 999,
-    //                 position: 'inherit' // 4
-    //             }
-
-    //         }} >
-    //             {
-    //                 items.map((item, i) => <Item key={i} item={item} />)
-    //             }
-    //         </Carousel >
-    //     )
-    // }
-
-    // function Item(props) {
-    //     return (
-    //         <div style={{
-    //             width: 500,
-    //             height: 625,
-    //             backgroundColor: 'black',
-    //             display: 'flex',
-    //             alignItems: 'center'
-    //         }}>
-    //             <img src={props.item.url} style={{
-    //                 width: '100%',
-    //             }} />
-    //         </div>
-    //     )
-    // }
-
-
-
-
-
-
-
-
     return (
         <Card sx={{ maxWidth: 500 }}>
             <CardHeader
@@ -125,18 +61,12 @@ export default function RecipeReviewCard({ postData }) {
                         <MoreVertIcon />
                     </IconButton>
                 }
-                // title="Author Author(ович)" // автор поста
-                // title={nickName ? nickName : login} // автор поста
-                title={postData.owner.nick ? postData.owner.nick : postData.owner.login} // автор поста
+
+                title={<a href={postData.owner._id}>{postData.owner.nick ? postData.owner.nick : postData.owner.login}</a>} // автор поста
+
                 subheader={dateofPostParse} // дата создания поста
             />
-            <CardMedia
-            // component="img"
-            // height="100%" // высота картинки
-            // // image="/images/image.jpeg" // ссылка на картинку в посте
-            // image={imgOfPost ? imgOfPost : "/images/image.jpeg"} // ссылка на картинку в посте
-            // alt="Котики" // описание картинки
-            >
+            <CardMedia>
                 <MyCarousel />
             </CardMedia>
             <CardActions disableSpacing>
@@ -177,34 +107,36 @@ export default function RecipeReviewCard({ postData }) {
                 </Box>
             </CardActions>
             <CardActions>
-                {/* Нравится: 78 */}
-                {/* Нравится: {likesCount ? likesCount : '0'} */}
                 Нравится: {postData.likesCount ? postData.likesCount : '0'}
                 {/* Нравится: {postData.likesCount || '0'} // сработает или нет - проверить */}
             </CardActions>
             <CardContent>
                 <Typography variant="subtitle2" color="text.secondary">
-                    {/* {title} */}
                     {postData.title}
                 </Typography>
                 <Typography variant="body2" color="text.secondary">
-                    {/* {text} */}
                     {postData.text}
                 </Typography>
             </CardContent>
-            {/* <CardContent>
-                тут будет слайдер
-                <MyCarousel />
-            </CardContent> */}
             <CardActions>
-                {/* <Link to="/user/postId">Посмотреть все комментарии (44)</Link> */}
                 <Link to={postData._id}>Посмотреть все комментарии (44)</Link>
             </CardActions>
-
         </Card>
     )
 }
 
 
-
-
+export default function Feed({ posts = [] }) {
+    return (
+        <Box sx={{
+            width: '500',
+            height: '600',
+            margin: '10, 20'
+        }}>
+            {/* spacing - это отступ между карточками в ленте */}
+            <Stack spacing={1}>
+                {posts.map(post => <Item key={post._id}><RecipeReviewCard postData={post} /></Item>)}
+            </Stack>
+        </Box >
+    );
+}

+ 26 - 0
js/Project/project/src/components/post/index.js

@@ -0,0 +1,26 @@
+import { useEffect, useState } from 'react';
+import { useParams } from 'react-router';
+
+
+export default function Comments({ post = {}, loadPost }) {
+
+    const { postId } = useParams() // отслеживаем изменения в урле
+    // const post2 = useSelector(state => state?.CategoryGoodsAndSubCategoryGoods?.payload)
+
+    useEffect(() => { loadPost(postId) }, [postId]) // перезапускаем loadPost, если произошло изменение в урле
+
+    // console.log(post)
+
+
+    return (
+        <div>
+            {/* <div>{user} and {postId}</div> */}
+            тут будут отображаться все комментарии под постом
+            <h2>{post.createdAt}</h2>
+        </div>
+    )
+}
+
+
+// store.dispatch(actionFindPostOne())
+

+ 119 - 0
js/Project/project/src/components/user/gallery.js

@@ -0,0 +1,119 @@
+import * as React from 'react';
+import ImageList from '@mui/material/ImageList';
+import ImageListItem from '@mui/material/ImageListItem';
+
+export default function StandardImageList() {
+    return (
+        <ImageList sx={{ width: "100%", minHeight: "100%" }} cols={3} rowHeight={'auto'}>
+            {itemData.map((item) => (
+                // <ImageListItem key={item.img}>
+                <ImageListItem key={Math.random()}>
+
+                    <img
+                        src={`${item.img}?w=164&h=164&fit=crop&auto=format`}
+                        srcSet={`${item.img}?w=164&h=164&fit=crop&auto=format&dpr=2 2x`}
+                        alt={item.title}
+                        loading="lazy"
+                    />
+                </ImageListItem>
+            ))
+            }
+        </ImageList >
+    );
+}
+
+// массив с картинками
+const itemData = [
+    {
+        img: '/images/image4.jpeg',
+        title: 'Cat',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
+        title: 'Breakfast',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1551782450-a2132b4ba21d',
+        title: 'Burger',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1522770179533-24471fcdba45',
+        title: 'Camera',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1444418776041-9c7e33cc5a9c',
+        title: 'Coffee',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1533827432537-70133748f5c8',
+        title: 'Hats',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1516802273409-68526ee1bdd6',
+        title: 'Basketball',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1518756131217-31eb79b20e8f',
+        title: 'Fern',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1597645587822-e99fa5d45d25',
+        title: 'Mushrooms',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1567306301408-9b74779a11af',
+        title: 'Tomato basil',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1471357674240-e1a485acb3e1',
+        title: 'Sea star',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1589118949245-7d38baf380d6',
+        title: 'Bike',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e',
+        title: 'Breakfast',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1551782450-a2132b4ba21d',
+        title: 'Burger',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1522770179533-24471fcdba45',
+        title: 'Camera',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1444418776041-9c7e33cc5a9c',
+        title: 'Coffee',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1533827432537-70133748f5c8',
+        title: 'Hats',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1558642452-9d2a7deb7f62',
+        title: 'Honey',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1516802273409-68526ee1bdd6',
+        title: 'Basketball',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1518756131217-31eb79b20e8f',
+        title: 'Fern',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1597645587822-e99fa5d45d25',
+        title: 'Mushrooms',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1567306301408-9b74779a11af',
+        title: 'Tomato basil',
+    },
+    {
+        img: 'https://images.unsplash.com/photo-1471357674240-e1a485acb3e1',
+        title: 'Sea star',
+    }
+];

+ 45 - 0
js/Project/project/src/components/user/index.js

@@ -0,0 +1,45 @@
+import * as React from 'react';
+import CssBaseline from '@mui/material/CssBaseline';
+import Box from '@mui/material/Box';
+import Container from '@mui/material/Container';
+import StandardImageList from './gallery';
+import Divider from '@mui/material/Divider';
+import Grid from '@mui/material/Unstable_Grid2';
+
+
+// import { useEffect, useState } from 'react';
+// import { useParams } from 'react-router';
+
+export default function User() {
+    // console.log(111, user)
+    // const { userId } = useParams()
+    // useEffect(() => { loadUser(userId) }, [userId])
+
+    return (
+        <React.Fragment>
+            <CssBaseline />
+            <Container sx={{ minHeight: '100vh' }} maxWidth="100%">
+                <Box>
+                    <Grid container spacing={2}>
+                        <Grid xs={3} style={{ backgroundColor: "red" }}>
+                            текст
+                        </Grid>
+                        <Grid xs={9} style={{ backgroundColor: "green" }}>
+                            текст
+                        </Grid>
+                    </Grid>
+                </Box>
+                <Divider />
+                <Box >
+                    <StandardImageList />
+                </Box>
+            </Container>
+        </React.Fragment>
+    );
+}
+
+
+
+
+
+