diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index ca89b74..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.fontSize": 16 -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index b87cb00..0000000 --- a/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# 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 the browser. - -The page will reload if you make edits.\ -You will 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/). diff --git a/react-burger/package-lock.json b/package-lock.json similarity index 98% rename from react-burger/package-lock.json rename to package-lock.json index 984495e..f9ebf46 100644 --- a/react-burger/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "react-burger", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -17,9 +18,15 @@ "@types/react-dom": "^18.2.15", "@ya.praktikum/react-developer-burger-ui-components": "^1.14.0", "react": "^18.2.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", + "react-redux": "^9.0.4", "react-scripts": "^5.0.1", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "typescript": "^4.9.5", + "uuid": "^9.0.1", "web-vitals": "^2.1.4" } }, @@ -3248,6 +3255,53 @@ } } }, + "node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.0.1.tgz", + "integrity": "sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.0", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.3.tgz", + "integrity": "sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -4213,6 +4267,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.6.tgz", "integrity": "sha512-HYtNooPvUY9WAVRBr4u+4Qa9fYD1ze2IUlAD3HoA6oehn1taGwBx3Oa52U4mTslTS+GAExKpaFu39Y5xUEwfjg==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/ws": { "version": "8.5.9", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", @@ -6694,6 +6753,24 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, + "node_modules/dnd-core/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -8718,6 +8795,19 @@ "he": "bin/he" } }, + "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", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/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/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -14478,6 +14568,43 @@ "node": ">=8" } }, + "node_modules/react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "dependencies": { + "dnd-core": "^16.0.1" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -14500,6 +14627,32 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-redux": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.0.4.tgz", + "integrity": "sha512-9J1xh8sWO0vYq2sCxK2My/QO7MzUMRi3rpiILP/+tDr8krBHixC6JMM17fMK88+Oh3e4Ae6/sHIhNBgkUivwFA==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -14635,6 +14788,19 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", @@ -14780,6 +14946,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/reselect": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.0.1.tgz", + "integrity": "sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -15423,6 +15594,14 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -16648,6 +16827,14 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -16681,9 +16868,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } diff --git a/react-burger/package.json b/package.json similarity index 83% rename from react-burger/package.json rename to package.json index e4e2a4b..240dd5e 100644 --- a/react-burger/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@reduxjs/toolkit": "^2.0.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -12,9 +13,15 @@ "@types/react-dom": "^18.2.15", "@ya.praktikum/react-developer-burger-ui-components": "^1.14.0", "react": "^18.2.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", + "react-redux": "^9.0.4", "react-scripts": "^5.0.1", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", "typescript": "^4.9.5", + "uuid": "^9.0.1", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/react-burger/public/favicon.ico b/public/favicon.ico similarity index 100% rename from react-burger/public/favicon.ico rename to public/favicon.ico diff --git a/react-burger/public/index.html b/public/index.html similarity index 100% rename from react-burger/public/index.html rename to public/index.html diff --git a/react-burger/public/logo192.png b/public/logo192.png similarity index 100% rename from react-burger/public/logo192.png rename to public/logo192.png diff --git a/react-burger/public/logo512.png b/public/logo512.png similarity index 100% rename from react-burger/public/logo512.png rename to public/logo512.png diff --git a/react-burger/public/manifest.json b/public/manifest.json similarity index 100% rename from react-burger/public/manifest.json rename to public/manifest.json diff --git a/react-burger/public/robots.txt b/public/robots.txt similarity index 100% rename from react-burger/public/robots.txt rename to public/robots.txt diff --git a/react-burger/.gitignore b/react-burger/.gitignore deleted file mode 100644 index 4d29575..0000000 --- a/react-burger/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# 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* diff --git a/react-burger/src/components/burger-constructor/burger-constructor.tsx b/react-burger/src/components/burger-constructor/burger-constructor.tsx deleted file mode 100644 index 842bed8..0000000 --- a/react-burger/src/components/burger-constructor/burger-constructor.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useState } from 'react'; -import { CurrencyIcon, Button } from '@ya.praktikum/react-developer-burger-ui-components' -import { ConstructorTopElement, ConstructorBottomElement, ConstructorMidElement } from './constructor-element/constructor-element'; -import { IngredientsType } from '../burger-ingredients/burger-ingredients-types'; -import styles from "./burger-constructor.module.css" -import OrderDetails from '../orders-details/orders-details'; - -export function BurgerConstructor(props: IngredientsType) { - let orderAmount = 2 * Number(props.buns[0]?.price ?? 0); - - const [amount, changeAmount] = useState(0) - - props.sauces.forEach((item) => { - orderAmount += Number(item.price); - }) - - props.mains.forEach((item) => { - orderAmount += Number(item.price); - }) - - const [isModalOpen, setIsModalOpen] = useState(false); - const [modalHeader, setModalHeader] = useState(""); - - - function onModalClose() { - setIsModalOpen(false); - } - - function onModalOpen() { - setModalHeader(""); - setIsModalOpen(true); - } - - return( -
- -
- {props.sauces.map((item) => { - return - })} - {props.mains.map((item) => { - return - })} - -
- - -
-

{ orderAmount }

