Parcourir la source

done some blue prients

unknown il y a 2 ans
commit
5fffb6d544
36 fichiers modifiés avec 29428 ajouts et 0 suppressions
  1. 14 0
      .babelrc
  2. 9 0
      .browserslistrc
  3. 11 0
      .editorconfig
  4. 68 0
      .gitignore
  5. 12 0
      .prettierrc
  6. 95 0
      README.md
  7. 28336 0
      package-lock.json
  8. 68 0
      package.json
  9. 5 0
      postcss.config.js
  10. 25 0
      src/index.html
  11. 2 0
      src/index.js
  12. 135 0
      src/java-script/api-data/index.js
  13. 82 0
      src/java-script/hw.js
  14. 24 0
      src/java-script/redux/authorization/action/index.js
  15. 50 0
      src/java-script/redux/authorization/operations/index.js
  16. 27 0
      src/java-script/redux/authorization/reducer/index.js
  17. 4 0
      src/java-script/redux/authorization/selector/index.js
  18. 24 0
      src/java-script/redux/categories/action/index.js
  19. 36 0
      src/java-script/redux/categories/operations/index.js
  20. 29 0
      src/java-script/redux/categories/reducer/index.js
  21. 4 0
      src/java-script/redux/categories/selector/index.js
  22. 24 0
      src/java-script/redux/goods/action/index.js
  23. 36 0
      src/java-script/redux/goods/operations/index.js
  24. 29 0
      src/java-script/redux/goods/reducer/index.js
  25. 4 0
      src/java-script/redux/goods/selector/index.js
  26. 7 0
      src/java-script/redux/loading/action/index.js
  27. 7 0
      src/java-script/redux/loading/reducer/index.js
  28. 3 0
      src/java-script/redux/loading/selector/index.js
  29. 23 0
      src/java-script/redux/rootReducer/index.js
  30. 14 0
      src/java-script/redux/store/index.js
  31. 35 0
      src/styles.css
  32. 7 0
      webpack/config.js
  33. 38 0
      webpack/configs/development.js
  34. 58 0
      webpack/configs/production.js
  35. 75 0
      webpack/configs/shared.js
  36. 8 0
      webpack/utils/paths.js

+ 14 - 0
.babelrc

@@ -0,0 +1,14 @@
+{
+  "presets": [
+    [
+      "@babel/preset-env",
+      {
+        "modules": false,
+        "loose": true,
+        "useBuiltIns": "usage",
+        "corejs": 3
+      }
+    ]
+  ],
+  "plugins": ["@babel/plugin-proposal-class-properties"]
+}

+ 9 - 0
.browserslistrc

@@ -0,0 +1,9 @@
+[development]
+last 1 chrome version
+last 1 firefox version
+last 1 safari version
+
+[production]
+>0.2%
+not dead
+not op_mini all

+ 11 - 0
.editorconfig

@@ -0,0 +1,11 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false

+ 68 - 0
.gitignore

@@ -0,0 +1,68 @@
+# production
+/build
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Typescript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local

+ 12 - 0
.prettierrc

@@ -0,0 +1,12 @@
+{
+  "printWidth": 80,
+  "tabWidth": 2,
+  "useTabs": false,
+  "semi": true,
+  "singleQuote": true,
+  "trailingComma": "all",
+  "bracketSpacing": true,
+  "jsxBracketSameLine": false,
+  "arrowParens": "avoid",
+  "proseWrap": "always"
+}

Fichier diff supprimé car celui-ci est trop grand
+ 95 - 0
README.md


Fichier diff supprimé car celui-ci est trop grand
+ 28336 - 0
package-lock.json


+ 68 - 0
package.json

