Volddemar4ik 2 years ago
parent
commit
4a900575d7

+ 23 - 0
js/Project/project/.gitignore

@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*

+ 70 - 0
js/Project/project/README.md

@@ -0,0 +1,70 @@
+# Getting Started with Create React App
+
+This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `npm start`
+
+Runs the app in the development mode.\
+Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
+
+The page will reload when you make changes.\
+You may also see any lint errors in the console.
+
+### `npm test`
+
+Launches the test runner in the interactive watch mode.\
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
+
+### `npm run build`
+
+Builds the app for production to the `build` folder.\
+It correctly bundles React in production mode and optimizes the build for the best performance.
+
+The build is minified and the filenames include the hashes.\
+Your app is ready to be deployed!
+
+See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
+
+### `npm run eject`
+
+**Note: this is a one-way operation. Once you `eject`, you can't go back!**
+
+If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
+
+Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
+
+You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
+
+## Learn More
+
+You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
+
+To learn React, check out the [React documentation](https://reactjs.org/).
+
+### Code Splitting
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
+
+### Analyzing the Bundle Size
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
+
+### Making a Progressive Web App
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
+
+### Advanced Configuration
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
+
+### Deployment
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
+
+### `npm run build` fails to minify
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

File diff suppressed because it is too large
+ 30533 - 0
js/Project/project/package-lock.json


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

@@ -0,0 +1,47 @@
+{
+  "name": "project",
+  "version": "0.1.0",
+  "private": true,
+  "dependencies": {
+    "@emotion/react": "^11.10.6",
+    "@emotion/styled": "^11.10.6",
+    "@fontsource/roboto": "^4.5.8",
+    "@mui/icons-material": "^5.11.11",
+    "@mui/material": "^5.11.11",
+    "@testing-library/jest-dom": "^5.16.5",
+    "@testing-library/react": "^13.4.0",
+    "@testing-library/user-event": "^13.5.0",
+    "react": "^18.2.0",
+    "react-dom": "^18.2.0",
+    "react-material-ui-carousel": "^3.4.2",
+    "react-redux": "^8.0.5",
+    "react-scripts": "5.0.1",
+    "redux": "^4.2.1",
+    "redux-thunk": "^2.4.2",
+    "web-vitals": "^2.1.4"
+  },
+  "scripts": {
+    "start": "react-scripts start",
+    "build": "react-scripts build",
+    "test": "react-scripts test",
+    "eject": "react-scripts eject"
+  },
+  "eslintConfig": {
+    "extends": [
+      "react-app",
+      "react-app/jest"
+    ]
+  },
+  "browserslist": {
+    "production": [
+      ">0.2%",
+      "not dead",
+      "not op_mini all"
+    ],
+    "development": [
+      "last 1 chrome version",
+      "last 1 firefox version",
+      "last 1 safari version"
+    ]
+  }
+}

BIN
js/Project/project/public/favicon.ico


BIN
js/Project/project/public/images/avatar.jpeg


BIN
js/Project/project/public/images/image.jpeg


BIN
js/Project/project/public/images/image2.jpeg


BIN
js/Project/project/public/images/image3.jpg


BIN
js/Project/project/public/images/image4.jpeg


+ 45 - 0
js/Project/project/public/index.html

@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="utf-8" />
+  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+  <meta name="viewport" content="width=device-width, initial-scale=1" />
+  <meta name="theme-color" content="#000000" />
+  <meta name="description" content="Web site created using create-react-app" />
+  <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
+  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
+  <!--
+      manifest.json provides metadata used when your web app is installed on a
+      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
+    -->
+  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
+  <!--
+      Notice the use of %PUBLIC_URL% in the tags above.
+      It will be replaced with the URL of the `public` folder during the build.
+      Only files inside the `public` folder can be referenced from the HTML.
+
+      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+      work correctly both with client-side routing and a non-root public URL.
+      Learn how to configure a non-root public URL by running `npm run build`.
+    -->
+  <title>Hipstagram</title>
+</head>
+
+<body>
+  <noscript>You need to enable JavaScript to run this app.</noscript>
+  <div id="root"></div>
+  <!--
+      This HTML file is a template.
+      If you open it directly in the browser, you will see an empty page.
+
+      You can add webfonts, meta tags, or analytics to this file.
+      The build step will place the bundled scripts into the <body> tag.
+
+      To begin the development, run `npm start` or `yarn start`.
+      To create a production bundle, use `npm run build` or `yarn build`.
+    -->
+</body>
+
+</html>

BIN
js/Project/project/public/logo192.png


BIN
js/Project/project/public/logo512.png


+ 25 - 0
js/Project/project/public/manifest.json

@@ -0,0 +1,25 @@
+{
+  "short_name": "React App",
+  "name": "Create React App Sample",
+  "icons": [
+    {
+      "src": "favicon.ico",
+      "sizes": "64x64 32x32 24x24 16x16",
+      "type": "image/x-icon"
+    },
+    {
+      "src": "logo192.png",
+      "type": "image/png",
+      "sizes": "192x192"
+    },
+    {
+      "src": "logo512.png",
+      "type": "image/png",
+      "sizes": "512x512"
+    }
+  ],
+  "start_url": ".",
+  "display": "standalone",
+  "theme_color": "#000000",
+  "background_color": "#ffffff"
+}

+ 3 - 0
js/Project/project/public/robots.txt

@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:

+ 38 - 0
js/Project/project/src/App.css

@@ -0,0 +1,38 @@
+.App {
+  text-align: center;
+}
+
+.App-logo {
+  height: 40vmin;
+  pointer-events: none;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+  .App-logo {
+    animation: App-logo-spin infinite 20s linear;
+  }
+}
+
+.App-header {
+  background-color: #282c34;
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  font-size: calc(10px + 2vmin);
+  color: white;
+}
+
+.App-link {
+  color: #61dafb;
+}
+
+@keyframes App-logo-spin {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
+  }
+}