- -
- {isModalOpen && ( - - )} -
- ) -} \ No newline at end of file diff --git a/react-burger/src/components/burger-ingredients/burger-ingredients.tsx b/react-burger/src/components/burger-ingredients/burger-ingredients.tsx deleted file mode 100644 index 3f8bc32..0000000 --- a/react-burger/src/components/burger-ingredients/burger-ingredients.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import styles from "./burger-ingredients.module.css"; -import IngredientsTable from './ingredient-table/ingredient-table'; -import { Tab } from '@ya.praktikum/react-developer-burger-ui-components' -import { IngredientsType } from './burger-ingredients-types'; - -export default function BurgerIngredients(props: IngredientsType) { - const [current, setCurrent] = React.useState('bun') - - return( -
-

Соберите бургер

- -
- - Булка - - - Соус - - - Основа - -
- -
- - - -
-
- ) - -} \ No newline at end of file diff --git a/react-burger/src/components/burger-ingredients/ingredient-table/card/card.tsx b/react-burger/src/components/burger-ingredients/ingredient-table/card/card.tsx deleted file mode 100644 index ab0e09b..0000000 --- a/react-burger/src/components/burger-ingredients/ingredient-table/card/card.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React, { useState } from 'react'; -import { CurrencyIcon } from '@ya.praktikum/react-developer-burger-ui-components' -import { cardData } from './data'; -import styles from './card.module.css'; -import Modal from '../../../modal/modal'; -import IngredientDetails from '../../../ingredient-details/ingredient-details'; -import { Ingredients } from '../../../../services/get-ingredients/get-ingredients-types'; - -export default function IngredientCard(props: cardData) { - const [isModalOpen, setIsModalOpen] = useState(false); - const [modalData, setModalData] = useState(); - - function onModalClose() { - setIsModalOpen(false); - } - - function onModalOpen(header: string, item: Ingredients) { - setModalData(item); - setIsModalOpen(true); - } - - return( - <> -
onModalOpen(props.name, props.item)}> - { -

{ props.price }

-

{ props.name }

-
- {isModalOpen && ( - - - - )} - - ) -} \ No newline at end of file diff --git a/react-burger/src/components/main/main.tsx b/react-burger/src/components/main/main.tsx deleted file mode 100644 index 176a3ec..0000000 --- a/react-burger/src/components/main/main.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useState, useEffect, ReactNode } from 'react'; -import BurgerIngredients from '../burger-ingredients/burger-ingredients'; -import { BurgerConstructor } from '../burger-constructor/burger-constructor'; -import getIngredients from '../../services/get-ingredients/get-ingredients'; -import { Ingredients } from '../../services/get-ingredients/get-ingredients-types'; -import styles from "./main.module.css"; - - -export default function MainContent() { - const [main, setMainData] = useState([]) - const [bun, setBunData] = useState([]) - const [sauce, setSauceData] = useState([]) - const [loading, setLoaded] = useState(false) - - useEffect(() => { - async function getData() { - const url = "https://norma.nomoreparties.space/api/ingredients"; - const res = await getIngredients(url); - - setMainData(res.data.filter((item: Ingredients) => item.type === "main")) - setBunData(res.data.filter((item: Ingredients) => item.type === "bun")) - setSauceData(res.data.filter((item: Ingredients) => item.type === "sauce")) - setLoaded(Boolean(res.success)); - } - getData().catch((err) => console.log("error while recieveng data: ", err)); - }, []) - - const [modalChild, setModalChild] = React.useState(''); - const [modalHeader, setModalHeader] = React.useState(''); - - - if (loading) { - return ( -
- - -
- ); - } - return ( - <> - ); -} \ No newline at end of file diff --git a/react-burger/src/services/get-ingredients/get-ingredients.ts b/react-burger/src/services/get-ingredients/get-ingredients.ts deleted file mode 100644 index 1a8ea95..0000000 --- a/react-burger/src/services/get-ingredients/get-ingredients.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IngredientsResp } from "./get-ingredients-types"; - -const getIngredients = async(url: string): Promise => { - const resp = await fetch(url); - if (resp.ok) { - return resp.json(); - } - return Promise.reject(`Ошибка ${resp.status}`); -} - -export default getIngredients; \ No newline at end of file diff --git a/react-burger/src/components/App/app.module.css b/src/components/App/app.module.css similarity index 100% rename from react-burger/src/components/App/app.module.css rename to src/components/App/app.module.css diff --git a/react-burger/src/components/App/app.tsx b/src/components/App/app.tsx similarity index 100% rename from react-burger/src/components/App/app.tsx rename to src/components/App/app.tsx diff --git a/react-burger/src/components/app-header/app-header.module.css b/src/components/app-header/app-header.module.css similarity index 100% rename from react-burger/src/components/app-header/app-header.module.css rename to src/components/app-header/app-header.module.css diff --git a/react-burger/src/components/app-header/app-header.tsx b/src/components/app-header/app-header.tsx similarity index 100% rename from react-burger/src/components/app-header/app-header.tsx rename to src/components/app-header/app-header.tsx diff --git a/react-burger/src/components/burger-constructor/burger-constructor-types.ts b/src/components/burger-constructor/burger-constructor-types.ts similarity index 100% rename from react-burger/src/components/burger-constructor/burger-constructor-types.ts rename to src/components/burger-constructor/burger-constructor-types.ts diff --git a/react-burger/src/components/burger-constructor/burger-constructor.module.css b/src/components/burger-constructor/burger-constructor.module.css similarity index 66% rename from react-burger/src/components/burger-constructor/burger-constructor.module.css rename to src/components/burger-constructor/burger-constructor.module.css index b8c7b8d..01c578e 100644 --- a/react-burger/src/components/burger-constructor/burger-constructor.module.css +++ b/src/components/burger-constructor/burger-constructor.module.css @@ -2,7 +2,7 @@ display: flex; flex-direction: column; overflow-y: scroll; - height: calc(100vh - 532px); + height: calc(100vh - 342px); gap: 10px; } @@ -12,4 +12,10 @@ justify-content: center; align-items: center; height: auto; +} + +.mainElements { + display: flex; + flex-direction: column; + gap: 10px; } \ No newline at end of file diff --git a/src/components/burger-constructor/burger-constructor.tsx b/src/components/burger-constructor/burger-constructor.tsx new file mode 100644 index 0000000..9963381 --- /dev/null +++ b/src/components/burger-constructor/burger-constructor.tsx @@ -0,0 +1,100 @@ +import { useCallback, useRef, useState } from 'react'; +import { Button } from '@ya.praktikum/react-developer-burger-ui-components' +import styles from "./burger-constructor.module.css" +import OrderDetails from '../orders-details/orders-details'; +import { useDispatch, useSelector } from 'react-redux'; +import {addIngredient, changeBun, sendIngredients} from '../../services/actions/constructor-action'; +import { + ConstructorBottomElement, + ConstructorMidElement, + ConstructorTopElement +} from './constructor-element/constructor-element'; +import { CurrencyIcon } from '@ya.praktikum/react-developer-burger-ui-components'; +import { useDrop } from "react-dnd"; +import { clearConstructor } from '../../services/actions/constructor-action'; +import { AppDispatch, RootState } from '../../services/reducers/store'; +import { Ingredients } from '../../services/get-ingredients/get-ingredients-types'; + +export function BurgerConstructor() { + const myRef = useRef(); + const handleAdding = (item: any, pos: any) => { + if (item && item.type === 'bun') { + dispatch(changeBun(item)); + } else { + dispatch(addIngredient(item)); + } + } + + const [isModalOpen, setIsModalOpen] = useState(false); + + + const dispatch = useDispatch(); + const {elements, bun} = useSelector((state: RootState) => state.elementConstructor) + + const [{ isOver }, drop] = useDrop(() => ({ + accept: 'card', + drop: (item) => { + handleAdding(item, elements.length); + }, + collect: (monitor) => ({ + isOver: !!monitor.isOver(), + }), + })) + + const [{ isOverBetween }, dropBetween] = useDrop(() => ({ + accept: 'cardBetween', + collect: (monitor) => ({ + isOverBetween: monitor.isOver(), + }), + })) + + function onModalClose() { + setIsModalOpen(false); + } + + const calcOrderSum = useCallback(() => { + return 2 * (bun?.price ?? 0) + elements.reduce((acc, item) => { + return acc + item.price + }, 0) + }, [elements, bun]) + + const makeOrder = useCallback(async () => { + const baseElements = elements.map(elem => elem._id); + const ingredients = bun ? baseElements.concat(bun._id) : baseElements; + await dispatch(sendIngredients({ingredients})); + dispatch(clearConstructor()); + setIsModalOpen(true); + }, [elements, bun]) + + const { v4: uuidv4 } = require('uuid'); + + const order = useSelector((state: RootState) => state.order.orderId); + + return( + // @ts-ignore +
+
+ { bun && ( + + )} +
+ {elements.map((item, index) => { + return + })} +
+ + { bun && ( + + )} +
+ +
+

{ calcOrderSum() }

+ +
+ {isModalOpen && ( + + )} +
+ ) +} \ No newline at end of file diff --git a/react-burger/src/components/burger-constructor/constructor-element/burger-element.module.css b/src/components/burger-constructor/constructor-element/burger-element.module.css similarity index 100% rename from react-burger/src/components/burger-constructor/constructor-element/burger-element.module.css rename to src/components/burger-constructor/constructor-element/burger-element.module.css diff --git a/react-burger/src/components/burger-constructor/constructor-element/constructor-element-types.ts b/src/components/burger-constructor/constructor-element/constructor-element-types.ts similarity index 90% rename from react-burger/src/components/burger-constructor/constructor-element/constructor-element-types.ts rename to src/components/burger-constructor/constructor-element/constructor-element-types.ts index 8b9a307..ee26e12 100644 --- a/react-burger/src/components/burger-constructor/constructor-element/constructor-element-types.ts +++ b/src/components/burger-constructor/constructor-element/constructor-element-types.ts @@ -3,4 +3,5 @@ import { Ingredients } from "../../../services/get-ingredients/get-ingredients-t export interface ElementProps { isLocked: boolean; item: Ingredients; + index: number; } \ No newline at end of file diff --git a/react-burger/src/components/burger-constructor/constructor-element/constructor-element.tsx b/src/components/burger-constructor/constructor-element/constructor-element.jsx similarity index 50% rename from react-burger/src/components/burger-constructor/constructor-element/constructor-element.tsx rename to src/components/burger-constructor/constructor-element/constructor-element.jsx index afbafe7..1df3e13 100644 --- a/react-burger/src/components/burger-constructor/constructor-element/constructor-element.tsx +++ b/src/components/burger-constructor/constructor-element/constructor-element.jsx @@ -1,9 +1,12 @@ import React from 'react'; import { ConstructorElement, DragIcon } from '@ya.praktikum/react-developer-burger-ui-components' -import { ElementProps } from './constructor-element-types'; import styles from "./burger-element.module.css" +import { useDispatch } from 'react-redux'; +import {removeIngredients, swapElements} from '../../../services/actions/constructor-action'; +import { useDrag, useDrop } from 'react-dnd'; +import { useRef } from 'react'; -export function ConstructorTopElement(props: ElementProps) { +export function ConstructorTopElement(props) { return(
@@ -20,7 +23,7 @@ export function ConstructorTopElement(props: ElementProps) { ) } -export function ConstructorBottomElement(props: ElementProps) { +export function ConstructorBottomElement(props) { return(
@@ -37,18 +40,42 @@ export function ConstructorBottomElement(props: ElementProps) { ) } -export function ConstructorMidElement(props: ElementProps) { +export function ConstructorMidElement({ index, isLocked, item }) { + const dispatch = useDispatch(); + const ref = useRef(); + + const [{ isDragging}, dragBetween] = useDrag(() => ({ + type: 'cardBetween', + item: { index }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }) + })) + + const [{ isOverBetween }, dropBetween] = useDrop(() => ({ + accept: 'cardBetween', + collect: (monitor) => ({ + isOverBetween: monitor.isOver(), + }), + drop: (curItem) => { + dispatch(swapElements(curItem.index, index)); + } + })) + return( -
+
{ + dispatch(removeIngredients(index)); + }} />
- {!props.isLocked ? : null } + {!isLocked ? : null }
) } \ No newline at end of file diff --git a/react-burger/src/components/burger-ingredients/burger-ingredients-types.ts b/src/components/burger-ingredients/burger-ingredients-types.ts similarity index 100% rename from react-burger/src/components/burger-ingredients/burger-ingredients-types.ts rename to src/components/burger-ingredients/burger-ingredients-types.ts diff --git a/react-burger/src/components/burger-ingredients/burger-ingredients.module.css b/src/components/burger-ingredients/burger-ingredients.module.css similarity index 100% rename from react-burger/src/components/burger-ingredients/burger-ingredients.module.css rename to src/components/burger-ingredients/burger-ingredients.module.css diff --git a/src/components/burger-ingredients/burger-ingredients.tsx b/src/components/burger-ingredients/burger-ingredients.tsx new file mode 100644 index 0000000..97d9e09 --- /dev/null +++ b/src/components/burger-ingredients/burger-ingredients.tsx @@ -0,0 +1,111 @@ +import React, { useCallback, useMemo } from 'react'; +import styles from "./burger-ingredients.module.css"; +import IngredientsTable from './ingredient-table/ingredient-table'; +import { Tab } from '@ya.praktikum/react-developer-burger-ui-components' +import { IngredientsType } from './burger-ingredients-types'; +import { useSelector } from 'react-redux'; +import store from '../../services/reducers/store'; +import { RootState } from '../../services/reducers/store'; +import { AppDispatch } from '../../services/reducers/store'; +import { useDispatch } from 'react-redux'; +import { useEffect } from 'react'; +import { initialiseIngredients } from '../../services/actions/ingredients-actions'; +import { useRef } from 'react'; + +export default function BurgerIngredients() { + const dispatch = useDispatch(); + const [current, setCurrent] = React.useState('bun') + + const bunTabRef = useRef(null); + const sauceTabRef = useRef(null); + const mainTabRef = useRef(null); + const menuRef = useRef(null); + + useEffect(() => { + dispatch(initialiseIngredients()); + }, []); + + const menuAbsoluteHeightHalf = useMemo(() => { + return menuRef.current?.offsetHeight ?? 0; + }, [menuRef.current?.offsetHeight]); + + useEffect(() => { + const menu = menuRef.current; + if (menu) { + const onScroll = () => { + const bunTab = bunTabRef.current; + const sauceTab = sauceTabRef.current; + const mainTab = mainTabRef.current; + + if (bunTab && sauceTab && mainTab) { + const bunTabTop = bunTab.getBoundingClientRect().top; + const sauceTabTop = sauceTab.getBoundingClientRect().top; + const mainTabTop = mainTab.getBoundingClientRect().top; + + if (bunTabTop >= 0 && bunTabTop <= menuAbsoluteHeightHalf) { + setCurrent('bun'); + } else if (sauceTabTop >= 0 && sauceTabTop <= menuAbsoluteHeightHalf) { + setCurrent('sauce'); + } else if (mainTabTop >= 0 && mainTabTop <= menuAbsoluteHeightHalf) { + setCurrent('main'); + } + } + }; + + menu.addEventListener('scroll', onScroll); + return () => { + menu.removeEventListener('scroll', onScroll); + }; + } + }, [menuRef.current?.offsetHeight]); + + const scrollToTab = useCallback((current: string) => { + if (current === 'bun') { + bunTabRef.current?.scrollIntoView({ behavior: 'smooth' }); + } else if (current === 'sauce') { + sauceTabRef.current?.scrollIntoView({ behavior: 'smooth' }); + } else if (current === 'main') { + mainTabRef.current?.scrollIntoView({ behavior: 'smooth' }); + } + }, [current]); + + const handleTabClick = useCallback((current: string) => { + setCurrent(current); + scrollToTab(current); + }, [current]); + + // const { buns, mains, sauces } = useSelector((store: RootState) => ({ + // buns: store.ingredients.bun, + // mains: store.ingredients.main, + // sauces: store.ingredients.sauce + // })) + + const buns = useSelector((store: RootState) => store.ingredients.entities.bun); + const mains = useSelector((store: RootState) => store.ingredients.entities.main); + const sauces = useSelector((store: RootState) => store.ingredients.entities.sauce); + + return( +
+

Соберите бургер

+ +
+ + Булка + + + Соус + + + Основа + +
+ +
+ + + +
+
+ ) + +} \ No newline at end of file diff --git a/react-burger/src/components/burger-ingredients/ingredient-table/card/card.module.css b/src/components/burger-ingredients/ingredient-table/card/card.module.css similarity index 55% rename from react-burger/src/components/burger-ingredients/ingredient-table/card/card.module.css rename to src/components/burger-ingredients/ingredient-table/card/card.module.css index c522e17..207f286 100644 --- a/react-burger/src/components/burger-ingredients/ingredient-table/card/card.module.css +++ b/src/components/burger-ingredients/ingredient-table/card/card.module.css @@ -23,4 +23,18 @@ .img { width: 80%; +} + +.amount { + border-radius: 50%; + background-color: #4C4CFF; + width: 35px; + height: 35px; + margin-left: auto; + margin-right: 20px; + margin-top: auto; + margin-bottom: -35px; + display: flex; + justify-content: center; + align-items: center; } \ No newline at end of file diff --git a/src/components/burger-ingredients/ingredient-table/card/card.tsx b/src/components/burger-ingredients/ingredient-table/card/card.tsx new file mode 100644 index 0000000..2907460 --- /dev/null +++ b/src/components/burger-ingredients/ingredient-table/card/card.tsx @@ -0,0 +1,62 @@ +import React, { useState } from 'react'; +import { CurrencyIcon } from '@ya.praktikum/react-developer-burger-ui-components' +import { cardData } from './data'; +import styles from './card.module.css'; +import Modal from '../../../modal/modal'; +import IngredientDetails from '../../../ingredient-details/ingredient-details'; +import { Ingredients } from '../../../../services/get-ingredients/get-ingredients-types'; +import { useSelector } from 'react-redux'; +import { RootState } from '../../../../services/reducers/store'; +import { useDispatch } from 'react-redux'; +import { AppDispatch } from '../../../../services/reducers/store'; +import { closeModal, openModal } from '../../../../services/actions/modal-action'; +import {useDrag} from "react-dnd"; + +function countElements (elems: Ingredients[], bun: Ingredients | null, _id: string) { + let ans = 0; + for (let i = 0; i < elems.length; i++) { + if (elems[i]._id === _id) { + ans++; + } + } + if (bun && bun._id === _id) { + ans++; + } + return ans; +} + +export default function IngredientCard(props: Ingredients) { + const [isModalOpen, setIsModalOpen] = useState(false); + const [modalData, setModalData] = useState(); + + const dispatch = useDispatch(); + const modalElement = useSelector((state: RootState) => state.modalWindow) + + const [{isDragging}, drag] = useDrag(() => ({ + type: 'card', + item: props, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + }) + })) + + const { elements, bun } = useSelector((state: RootState) => state.elementConstructor) + + return( + <> +
dispatch(openModal(props))}> + {countElements(elements, bun, props._id) !== 0 && ( +
{countElements(elements, bun, props._id)}
+ )} + { +

{ props.price }

+

{ props.name }

+
+ {modalElement.isOpened && ( + dispatch(closeModal()) } header={"Детали ингредиента"}> + dispatch(closeModal()) }/> + + )} + + ) +} \ No newline at end of file diff --git a/react-burger/src/components/burger-ingredients/ingredient-table/card/data.ts b/src/components/burger-ingredients/ingredient-table/card/data.ts similarity index 100% rename from react-burger/src/components/burger-ingredients/ingredient-table/card/data.ts rename to src/components/burger-ingredients/ingredient-table/card/data.ts diff --git a/react-burger/src/components/burger-ingredients/ingredient-table/ingredient-item-name.ts b/src/components/burger-ingredients/ingredient-table/ingredient-item-name.ts similarity index 79% rename from react-burger/src/components/burger-ingredients/ingredient-table/ingredient-item-name.ts rename to src/components/burger-ingredients/ingredient-table/ingredient-item-name.ts index 545e19f..f5e2d00 100644 --- a/react-burger/src/components/burger-ingredients/ingredient-table/ingredient-item-name.ts +++ b/src/components/burger-ingredients/ingredient-table/ingredient-item-name.ts @@ -3,4 +3,5 @@ import { Ingredients } from "../../../services/get-ingredients/get-ingredients-t export interface IngredientsItemType { name: string; items: Array; + innerRef: React.RefObject; } \ No newline at end of file diff --git a/react-burger/src/components/burger-ingredients/ingredient-table/ingredient-table.module.css b/src/components/burger-ingredients/ingredient-table/ingredient-table.module.css similarity index 100% rename from react-burger/src/components/burger-ingredients/ingredient-table/ingredient-table.module.css rename to src/components/burger-ingredients/ingredient-table/ingredient-table.module.css diff --git a/react-burger/src/components/burger-ingredients/ingredient-table/ingredient-table.tsx b/src/components/burger-ingredients/ingredient-table/ingredient-table.tsx similarity index 77% rename from react-burger/src/components/burger-ingredients/ingredient-table/ingredient-table.tsx rename to src/components/burger-ingredients/ingredient-table/ingredient-table.tsx index 27e7bdf..9f65d00 100644 --- a/react-burger/src/components/burger-ingredients/ingredient-table/ingredient-table.tsx +++ b/src/components/burger-ingredients/ingredient-table/ingredient-table.tsx @@ -8,11 +8,11 @@ import Modal from '../../modal/modal'; export default function IngredientsTable(props: IngredientsItemType) { return( -
+