@@ -0,0 +1,68 @@
+{
+  "name": "webpack-starter-kit",
+  "version": "1.1.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "start": "webpack-dev-server --env.mode development --config ./webpack/config.js",
+    "build": "webpack --env.mode production --config ./webpack/config.js",
+    "predeploy": "npm run build",
+    "deploy": "gh-pages -d build"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/luxplanjay/webpack-starter-kit.git"
+  },
+  "keywords": [],
+  "author": "Alexander Repeta <alexander.repeta@gmail.com>",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/luxplanjay/webpack-starter-kit/issues"
+  },
+  "homepage": "https://github.com/grisha19961116/goit-js-home-wok-10",
+  "devDependencies": {
+    "@babel/core": "^7.8.7",
+    "@babel/plugin-proposal-class-properties": "^7.8.3",
+    "@babel/preset-env": "^7.11.5",
+    "@pnotify/core": "^5.1.2",
+    "autoprefixer": "^9.7.4",
+    "babel-loader": "^8.0.6",
+    "clean-webpack-plugin": "^3.0.0",
+    "css-loader": "^3.4.2",
+    "file-loader": "^6.0.0",
+    "friendly-errors-webpack-plugin": "^1.7.0",
+    "gh-pages": "^2.2.0",
+    "handlebars-loader": "^1.7.1",
+    "html-loader": "^0.5.5",
+    "html-webpack-plugin": "^3.2.0",
+    "img-loader": "^3.0.1",
+    "mini-css-extract-plugin": "^0.9.0",
+    "node-sass": "^4.13.1",
+    "optimize-css-assets-webpack-plugin": "^5.0.3",
+    "postcss-loader": "^3.0.0",
+    "sass-loader": "^8.0.2",
+    "style-loader": "^1.1.3",
+    "url-loader": "^4.0.0",
+    "webpack": "^4.42.0",
+    "webpack-cli": "^3.3.11",
+    "webpack-dev-server": "^3.10.3",
+    "webpack-merge": "^4.2.2",
+    "webpackbar": "^4.0.0"
+  },
+  "dependencies": {
+    "@reduxjs/toolkit": "^1.5.0",
+    "basiclightbox": "^5.0.3",
+    "core-js": "^3.6.4",
+    "handlebars": "^4.7.6",
+    "infinite-scroll": "^3.0.6",
+    "lodash.debounce": "^4.0.8",
+    "lodash.throttle": "^4.1.1",
+    "material-design-icons": "^3.0.1",
+    "pnotify": "^5.1.2",
+    "redux": "^4.0.5",
+    "redux-devtools-extension": "^2.13.8",
+    "redux-logger": "^3.0.6",
+    "redux-persist": "^6.0.0",
+    "redux-toolkit": "^1.1.2"
+  }
+}

+ 5 - 0
postcss.config.js

@@ -0,0 +1,5 @@
+const autoprefixer = require('autoprefixer');
+
+module.exports = {
+  plugins: [autoprefixer]
+};

+ 25 - 0
src/index.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
+    <title>Homework</title>
+    <link rel="stylesheet" href="styles.css" />
+  </head>
+  <body>
+    <p id="statusTitle" class="status"></p>
+    <form id="authForm" class="wrapperAuth">
+      <input placeholder="Write down email" />
+      <input placeholder="Write down password" />
+      <button id="login" class="login" type="button">Login</button>
+      <button id="register" class="register" type="button">Register</button>
+    </form>
+    <button id="categoriesBtn" class="categoriesBtn" type="button">
+      Categories
+    </button>
+    <button id="goodsBtn" class="goodsBtn" type="button">Goods</button>
+    <ul id="categoriesList" class="categoriesGoodsList"></ul>
+    <ul id="goodsList" class="categoriesGoodsList"></ul>
+  </body>
+</html>

+ 2 - 0
src/index.js

@@ -0,0 +1,2 @@
+import './styles.css';
+import './java-script/hw.js';

+ 135 - 0
src/java-script/api-data/index.js