+ 327 - 0
js/Project/project/src/App.js

@@ -0,0 +1,327 @@
+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 { 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 actionPostsFind = () => actionPromise('PostsFind', gql(`query baseCategory($searchVariablesCategory: String){
+//         PostsFind(query: $searchVariablesCategory){
+//             _id name parent {
+//                 _id
+//                 name
+//             }
+//         }
+//     }`, {
+//     searchVariablesCategory: JSON.stringify([{ parent: null }])
+// }))
+
+
+
+
+const store = createStore(promiseReducer, applyMiddleware(thunk))
+store.subscribe(() => console.log(store.getState()))
+
+store.dispatch(actionfindPosts())
+// store.dispatch(actionCategoryFind())
+
+
+
+
+
+
+
+
+
+
+
+const history = createHistory()
+
+const Autorization = () =>
+    <div>
+        Авторизация
+    </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 PageAbout = () =>
+    <div>
+        Страница "О нас"
+    </div>
+
+const Page404 = () =>
+    <div>
+        NOT FOUND
+    </div>
+
+
+// ==================================================
+// страница одного поста
+
+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)
+// ====================================================
+
+
+function App() {
+    return (
+        <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={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 /> */}
+
+
+                            </Switch>
+                        </main>
+                        <footer style={{ backgroundColor: '#dbffe7' }}>Hipstagram from Volddemar4ik</footer>
+                    </section>
+                </div>
+            </Router >
+        </Provider>
+    );
+}
+
+export default App;

+ 8 - 0
js/Project/project/src/App.test.js

@@ -0,0 +1,8 @@
+import { render, screen } from '@testing-library/react';
+import App from './App';
+
+test('renders learn react link', () => {
+  render(<App />);
+  const linkElement = screen.getByText(/learn react/i);
+  expect(linkElement).toBeInTheDocument();
+});

+ 150 - 0
js/Project/project/src/App_test.js

@@ -0,0 +1,150 @@
+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 Box from '@mui/material/Box';
+import Stack from '@mui/material/Stack';
+import Paper from '@mui/material/Paper';
+import { styled } from '@mui/material/styles';
+
+import createHistory from "history/createBrowserHistory";
+
+
+const history = createHistory()
+
+const Autorization = () =>
+  <div>
+    Авторизация
+  </div>
+
+
+const Registration = () =>
+  <div>
+    Регистрация
+  </div>
+
+
+const MainPage = () =>
+  <div>
+    Главная страница
+  </div>
+
+
+const Direct = () =>
+  <div>
+    Direct
+  </div>
+
+
+// блок поста альтернативный
+const Item = styled(Paper)(({ theme }) => ({
+  backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
+  width: 500
+}));
+
+const Feed = () => {
+  return (
+    <Box sx={{
+      width: '500',
+      height: '600',
+      margin: '10, 20'
+    }}>
+      {/* spacing - это отступ между карточками в ленте */}
+      <Stack spacing={1}>
+        <Item>
+          <RecipeReviewCard />
+        </Item>
+        <Item>
+          <RecipeReviewCard />
+        </Item>
+        <Item>
+          <RecipeReviewCard />
+        </Item>
+      </Stack>
+    </Box >
+  );
+}
+
+
+const CreatePost = () =>
+  <div>
+    Страницв создания поста
+  </div>
+
+
+const User = () =>
+  <div>
+    Страница юзера
+  </div>
+
+
+const PageAbout = () =>
+  <div>
+    Страница "О нас"
+  </div>
+
+const Page404 = () =>
+  <div>
+    NOT FOUND
+  </div>
+
+const Comments = ({ match: { params: { user, postId } } }) =>
+  <div>
+    <div>{user} and {postId}</div>
+    тут будут отображаться все комментарии под постом
+  </div>
+
+
+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 >
+  );
+}
+
+export default App;

+ 16 - 0
js/Project/project/src/index.css

@@ -0,0 +1,16 @@
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+  /* мои стили */
+  height: 100%;
+}
+
+code {
+  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+    monospace;
+}