{ props.name }

- { props.items.map((item) => ( - + { props.items.map((item, pos) => ( + ))}
diff --git a/react-burger/src/components/ingredient-details/ingredient-deatail-types.ts b/src/components/ingredient-details/ingredient-deatail-types.ts similarity index 87% rename from react-burger/src/components/ingredient-details/ingredient-deatail-types.ts rename to src/components/ingredient-details/ingredient-deatail-types.ts index adbe303..55fb3c8 100644 --- a/react-burger/src/components/ingredient-details/ingredient-deatail-types.ts +++ b/src/components/ingredient-details/ingredient-deatail-types.ts @@ -1,6 +1,5 @@ import { Ingredients } from "../../services/get-ingredients/get-ingredients-types"; export interface IngredientDetailsType { - item?: Ingredients; onModalClose: () => void; } \ No newline at end of file diff --git a/react-burger/src/components/ingredient-details/ingredient-details.module.css b/src/components/ingredient-details/ingredient-details.module.css similarity index 100% rename from react-burger/src/components/ingredient-details/ingredient-details.module.css rename to src/components/ingredient-details/ingredient-details.module.css diff --git a/react-burger/src/components/ingredient-details/ingredient-details.tsx b/src/components/ingredient-details/ingredient-details.tsx similarity index 66% rename from react-burger/src/components/ingredient-details/ingredient-details.tsx rename to src/components/ingredient-details/ingredient-details.tsx index 847e179..7a36fec 100644 --- a/react-burger/src/components/ingredient-details/ingredient-details.tsx +++ b/src/components/ingredient-details/ingredient-details.tsx @@ -2,8 +2,15 @@ import Modal from '../modal/modal'; import { IngredientDetailsType } from './ingredient-deatail-types'; import styles from "./ingredient-details.module.css" import IngredientSubstance from './ingredient-substance/ingredient-substance'; +import { useDispatch } from 'react-redux'; +import { AppDispatch } from '../../services/reducers/store'; +import { useSelector } from 'react-redux'; +import { RootState } from '../../services/reducers/store'; + +export default function IngredientDetails(onModalClose: IngredientDetailsType) { + const dispatch = useDispatch(); + const item = useSelector((state: RootState) => state.modalWindow.modalData) -export default function IngredientDetails({item, onModalClose}: IngredientDetailsType) { return( <> {item?.name} diff --git a/react-burger/src/components/ingredient-details/ingredient-substance/ingredient-substance.module.css b/src/components/ingredient-details/ingredient-substance/ingredient-substance.module.css similarity index 100% rename from react-burger/src/components/ingredient-details/ingredient-substance/ingredient-substance.module.css rename to src/components/ingredient-details/ingredient-substance/ingredient-substance.module.css diff --git a/react-burger/src/components/ingredient-details/ingredient-substance/ingredient-substance.tsx b/src/components/ingredient-details/ingredient-substance/ingredient-substance.tsx similarity index 100% rename from react-burger/src/components/ingredient-details/ingredient-substance/ingredient-substance.tsx rename to src/components/ingredient-details/ingredient-substance/ingredient-substance.tsx diff --git a/react-burger/src/components/ingredient-details/ingredient-substance/ingredient-substancse-types.ts b/src/components/ingredient-details/ingredient-substance/ingredient-substancse-types.ts similarity index 100% rename from react-burger/src/components/ingredient-details/ingredient-substance/ingredient-substancse-types.ts rename to src/components/ingredient-details/ingredient-substance/ingredient-substancse-types.ts diff --git a/react-burger/src/components/main/main.module.css b/src/components/main/main.module.css similarity index 100% rename from react-burger/src/components/main/main.module.css rename to src/components/main/main.module.css diff --git a/src/components/main/main.tsx b/src/components/main/main.tsx new file mode 100644 index 0000000..a8c8afb --- /dev/null +++ b/src/components/main/main.tsx @@ -0,0 +1,17 @@ +import React, { useState, useEffect, ReactNode } from 'react'; +import BurgerIngredients from '../burger-ingredients/burger-ingredients'; +import { BurgerConstructor } from '../burger-constructor/burger-constructor'; +import styles from "./main.module.css"; +import {DndProvider} from "react-dnd"; +import {HTML5Backend} from "react-dnd-html5-backend"; + +export default function MainContent() { + return ( + +
+ + +
+
+ ); +} \ No newline at end of file diff --git a/react-burger/src/components/modal-overlay/modal-overlay.module.css b/src/components/modal-overlay/modal-overlay.module.css similarity index 100% rename from react-burger/src/components/modal-overlay/modal-overlay.module.css rename to src/components/modal-overlay/modal-overlay.module.css diff --git a/react-burger/src/components/modal-overlay/modal-overlay.tsx b/src/components/modal-overlay/modal-overlay.tsx similarity index 100% rename from react-burger/src/components/modal-overlay/modal-overlay.tsx rename to src/components/modal-overlay/modal-overlay.tsx diff --git a/react-burger/src/components/modal/modal-type.ts b/src/components/modal/modal-type.ts similarity index 100% rename from react-burger/src/components/modal/modal-type.ts rename to src/components/modal/modal-type.ts diff --git a/react-burger/src/components/modal/modal.module.css b/src/components/modal/modal.module.css similarity index 100% rename from react-burger/src/components/modal/modal.module.css rename to src/components/modal/modal.module.css diff --git a/react-burger/src/components/modal/modal.tsx b/src/components/modal/modal.tsx similarity index 100% rename from react-burger/src/components/modal/modal.tsx rename to src/components/modal/modal.tsx diff --git a/react-burger/src/components/orders-details/order-details-types.ts b/src/components/orders-details/order-details-types.ts similarity index 88% rename from react-burger/src/components/orders-details/order-details-types.ts rename to src/components/orders-details/order-details-types.ts index 28f77e8..0d82bc3 100644 --- a/react-burger/src/components/orders-details/order-details-types.ts +++ b/src/components/orders-details/order-details-types.ts @@ -2,4 +2,5 @@ import { Ingredients } from "../../services/get-ingredients/get-ingredients-type export interface OrderDetailsType { onModalClose: () => void; + orderId: string; } \ No newline at end of file diff --git a/react-burger/src/components/orders-details/order-details.module.css b/src/components/orders-details/order-details.module.css similarity index 100% rename from react-burger/src/components/orders-details/order-details.module.css rename to src/components/orders-details/order-details.module.css diff --git a/react-burger/src/components/orders-details/orders-details.tsx b/src/components/orders-details/orders-details.tsx similarity index 69% rename from react-burger/src/components/orders-details/orders-details.tsx rename to src/components/orders-details/orders-details.tsx index c4a6788..73e1681 100644 --- a/react-burger/src/components/orders-details/orders-details.tsx +++ b/src/components/orders-details/orders-details.tsx @@ -3,11 +3,11 @@ import { OrderDetailsType } from './order-details-types'; import image from "../../images/done.png" import styles from "./order-details.module.css" -export default function OrderDetails({onModalClose}: OrderDetailsType) { +export default function OrderDetails({onModalClose, orderId}: OrderDetailsType) { return( -

034536

-

идендификатор заказа

+

{orderId}

+

Идентификатор заказа

done

Ваш заказ начали готовить

Дождитесь готовности на орбитальной станции

diff --git a/react-burger/src/images/done.png b/src/images/done.png similarity index 100% rename from react-burger/src/images/done.png rename to src/images/done.png diff --git a/react-burger/src/index.css b/src/index.css similarity index 100% rename from react-burger/src/index.css rename to src/index.css diff --git a/react-burger/src/index.tsx b/src/index.tsx similarity index 68% rename from react-burger/src/index.tsx rename to src/index.tsx index 3c7a027..5b8256b 100644 --- a/react-burger/src/index.tsx +++ b/src/index.tsx @@ -2,6 +2,8 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import reportWebVitals from './reportWebVitals'; import App from './components/App/app'; +import { Provider } from 'react-redux'; +import store from './services/reducers/store'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement @@ -9,7 +11,9 @@ const root = ReactDOM.createRoot( root.render( - + + + ); diff --git a/react-burger/src/react-app-env.d.ts b/src/react-app-env.d.ts similarity index 100% rename from react-burger/src/react-app-env.d.ts rename to src/react-app-env.d.ts diff --git a/react-burger/src/reportWebVitals.ts b/src/reportWebVitals.ts similarity index 100% rename from react-burger/src/reportWebVitals.ts rename to src/reportWebVitals.ts diff --git a/src/services/actions/constructor-action.ts b/src/services/actions/constructor-action.ts new file mode 100644 index 0000000..12ce342 --- /dev/null +++ b/src/services/actions/constructor-action.ts @@ -0,0 +1,40 @@ +import { Ingredients, PostOrderRequest, PostOrderResponse } from "../reducers/types"; +import { constructorActions } from "../reducers/constructor-reducer"; +import { AppDispatch } from "../reducers/store"; +import { postIngredients } from "../get-ingredients/get-ingredients"; +import { orderActions } from "../reducers/order-reducer"; +import { BASE_URL } from "../reducers/types"; + +export const addIngredient = (ingredient: Ingredients) => (dispatch: AppDispatch) => { + dispatch(constructorActions.addIngredients(ingredient)); +} + +export const changeBun = (ingredient: Ingredients) => (dispatch: AppDispatch) => { + dispatch(constructorActions.changeBun(ingredient)); +} + +export const removeIngredients = (index: number) => (dispatch: AppDispatch) => { + dispatch(constructorActions.removeIngredients(index)); +} + +export const swapElements = (index1: number, index2: number) => (dispatch: AppDispatch) => { + dispatch(constructorActions.swapElements({firstId: index1, secondId: index2})); +} + +export const sendIngredients = (request: PostOrderRequest) => async (dispatch: AppDispatch) => { + dispatch(orderActions.setLoading()); + try { + const res = await postIngredients(request); + if (res.success) { + dispatch(orderActions.setOrder(res.order.number.toString())); + } else { + dispatch(orderActions.setError()); + } + } catch (err) { + dispatch(orderActions.setError()); + } +} + +export const clearConstructor = () => (dispatch: AppDispatch) => { + dispatch(constructorActions.clearConstructor()); +} diff --git a/src/services/actions/ingredients-actions.ts b/src/services/actions/ingredients-actions.ts new file mode 100644 index 0000000..5455518 --- /dev/null +++ b/src/services/actions/ingredients-actions.ts @@ -0,0 +1,19 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { getIngredients } from "../get-ingredients/get-ingredients"; +import { ingredientsActions } from "../reducers/ingredients-reducer"; +import { AppDispatch } from "../reducers/store"; + +export const initialiseIngredients = () => async (dispatch: AppDispatch) => { + dispatch(ingredientsActions.setLoading()); + + try { + const ingredients = await getIngredients(); + if (ingredients.success) { + dispatch(ingredientsActions.setIngredients(ingredients.data)); + } else { + dispatch(ingredientsActions.setError()); + } + } catch (error) { + dispatch(ingredientsActions.setError()); + } +} diff --git a/src/services/actions/modal-action.ts b/src/services/actions/modal-action.ts new file mode 100644 index 0000000..94a1b83 --- /dev/null +++ b/src/services/actions/modal-action.ts @@ -0,0 +1,11 @@ +import { Ingredients } from "../reducers/types"; +import { modalActions } from "../reducers/modal-reducer"; +import { AppDispatch } from "../reducers/store"; + +export const openModal = (ingredient: Ingredients) => (dispatch: AppDispatch) => { + dispatch(modalActions.setModal(ingredient)); +} + +export const closeModal = () => (dispatch: AppDispatch) => { + dispatch(modalActions.closeModal()); +} \ No newline at end of file diff --git a/react-burger/src/services/get-ingredients/get-ingredients-types.ts b/src/services/get-ingredients/get-ingredients-types.ts similarity index 94% rename from react-burger/src/services/get-ingredients/get-ingredients-types.ts rename to src/services/get-ingredients/get-ingredients-types.ts index b3f23ad..e5a7adb 100644 --- a/react-burger/src/services/get-ingredients/get-ingredients-types.ts +++ b/src/services/get-ingredients/get-ingredients-types.ts @@ -7,7 +7,7 @@ export interface Ingredients { image_large: string; image_mobile: string; name: string; - price: string; + price: number; proteins: number; type: string; } diff --git a/src/services/get-ingredients/get-ingredients.ts b/src/services/get-ingredients/get-ingredients.ts new file mode 100644 index 0000000..c0b9090 --- /dev/null +++ b/src/services/get-ingredients/get-ingredients.ts @@ -0,0 +1,25 @@ +import { BASE_URL, PostOrderRequest } from "../reducers/types"; +import { IngredientsResp } from "./get-ingredients-types"; +import { PostOrderResponse } from "../reducers/types"; + +export const getIngredients = async(): Promise => { + const resp = await fetch(`${BASE_URL}/ingredients`); + if (resp.ok) { + return resp.json(); + } + return Promise.reject(`Ошибка ${resp.status}`); +} + +export const postIngredients = async (request: PostOrderRequest): Promise => { + const resp = await fetch(`${BASE_URL}/orders`, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify(request), + }) + + if (resp.ok) { + return resp.json(); + } + + return Promise.reject(`Ошибка ${resp.status}`); +} \ No newline at end of file diff --git a/src/services/reducers/constructor-reducer.ts b/src/services/reducers/constructor-reducer.ts new file mode 100644 index 0000000..8fba520 --- /dev/null +++ b/src/services/reducers/constructor-reducer.ts @@ -0,0 +1,55 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { ActionState, Burger } from './types'; + +const initial = { elements: [], bun: null, state: ActionState.INITIAL } as Burger; + +const { actions, reducer } = createSlice({ + name: 'ELEMENT_CONSTRUCTOR', + initialState: initial, + reducers: { + addIngredients(state, action) { + return { + ...state, + elements: state.elements.concat(action.payload) + } + }, + removeIngredients(state, action) { + const newElements = state.elements.slice(0, action.payload).concat(state.elements.slice(action.payload + 1)); + return { + ...state, + elements: newElements, + } + }, + changeBun(state, action) { + return { + ...state, + bun: action.payload, + } + }, + swapElements(state, action) { + let index1 = action.payload.firstId; + let index2 = action.payload.secondId; + const newElements = state.elements.slice(); + if (index1 > index2) { + let tmp = index1; + index1 = index2; + index2 = tmp; + } + let tmp = newElements[index2]; + for (let i = index2; i > index1; i--) { + newElements[i] = newElements[i - 1]; + } + newElements[index1] = tmp; + return { + ...state, + elements: newElements, + } + }, + clearConstructor(state) { + return initial; + }, + }, +}) + +export const constructorActions = actions; +export default reducer \ No newline at end of file diff --git a/src/services/reducers/ingredients-reducer.ts b/src/services/reducers/ingredients-reducer.ts new file mode 100644 index 0000000..3f8d6da --- /dev/null +++ b/src/services/reducers/ingredients-reducer.ts @@ -0,0 +1,48 @@ +import { createSlice } from '@reduxjs/toolkit' +import BurgerIngredients from '../../components/burger-ingredients/burger-ingredients'; +import { ActionState, BurgerComponents, BurgerData } from './types'; +import { Ingredients } from './types'; + +const initial: BurgerData = { + entities: { + bun: [], + main: [], + sauce: [] + } as BurgerComponents, + state: ActionState.INITIAL, +} + +const { actions, reducer } = createSlice({ + name: 'INGREDIENTS', + initialState: initial, + reducers: { + setLoading: (state) => { + return { + ...state, + state: ActionState.LOADING, + } + }, + setError: (state) => { + return { + ...state, + state: ActionState.ERROR, + } + }, + setIngredients: (state, action: { payload: Ingredients[] }) => { + const ingredients = action.payload.reduce((acc: BurgerComponents, ingredient: Ingredients) => { + const ingredientType = ingredient.type as keyof BurgerComponents; + acc[ingredientType].push(ingredient); + return acc; + }, { bun: [], main: [], sauce: [] }); + + return { + ...state, + entities: ingredients, + state: ActionState.SUCCESS, + } + }, + }, +}) + +export const ingredientsActions = actions; +export default reducer \ No newline at end of file diff --git a/src/services/reducers/modal-reducer.ts b/src/services/reducers/modal-reducer.ts new file mode 100644 index 0000000..55e5427 --- /dev/null +++ b/src/services/reducers/modal-reducer.ts @@ -0,0 +1,28 @@ +import { createSlice } from '@reduxjs/toolkit' +import { Ingredients } from './types'; + +const sampleIngredient: Ingredients = {"_id": "", "name": "", "type": "", "proteins": 0, "fat": 0, "carbohydrates": 0, "calories": 0, "price": 0, "image": "", "image_mobile": "", "image_large": "",}; + +const initial = { isOpened: false, modalData : sampleIngredient } + +const { actions, reducer } = createSlice({ + name: 'MODAL_WINDOW', + initialState: initial, + reducers: { + setModal(state, action) { + return { + modalData: action.payload, + isOpened: true + } + }, + closeModal(state) { + return { + ...state, + isOpened: false + } + }, + }, +}) + +export const modalActions = actions; +export default reducer \ No newline at end of file diff --git a/src/services/reducers/order-reducer.ts b/src/services/reducers/order-reducer.ts new file mode 100644 index 0000000..0d98d23 --- /dev/null +++ b/src/services/reducers/order-reducer.ts @@ -0,0 +1,32 @@ +import { createSlice } from '@reduxjs/toolkit' +import { ActionState } from './types' + +const initial = { orderId : '', state: ActionState.INITIAL } + +const { actions, reducer } = createSlice({ + name: 'ORDER', + initialState: initial, + reducers: { + setLoading: (state) => { + return { + ...state, + state: ActionState.LOADING, + } + }, + setError: (state) => { + return { + ...state, + state: ActionState.ERROR, + } + }, + setOrder: (state, action: { payload: string }) => { + return { + orderId: action.payload, + state: ActionState.SUCCESS, + } + } + }, +}) + +export const orderActions = actions; +export default reducer \ No newline at end of file diff --git a/src/services/reducers/store.ts b/src/services/reducers/store.ts new file mode 100644 index 0000000..0b5f8d7 --- /dev/null +++ b/src/services/reducers/store.ts @@ -0,0 +1,23 @@ +import { configureStore } from '@reduxjs/toolkit' + +import ingredientsReducer from './ingredients-reducer' +import constructorReducer from './constructor-reducer' +import modalReducer from './modal-reducer' +import orderReducer from './order-reducer' + +const store = configureStore({ + reducer: { + ingredients: ingredientsReducer, + elementConstructor: constructorReducer, + modalWindow: modalReducer, + order: orderReducer, + }, + middleware: (getDefaultMiddleware) => getDefaultMiddleware({ + serializableCheck: false, + }), + devTools: process.env.NODE_ENV !== 'production', +}) + +export default store +export type RootState = ReturnType +export type AppDispatch = typeof store.dispatch \ No newline at end of file diff --git a/src/services/reducers/types.ts b/src/services/reducers/types.ts new file mode 100644 index 0000000..75949aa --- /dev/null +++ b/src/services/reducers/types.ts @@ -0,0 +1,63 @@ +import { BooleanLiteral, StringLiteral } from "typescript"; + +export interface Ingredients { + _id: string; + calories: number; + carbohydrates: number; + fat: number; + image: string; + image_large: string; + image_mobile: string; + name: string; + price: number; + proteins: number; + type: string; +} + +export const BASE_URL = 'https://norma.nomoreparties.space/api'; + +export enum ActionState { + INITIAL = '_INITIAL', + LOADING = '_LOADING', + ERROR = '_ERROR', + SUCCESS = '_SUCCESS' +} + +export interface IngredientsResp { + success: boolean; + data: Ingredients[]; +} + +export interface PostOrderRequest { + ingredients: string[]; +} + +export interface PostOrderResponse { + name: string; + success: boolean; + order: { + number: number; + }; +} + +export interface BurgerComponents { + bun: Ingredients[]; + main: Ingredients[]; + sauce: Ingredients[]; +} + +export interface BurgerData { + entities: BurgerComponents; + state: ActionState; +} + +export interface Burger { + elements: Ingredients[]; + bun: Ingredients | null; + state: ActionState; +} + +export interface OrderData { + orderId: string, + state: ActionState, +} \ No newline at end of file diff --git a/react-burger/src/setupTests.ts b/src/setupTests.ts similarity index 100% rename from react-burger/src/setupTests.ts rename to src/setupTests.ts diff --git a/react-burger/tsconfig.json b/tsconfig.json similarity index 100% rename from react-burger/tsconfig.json rename to tsconfig.json