@@ -0,0 +1,135 @@
+const getGQL = url => async (query, variables) => {
+  try {
+    const token = localStorage.token;
+    const res = await fetch(url, {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: token ? 'Bearer ' + token : '',
+      },
+      body: JSON.stringify({ query, variables }),
+    });
+    return res.json();
+  } catch (e) {
+    return e;
+  }
+};
+
+const gql = getGQL('http://shop-roles.asmer.fs.a-level.com.ua/graphql');
+
+const loginGQL = async (login, password) => {
+  try {
+    const { data } = await gql(
+      `
+query log($login:String, $password:String){
+        login(login:$login, password:$password)
+    }`,
+      { login, password },
+    );
+    const token = data.login;
+    if (token) localStorage.token = token;
+    return token;
+  } catch (e) {
+    console.error(e);
+  }
+};
+
+const registerGQL = async (login, password) => {
+  try {
+    const { data } = await gql(
+      `mutation register($login:String, $password:String){
+        UserUpsert(user: {login:$login, password:$password}){
+			_id,login
+		}
+    }`,
+      { login, password },
+    );
+    return data.UserUpsert;
+  } catch (e) {
+    console.error(e);
+  }
+};
+
+const categoriesGQL = async () => {
+  try {
+    const { data } = await gql(
+      `query allCategories{
+		CategoryFind(query:"[{}]"){
+          _id,
+          name,
+		  createdAt
+		}
+	}`,
+      {},
+    );
+    return data.CategoryFind;
+  } catch (e) {
+    console.error(e);
+  }
+};
+
+const goodsGQL = async () => {
+  try {
+    const { data } = await gql(
+      `query allGoods{
+		GoodFind(query:"[{}]"){
+          _id
+          name,
+		  createdAt,
+		  price,
+		}
+	}`,
+      {},
+    );
+    return data.GoodFind;
+  } catch (e) {
+    console.error(e);
+  }
+};
+
+const categoryById = async _id => {
+  try {
+    const { data } = await gql(
+      `query categoryById($id:String){
+		CategoryFindOne(query:$id){
+			_id,name,
+			goods {
+				_id,createdAt,name
+			}
+		 },
+	}`,
+      { id: JSON.stringify([{ _id }]) },
+    );
+    return data.CategoryFindOne;
+  } catch (e) {
+    console.error(e);
+  }
+};
+
+const goodById = async _id => {
+  try {
+    const { data } = await gql(
+      `query findById($id:String){
+        GoodFindOne (query:$id){
+            _id name price description images  {
+				url
+			}
+        }
+    }`,
+      { id: JSON.stringify([{ _id }]) },
+    );
+
+    return data.GoodFindOne;
+  } catch (e) {
+    console.error(e);
+  }
+};
+
+export {
+  loginGQL,
+  registerGQL,
+  categoriesGQL,
+  goodsGQL,
+  categoryById,
+  goodById,
+};

+ 82 - 0
src/java-script/hw.js

@@ -0,0 +1,82 @@
+import { store } from './redux/store';
+import { asyncLogin, asyncCreateUser } from './redux/authorization/operations';
+import {
+  asyncGetCategories,
+  asyncGetCategoryById,
+} from './redux/categories/operations';
+import { asyncGetGoods, asyncGetGoodById } from './redux/goods/operations';
+import { getToken } from './redux/authorization/selector';
+import { getCategories, getCategory } from './redux/categories/selector';
+import { getGoods, getGood } from './redux/goods/selector/';
+const { dispatch, subscribe, getState } = store;
+
+const statusHtml = document.getElementById('statusTitle');
+const formAuthHtml = document.getElementById('authForm');
+const changeStatus = token => {
+  if (token) {
+    statusHtml.textContent = 'Status : logIn';
+    statusHtml.style.color = 'green';
+  } else {
+    statusHtml.textContent = 'Status : Not logIn';
+    statusHtml.style.color = 'red';
+  }
+};
+
+subscribe(() => changeStatus(getToken(getState())));
+
+const categoriesList = document.getElementById('categoriesList');
+const goodsList = document.getElementById('goodsList');
+
+const changeListsState = (data, root) => {
+  root.innerHTML = '';
+  const arr = data.map(({ _id, name, createdAt }) => {
+    const li = document.createElement('li');
+    const id = document.createElement('span');
+    id.textContent = `id : ${_id}`;
+    const nameHtml = document.createElement('span');
+    nameHtml.textContent = `name : ${name}`;
+    const created = document.createElement('span');
+    created.textContent = `createdAt : ${createdAt}`;
+    li.id = _id;
+    li.append(id, nameHtml, created);
+    console.log(li);
+    return li;
+  });
+  root.append(...arr);
+};
+
+subscribe(() => changeListsState(getCategories(getState()), categoriesList));
+
+subscribe(() => changeListsState(getGoods(getState()), goodsList));
+
+const handleAuthForm = async function (e) {
+  e.preventDefault();
+  const id = e.target.id;
+  const form = this.children;
+  const login = form[0].value;
+  const password = form[1].value;
+  if (login === '' || password === '') return;
+  if (id === 'login') {
+    dispatch(asyncLogin(login, password));
+  } else if (id === 'register') {
+    dispatch(asyncCreateUser(login, password));
+  }
+};
+
+formAuthHtml.addEventListener('click', handleAuthForm);
+
+const handleLits = async function (e) {
+  e.preventDefault();
+  const id = e.target.id;
+  if (id === 'categoriesBtn') {
+    dispatch(asyncGetCategories());
+  } else if (id === 'goodsBtn') {
+    dispatch(asyncGetGoods());
+  }
+};
+
+const categoriesLinkHtml = document.getElementById('categoriesBtn');
+const goodsLinkHtml = document.getElementById('goodsBtn');
+
+categoriesLinkHtml.addEventListener('click', handleLits);
+goodsLinkHtml.addEventListener('click', handleLits);