+ 19 - 0
js/Project/project/src/index.js

@@ -0,0 +1,19 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.css';
+import App from './App';
+import reportWebVitals from './reportWebVitals';
+import { Provider } from 'react-redux';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render(
+  // <React.StrictMode>
+  // <Provider>
+    <App />
+  // </Provider>  // </React.StrictMode>
+);
+
+// If you want to start measuring performance in your app, pass a function
+// to log results (for example: reportWebVitals(console.log))
+// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
+reportWebVitals();

File diff suppressed because it is too large
+ 1 - 0
js/Project/project/src/logo.svg


+ 56 - 0
js/Project/project/src/post/carousel.js

@@ -0,0 +1,56 @@
+// 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 = [
+        {
+            // 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>
+    )
+}

+ 210 - 0
js/Project/project/src/post/index.js

@@ -0,0 +1,210 @@
+import * as React from 'react';
+import Card from '@mui/material/Card';
+import CardHeader from '@mui/material/CardHeader';
+import CardMedia from '@mui/material/CardMedia';
+import CardContent from '@mui/material/CardContent';
+import CardActions from '@mui/material/CardActions';
+import Avatar from '@mui/material/Avatar';
+import IconButton from '@mui/material/IconButton';
+import Typography from '@mui/material/Typography';
+import MoreVertIcon from '@mui/icons-material/MoreVert';
+import FavoriteBorderRoundedIcon from '@mui/icons-material/FavoriteBorderRounded';
+import SendIcon from '@mui/icons-material/Send';
+import ChatBubbleOutlineIcon from '@mui/icons-material/ChatBubbleOutline';
+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';
+
+
+
+const url = 'http://hipstagram.node.ed.asmer.org.ua/'
+
+
+// export default function RecipeReviewCard({ date, title, text, likesCount, nickName, login }) {
+export default 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)
+    }
+
+
+
+
+    // // сама карусель - ее нужно вынеси в отдельный контенйре
+
+    // 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
+                avatar={
+                    <Avatar
+                        alt=""
+                        src="/images/avatar.jpeg"
+                        sx={{ width: 50, height: 50 }}
+                        style={{ margin: '5px', border: '3px solid black', borderRadius: '50%', flexShrink: '0', overflow: 'hidden' }}
+                    />
+                }
+                action={   // троеточие в хедере
+                    <IconButton aria-label="settings">
+                        <MoreVertIcon />
+                    </IconButton>
+                }
+                // title="Author Author(ович)" // автор поста
+                // title={nickName ? nickName : login} // автор поста
+                title={postData.owner.nick ? postData.owner.nick : postData.owner.login} // автор поста
+                subheader={dateofPostParse} // дата создания поста
+            />
+            <CardMedia
+            // component="img"
+            // height="100%" // высота картинки
+            // // image="/images/image.jpeg" // ссылка на картинку в посте
+            // image={imgOfPost ? imgOfPost : "/images/image.jpeg"} // ссылка на картинку в посте
+            // alt="Котики" // описание картинки
+            >
+                <MyCarousel />
+            </CardMedia>
+            <CardActions disableSpacing>
+                <Box sx={{ flexGrow: 1 }}>
+                    <Grid container spacing={2}>
+                        <Grid
+                            xs={12}
+                            container
+                            justifyContent="space-between"
+                            alignItems="center"
+                            flexDirection={{ xs: 'column', sm: 'row' }}
+                            sx={{ fontSize: '12px' }}
+                        >
+                            <Grid container columnSpacing={1} sx={{ order: { xs: 2, sm: 1 } }}>
+                                <Grid>
+                                    <IconButton aria-label="add to favorites">
+                                        <FavoriteBorderRoundedIcon />
+                                    </IconButton>
+                                </Grid>
+                                <Grid>
+                                    <IconButton>
+                                        <ChatBubbleOutlineIcon />
+                                    </IconButton>
+                                </Grid>
+                                <Grid>
+                                    <IconButton aria-label="share">
+                                        <SendIcon />
+                                    </IconButton>
+                                </Grid>
+                            </Grid>
+                            <Grid sx={{ order: { xs: 1, sm: 2 } }}>
+                                <IconButton>
+                                    <TurnedInNotIcon />
+                                </IconButton>
+                            </Grid>
+                        </Grid>
+                    </Grid>
+                </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>
+    )
+}
+
+
+
+

+ 13 - 0
js/Project/project/src/reportWebVitals.js

@@ -0,0 +1,13 @@
+const reportWebVitals = onPerfEntry => {
+  if (onPerfEntry && onPerfEntry instanceof Function) {
+    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+      getCLS(onPerfEntry);
+      getFID(onPerfEntry);
+      getFCP(onPerfEntry);
+      getLCP(onPerfEntry);
+      getTTFB(onPerfEntry);
+    });
+  }
+};
+
+export default reportWebVitals;

+ 5 - 0
js/Project/project/src/setupTests.js

@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';