+ 24 - 0
src/java-script/redux/authorization/action/index.js

@@ -0,0 +1,24 @@
+import { createAction } from '@reduxjs/toolkit';
+
+const actionLogInSuccess = createAction('login/success', value => ({
+  payload: value,
+}));
+
+const actionLogInReject = createAction('login/reject', value => ({
+  payload: value,
+}));
+
+const actionLogOutSuccess = createAction('logout/success', value => ({
+  payload: value,
+}));
+
+const actionLogOutReject = createAction('logout/reject', value => ({
+  payload: value,
+}));
+
+export {
+  actionLogInSuccess,
+  actionLogInReject,
+  actionLogOutSuccess,
+  actionLogOutReject,
+};

+ 50 - 0
src/java-script/redux/authorization/operations/index.js

@@ -0,0 +1,50 @@
+import { actionIsLoading } from '../../loading/action';
+
+import {
+  actionLogInSuccess,
+  actionLogInReject,
+  actionLogOutSuccess,
+  actionLogOutReject,
+} from '../action';
+
+import { loginGQL, registerGQL } from '../../../api-data';
+
+const asyncLogin = (login, password) => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    const token = await loginGQL(login, password);
+    console.log(token);
+    dispatch(actionLogInSuccess({ login, token }));
+  } catch (e) {
+    dispatch(actionLogInReject());
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+const asyncLogout = () => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    dispatch(actionLogOutSuccess());
+  } catch (e) {
+    dispatch(actionLogOutReject());
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+const asyncCreateUser = (login, password) => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    await registerGQL(login, password);
+    const token = await loginGQL(login, password);
+    console.log(token);
+    dispatch(actionLogInSuccess({ login, token }));
+  } catch (e) {
+    console.error('Credentials have already used', e);
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+export { asyncLogin, asyncLogout, asyncCreateUser };

+ 27 - 0
src/java-script/redux/authorization/reducer/index.js

@@ -0,0 +1,27 @@
+import { createReducer } from '@reduxjs/toolkit';
+
+import {
+  actionLogInSuccess,
+  actionLogInReject,
+  actionLogOutSuccess,
+  actionLogOutReject,
+} from '../action';
+
+const initialState = { login: '', token: '' };
+
+const reducerAuthorization = createReducer(initialState, {
+  [actionLogInSuccess]: (_, { payload }) => {
+    return payload;
+  },
+  [actionLogInReject]: (state, _) => {
+    return state;
+  },
+  [actionLogOutSuccess]: () => {
+    return initialState;
+  },
+  [actionLogOutReject]: (state, _) => {
+    return state;
+  },
+});
+
+export default reducerAuthorization;

+ 4 - 0
src/java-script/redux/authorization/selector/index.js

@@ -0,0 +1,4 @@
+const getToken = state => state.authorization.token;
+const getLogin = state => state.authorization.login;
+
+export { getToken, getLogin };

+ 24 - 0
src/java-script/redux/categories/action/index.js

@@ -0,0 +1,24 @@
+import { createAction } from '@reduxjs/toolkit';
+
+const actionCategoriesSuccess = createAction('categories/success', value => ({
+  payload: value,
+}));
+
+const actionCategoriesReject = createAction('categories/reject', value => ({
+  payload: value,
+}));
+
+const actionCategorySuccess = createAction('category/success', value => ({
+  payload: value,
+}));
+
+const actionCategoryReject = createAction('category/reject', value => ({
+  payload: value,
+}));
+
+export {
+  actionCategoriesSuccess,
+  actionCategoriesReject,
+  actionCategorySuccess,
+  actionCategoryReject,
+};

+ 36 - 0
src/java-script/redux/categories/operations/index.js

@@ -0,0 +1,36 @@
+import { actionIsLoading } from '../../loading/action';
+
+import {
+  actionCategoriesSuccess,
+  actionCategoriesReject,
+  actionCategorySuccess,
+  actionCategoryReject,
+} from '../action';
+
+import { categoriesGQL, categoryById } from '../../../api-data';
+
+const asyncGetCategories = () => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    const data = await categoriesGQL();
+    dispatch(actionCategoriesSuccess(data));
+  } catch (e) {
+    dispatch(actionCategoriesReject());
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+const asyncGetCategoryById = id => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    const data = await categoryById(id);
+    dispatch(actionCategorySuccess(data));
+  } catch (e) {
+    dispatch(actionCategoryReject());
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+export { asyncGetCategories, asyncGetCategoryById };

+ 29 - 0
src/java-script/redux/categories/reducer/index.js

@@ -0,0 +1,29 @@
+import { createReducer } from '@reduxjs/toolkit';
+
+import {
+  actionCategoriesSuccess,
+  actionCategoriesReject,
+  actionCategorySuccess,
+  actionCategoryReject,
+} from '../action';
+
+const initialState = { categories: [], category: {} };
+
+const reducerCategories = createReducer(initialState, {
+  [actionCategoriesSuccess]: (state, { payload: categories }) => {
+    const category = state.category;
+    return { categories, category };
+  },
+  [actionCategoriesReject]: (state, _) => {
+    return state;
+  },
+  [actionCategorySuccess]: (state, { payload: category }) => {
+    const categories = state.category;
+    return { categories, category };
+  },
+  [actionCategoryReject]: (state, _) => {
+    return state;
+  },
+});
+
+export default reducerCategories;

+ 4 - 0
src/java-script/redux/categories/selector/index.js

@@ -0,0 +1,4 @@
+const getCategories = state => state.categories.categories;
+const getCategory = state => state.categories.category;
+
+export { getCategories, getCategory };

+ 24 - 0
src/java-script/redux/goods/action/index.js

@@ -0,0 +1,24 @@
+import { createAction } from '@reduxjs/toolkit';
+
+const actionGoodsSuccess = createAction('goods/success', value => ({
+  payload: value,
+}));
+
+const actionGoodsReject = createAction('goods/reject', value => ({
+  payload: value,
+}));
+
+const actionGoodSuccess = createAction('good/success', value => ({
+  payload: value,
+}));
+
+const actionGoodReject = createAction('good/reject', value => ({
+  payload: value,
+}));
+
+export {
+  actionGoodsSuccess,
+  actionGoodsReject,
+  actionGoodSuccess,
+  actionGoodReject,
+};

+ 36 - 0
src/java-script/redux/goods/operations/index.js

@@ -0,0 +1,36 @@
+import { actionIsLoading } from '../../loading/action';
+
+import {
+  actionGoodsSuccess,
+  actionGoodsReject,
+  actionGoodSuccess,
+  actionGoodReject,
+} from '../action';
+
+import { goodsGQL, goodById } from '../../../api-data';
+
+const asyncGetGoods = () => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    const data = await goodsGQL();
+    dispatch(actionGoodsSuccess(data));
+  } catch (e) {
+    dispatch(actionGoodsReject());
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+const asyncGetGoodById = id => async dispatch => {
+  try {
+    dispatch(actionIsLoading(true));
+    const data = await goodById(id);
+    dispatch(actionGoodSuccess(data));
+  } catch (e) {
+    dispatch(actionGoodReject());
+  } finally {
+    dispatch(actionIsLoading(false));
+  }
+};
+
+export { asyncGetGoods, asyncGetGoodById };

+ 29 - 0
src/java-script/redux/goods/reducer/index.js

@@ -0,0 +1,29 @@
+import { createReducer } from '@reduxjs/toolkit';
+
+import {
+  actionGoodsSuccess,
+  actionGoodsReject,
+  actionGoodSuccess,
+  actionGoodReject,
+} from '../action';
+
+const initialState = { goods: [], good: {} };
+
+const reducerGoods = createReducer(initialState, {
+  [actionGoodsSuccess]: (state, { payload: goods }) => {
+    const good = state.good;
+    return { goods, good };
+  },
+  [actionGoodsReject]: (state, _) => {
+    return state;
+  },
+  [actionGoodSuccess]: (state, { payload: good }) => {
+    const goods = state.goods;
+    return { goods, good };
+  },
+  [actionGoodReject]: (state, _) => {
+    return state;
+  },
+});
+
+export default reducerGoods;

+ 4 - 0
src/java-script/redux/goods/selector/index.js

@@ -0,0 +1,4 @@
+const getGoods = state => state.goods.goods;
+const getGood = state => state.goods.good;
+
+export { getGoods, getGood };

+ 7 - 0
src/java-script/redux/loading/action/index.js

@@ -0,0 +1,7 @@
+import { createAction } from '@reduxjs/toolkit';
+
+const actionIsLoading = createAction('fetch/loading', value => ({
+  payload: value,
+}));
+
+export { actionIsLoading };

+ 7 - 0
src/java-script/redux/loading/reducer/index.js

@@ -0,0 +1,7 @@
+import { createReducer } from '@reduxjs/toolkit';
+import { actionIsLoading } from '../action';
+
+const reducerLoading = createReducer(false, {
+  [actionIsLoading]: (_, { payload }) => payload,
+});
+export default reducerLoading;

+ 3 - 0
src/java-script/redux/loading/selector/index.js

@@ -0,0 +1,3 @@
+const getLoad = state => state.isLoading;
+
+export { getLoad };

+ 23 - 0
src/java-script/redux/rootReducer/index.js

@@ -0,0 +1,23 @@
+import { combineReducers } from '@reduxjs/toolkit';
+import { persistReducer } from 'redux-persist';
+import storage from 'redux-persist/lib/storage';
+
+import reducerCategories from '../categories/reducer';
+import reducerGoods from '../goods/reducer';
+import reducerLoading from '../loading/reducer';
+import reducerAuthorization from '../authorization/reducer';
+
+const authorizationPersistConfig = {
+  key: 'token',
+  storage: storage,
+};
+
+export const rootReducer = combineReducers({
+  categories: reducerCategories,
+  goods: reducerGoods,
+  isLoading: reducerLoading,
+  authorization: persistReducer(
+    authorizationPersistConfig,
+    reducerAuthorization,
+  ),
+});

+ 14 - 0
src/java-script/redux/store/index.js

@@ -0,0 +1,14 @@
+import { createStore, applyMiddleware } from 'redux';
+import thunk from 'redux-thunk';
+import { persistStore } from 'redux-persist';
+import { composeWithDevTools } from 'redux-devtools-extension';
+
+import { rootReducer } from '../rootReducer';
+
+const composeEnhancers = composeWithDevTools({});
+const store = createStore(
+  rootReducer,
+  composeEnhancers(applyMiddleware(thunk)),
+);
+const persistor = persistStore(store);
+export { store, persistor };

+ 35 - 0
src/styles.css

@@ -0,0 +1,35 @@
+body {
+    background-color: rgb(243, 243, 245);
+}
+
+.wrapperAuth{
+    padding-top: 80px;
+    width: 100%;
+    margin: 0 auto;
+    padding-bottom: 30px;
+}
+
+.status{
+    position: absolute;
+    content: "";
+    position: 0;
+    font-size: 30px;
+}
+
+.categoriesBtn , .goodsBtn{
+    background-color: yellow;
+    color: rgb(8, 92, 15);
+    font-size: 30px;
+}
+
+
+
+.categoriesGoodsList{
+    background-color: rgb(71, 71, 11);
+    color: rgb(200, 200, 200);
+    font-size: 30px;
+}
+
+span {
+    margin-right: 10px;
+}

+ 7 - 0
webpack/config.js

@@ -0,0 +1,7 @@
+const webpackMerge = require('webpack-merge');
+const loadSharedConfig = require('./configs/shared');
+
+const loadModeConfig = env => require(`./configs/${env.mode}`)(env);
+
+module.exports = env =>
+  webpackMerge(loadSharedConfig(env), loadModeConfig(env));

+ 38 - 0
webpack/configs/development.js

@@ -0,0 +1,38 @@
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const paths = require('../utils/paths');
+
+module.exports = env => ({
+  devtool: 'cheap-eval-source-map',
+  output: {
+    filename: '[name].js',
+  },
+  module: {
+    rules: [
+      {
+        test: /\.css$/,
+        use: ['style-loader', 'css-loader', 'postcss-loader'],
+      },
+      {
+        test: /\.scss$/,
+        use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
+      },
+    ],
+  },
+  plugins: [
+    new HtmlWebpackPlugin({
+      template: './index.html',
+    }),
+  ],
+  devServer: {
+    contentBase: paths.BUILD_DIR,
+    publicPath: '',
+    historyApiFallback: true,
+    compress: true,
+    port: 4042,
+    noInfo: true,
+    quiet: true,
+    clientLogLevel: 'warning',
+    stats: 'errors-only',
+    open: true,
+  },
+});

+ 58 - 0
webpack/configs/production.js

@@ -0,0 +1,58 @@
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
+
+module.exports = env => ({
+  devtool: 'source-map',
+  output: {
+    filename: '[name].[contenthash].js',
+  },
+  optimization: {
+    moduleIds: 'hashed',
+    runtimeChunk: 'single',
+    splitChunks: {
+      cacheGroups: {
+        vendor: {
+          test: /[\\/]node_modules[\\/]/,
+          name: 'vendors',
+          chunks: 'all',
+        },
+      },
+    },
+  },
+  module: {
+    rules: [
+      {
+        test: /\.css$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
+      },
+      {
+        test: /\.scss$/,
+        use: [
+          MiniCssExtractPlugin.loader,
+          'css-loader',
+          'postcss-loader',
+          'sass-loader',
+        ],
+      },
+    ],
+  },
+  plugins: [
+    new HtmlWebpackPlugin({
+      template: './index.html',
+      minify: {
+        collapseWhitespace: true,
+        removeComments: true,
+        removeRedundantAttributes: true,
+        removeScriptTypeAttributes: true,
+        removeStyleLinkTypeAttributes: true,
+        useShortDoctype: true,
+      },
+    }),
+    new MiniCssExtractPlugin({
+      filename: '[name].[contenthash].css',
+      chunkFilename: '[name].[id].[contenthash].css',
+    }),
+    new OptimizeCssAssetsPlugin({}),
+  ],
+});

+ 75 - 0
webpack/configs/shared.js

@@ -0,0 +1,75 @@
+const { CleanWebpackPlugin } = require('clean-webpack-plugin');
+const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
+const WebpackBar = require('webpackbar');
+const paths = require('../utils/paths');
+
+module.exports = env => ({
+  mode: env.mode,
+  context: paths.SRC_DIR,
+  entry: './index.js',
+  output: {
+    path: paths.BUILD_DIR,
+  },
+  module: {
+    rules: [
+      {
+        test: /\.js$/,
+        include: paths.SRC_DIR,
+        use: ['babel-loader'],
+      },
+      {
+        test: /\.(gif|png|jpe?g|svg)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              name: '[path][name].[ext]',
+              limit: 8192,
+              esModule: false,
+            },
+          },
+          'img-loader',
+        ],
+      },
+      {
+        test: /\.woff(2)?(\?[a-z0-9#=&.]+)?$/,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              name: '[name].[ext]',
+              outputPath: 'fonts/',
+              limit: 10000,
+              mimetype: 'application/font-woff',
+            },
+          },
+        ],
+      },
+      {
+        test: /\.(ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
+        use: [
+          {
+            loader: 'file-loader',
+            options: {
+              name: '[name].[ext]',
+              outputPath: 'fonts/',
+            },
+          },
+        ],
+      },
+      {
+        test: /\.html$/,
+        use: 'html-loader',
+      },
+      {
+        test: /\.hbs$/,
+        use: 'handlebars-loader',
+      },
+    ],
+  },
+  plugins: [
+    new CleanWebpackPlugin(),
+    new FriendlyErrorsWebpackPlugin(),
+    new WebpackBar(),
+  ],
+});

+ 8 - 0
webpack/utils/paths.js

@@ -0,0 +1,8 @@
+const path = require('path');
+
+const paths = {
+  SRC_DIR: path.resolve(__dirname, '../../src'),
+  BUILD_DIR: path.resolve(__dirname, '../../build'),
+};
+
+module.exports = paths;