Commit 63ecdad7 authored by Pavel Mishakov's avatar Pavel Mishakov

finished lesson 68

parent d0dadb30
...@@ -8,12 +8,14 @@ ...@@ -8,12 +8,14 @@
"name": "burger-builder", "name": "burger-builder",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.1",
"@testing-library/jest-dom": "^5.16.4", "@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0", "@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.2.1", "axios": "^1.2.1",
"react": "^18.1.0", "react": "^18.1.0",
"react-dom": "^18.1.0", "react-dom": "^18.1.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.4.4", "react-router-dom": "^6.4.4",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
...@@ -2907,6 +2909,29 @@ ...@@ -2907,6 +2909,29 @@
} }
} }
}, },
"node_modules/@reduxjs/toolkit": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.1.tgz",
"integrity": "sha512-HikrdY+IDgRfRYlCTGUQaiCxxDDgM1mQrRbZ6S1HFZX5ZYuJ4o8EstNmhTwHdPl2rTmLxzwSu0b3AyeyTlR+RA==",
"dependencies": {
"immer": "^9.0.16",
"redux": "^4.2.0",
"redux-thunk": "^2.4.2",
"reselect": "^4.1.7"
},
"peerDependencies": {
"react": "^16.9.0 || ^17.0.0 || ^18",
"react-redux": "^7.2.1 || ^8.0.2"
},
"peerDependenciesMeta": {
"react": {
"optional": true
},
"react-redux": {
"optional": true
}
}
},
"node_modules/@remix-run/router": { "node_modules/@remix-run/router": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.4.tgz",
...@@ -3589,6 +3614,15 @@ ...@@ -3589,6 +3614,15 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/html-minifier-terser": { "node_modules/@types/html-minifier-terser": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
...@@ -3761,6 +3795,11 @@ ...@@ -3761,6 +3795,11 @@
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
}, },
"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": { "node_modules/@types/ws": {
"version": "8.5.3", "version": "8.5.3",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
...@@ -8108,6 +8147,19 @@ ...@@ -8108,6 +8147,19 @@
"he": "bin/he" "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": { "node_modules/hoopy": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
...@@ -8371,9 +8423,9 @@ ...@@ -8371,9 +8423,9 @@
} }
}, },
"node_modules/immer": { "node_modules/immer": {
"version": "9.0.14", "version": "9.0.16",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz",
"integrity": "sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==", "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/immer" "url": "https://opencollective.com/immer"
...@@ -13507,6 +13559,49 @@ ...@@ -13507,6 +13559,49 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}, },
"node_modules/react-redux": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
"integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
"dependencies": {
"@babel/runtime": "^7.12.1",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/use-sync-external-store": "^0.0.3",
"hoist-non-react-statics": "^3.3.2",
"react-is": "^18.0.0",
"use-sync-external-store": "^1.0.0"
},
"peerDependencies": {
"@types/react": "^16.8 || ^17.0 || ^18.0",
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0",
"react-native": ">=0.59",
"redux": "^4"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
},
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
},
"redux": {
"optional": true
}
}
},
"node_modules/react-redux/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
...@@ -13675,6 +13770,22 @@ ...@@ -13675,6 +13770,22 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/redux": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz",
"integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==",
"dependencies": {
"@babel/runtime": "^7.9.2"
}
},
"node_modules/redux-thunk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
"integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
"peerDependencies": {
"redux": "^4"
}
},
"node_modules/regenerate": { "node_modules/regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
...@@ -13817,6 +13928,11 @@ ...@@ -13817,6 +13928,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
}, },
"node_modules/reselect": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz",
"integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A=="
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.0", "version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
...@@ -15367,6 +15483,14 @@ ...@@ -15367,6 +15483,14 @@
"punycode": "^2.1.0" "punycode": "^2.1.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": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
...@@ -18300,6 +18424,17 @@ ...@@ -18300,6 +18424,17 @@
"source-map": "^0.7.3" "source-map": "^0.7.3"
} }
}, },
"@reduxjs/toolkit": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.1.tgz",
"integrity": "sha512-HikrdY+IDgRfRYlCTGUQaiCxxDDgM1mQrRbZ6S1HFZX5ZYuJ4o8EstNmhTwHdPl2rTmLxzwSu0b3AyeyTlR+RA==",
"requires": {
"immer": "^9.0.16",
"redux": "^4.2.0",
"redux-thunk": "^2.4.2",
"reselect": "^4.1.7"
}
},
"@remix-run/router": { "@remix-run/router": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.4.tgz", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.4.tgz",
...@@ -18786,6 +18921,15 @@ ...@@ -18786,6 +18921,15 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"requires": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/html-minifier-terser": { "@types/html-minifier-terser": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
...@@ -18958,6 +19102,11 @@ ...@@ -18958,6 +19102,11 @@
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
}, },
"@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=="
},
"@types/ws": { "@types/ws": {
"version": "8.5.3", "version": "8.5.3",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
...@@ -22110,6 +22259,21 @@ ...@@ -22110,6 +22259,21 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
}, },
"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==",
"requires": {
"react-is": "^16.7.0"
},
"dependencies": {
"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=="
}
}
},
"hoopy": { "hoopy": {
"version": "0.1.4", "version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
...@@ -22306,9 +22470,9 @@ ...@@ -22306,9 +22470,9 @@
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
}, },
"immer": { "immer": {
"version": "9.0.14", "version": "9.0.16",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz",
"integrity": "sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==" "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ=="
}, },
"import-fresh": { "import-fresh": {
"version": "3.3.0", "version": "3.3.0",
...@@ -25875,6 +26039,26 @@ ...@@ -25875,6 +26039,26 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}, },
"react-redux": {
"version": "8.0.5",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
"integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
"requires": {
"@babel/runtime": "^7.12.1",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/use-sync-external-store": "^0.0.3",
"hoist-non-react-statics": "^3.3.2",
"react-is": "^18.0.0",
"use-sync-external-store": "^1.0.0"
},
"dependencies": {
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
"react-refresh": { "react-refresh": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
...@@ -25997,6 +26181,20 @@ ...@@ -25997,6 +26181,20 @@
"strip-indent": "^3.0.0" "strip-indent": "^3.0.0"
} }
}, },
"redux": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz",
"integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==",
"requires": {
"@babel/runtime": "^7.9.2"
}
},
"redux-thunk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
"integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
"requires": {}
},
"regenerate": { "regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
...@@ -26108,6 +26306,11 @@ ...@@ -26108,6 +26306,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
}, },
"reselect": {
"version": "4.1.7",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz",
"integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A=="
},
"resolve": { "resolve": {
"version": "1.22.0", "version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
...@@ -27253,6 +27456,12 @@ ...@@ -27253,6 +27456,12 @@
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
}, },
"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==",
"requires": {}
},
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.1",
"@testing-library/jest-dom": "^5.16.4", "@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0", "@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.2.1", "axios": "^1.2.1",
"react": "^18.1.0", "react": "^18.1.0",
"react-dom": "^18.1.0", "react-dom": "^18.1.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.4.4", "react-router-dom": "^6.4.4",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
......
...@@ -4,8 +4,15 @@ import Checkout from "./containers/Checkout/Checkout"; ...@@ -4,8 +4,15 @@ import Checkout from "./containers/Checkout/Checkout";
import ContactData from "./containers/Checkout/ContactData/ContactData"; import ContactData from "./containers/Checkout/ContactData/ContactData";
import Layout from "./components/Layout/Layout"; import Layout from "./components/Layout/Layout";
import Orders from "./containers/Orders/Orders"; import Orders from "./containers/Orders/Orders";
import { getIngredients } from "./store/ingredients.slice";
import { useDispatch } from "react-redux";
import { useEffect } from "react";
function App() { function App() {
const dispatch = useDispatch()
useEffect(() => {
dispatch(getIngredients())
}, [])
return ( return (
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
......
...@@ -16,6 +16,14 @@ class ApiBurger { ...@@ -16,6 +16,14 @@ class ApiBurger {
console.log(err) console.log(err)
} }
} }
getIngredients = async() => {
try {
const response = await burgerInstance.get('/ingredients.json')
return response?.data
} catch (err) {
console.log(err)
}
}
} }
export const apiBurger = new ApiBurger() export const apiBurger = new ApiBurger()
\ No newline at end of file
import React from 'react'; import React from 'react';
import './BuildControls.css'; import './BuildControls.css';
import BuildControl from './BuildControl/BuildControl' import BuildControl from './BuildControl/BuildControl'
import { useSelector } from 'react-redux';
const BuildControls = props => { const BuildControls = props => {
const ingredients = useSelector(state => state.ingredients.basket)
return ( return (
<div className='BuildControls'> <div className='BuildControls'>
<p>Current Price: <strong>{props.price} KZT</strong></p> <p>Current Price: <strong>{props.price} KZT</strong></p>
{Object.keys(props.ingredients).map(ingType => { {Object.keys(ingredients).map(ingType => {
return <BuildControl return <BuildControl
key={ingType} key={ingType}
type={ingType} type={ingType}
......
import React from 'react'; import React from 'react';
import { useSelector } from 'react-redux';
import './Burger.css'; import './Burger.css';
import Ingredient from './Ingredient/Ingredient' import Ingredient from './Ingredient/Ingredient'
// const Burger = (props) => { // const Burger = (props) => {
//const ingredientKeys = Object.keys(props.ingredients) // ['salad', 'bacon'...] //const ingredientKeys = Object.keys(props.ingredients) // ['salad', 'bacon'...]
// props = {ingredients} {ingredients} // props = {ingredients} {ingredients}
const Burger = ({ingredients}) => { const Burger = () => {
const ingredients = useSelector(state => state.ingredients.basket)
const ingredientKeys = Object.keys(ingredients) // ['salad', 'bacon'...] const ingredientKeys = Object.keys(ingredients) // ['salad', 'bacon'...]
let ingList = [] let ingList = []
ingredientKeys.forEach(igKey => { ingredientKeys.forEach(igKey => {
......
...@@ -110,3 +110,10 @@ ...@@ -110,3 +110,10 @@
background: linear-gradient(#bf3813, #c45e38); background: linear-gradient(#bf3813, #c45e38);
margin: 2% auto; margin: 2% auto;
} }
.Tomato {
width: 70%;
height: 8%;
background: linear-gradient(to right, red 50%, white 20%, orange 30%);
margin: 2% auto;
}
...@@ -12,16 +12,8 @@ const Ingredient = ({type}) => { ...@@ -12,16 +12,8 @@ const Ingredient = ({type}) => {
<div className='Seeds2' /> <div className='Seeds2' />
</div> </div>
) )
case 'meat':
return <div className='Meat' />
case 'bacon':
return <div className='Bacon' />
case 'cheese':
return <div className='Cheese' />
case 'salad':
return <div className='Salad' />
default: default:
return null return <div className={type} />
} }
} }
......
import React from "react"; import React from "react";
import { useSelector } from "react-redux";
import Button from "../../UI/Button/Button"; import Button from "../../UI/Button/Button";
import './OrderSummary.css' import './OrderSummary.css'
const OrderSummary = (props) => { const OrderSummary = (props) => {
const ingredients = useSelector(state => state.ingredients.basket)
const totalPrice = useSelector(state => state.ingredients.totalPrice)
const ingredientSummary = Object.keys(props.ingredients) const ingredientSummary = Object.keys(ingredients)
.map(igKey => { .map(igKey => {
return ( return (
<li key={igKey}> <li key={igKey}>
<span style={{textTransform: 'capitalize'}}> <span style={{textTransform: 'capitalize'}}>
{igKey} {igKey}
</span> : {props.ingredients[igKey]} </span> : {ingredients[igKey]}
</li> </li>
) )
}) })
...@@ -22,7 +25,7 @@ const OrderSummary = (props) => { ...@@ -22,7 +25,7 @@ const OrderSummary = (props) => {
<ul> <ul>
{ingredientSummary} {ingredientSummary}
</ul> </ul>
<p><strong>Total price: </strong>{props.price} KZT</p> <p><strong>Total price: </strong>{totalPrice} KZT</p>
<p>Continue to checkout</p> <p>Continue to checkout</p>
<Button btnType={'Danger'} clicked={props.purchaseCancelled}>CANCEL</Button> <Button btnType={'Danger'} clicked={props.purchaseCancelled}>CANCEL</Button>
<Button btnType={'Success'} clicked={props.purchaseContinued}>CONTINUE</Button> <Button btnType={'Success'} clicked={props.purchaseContinued}>CONTINUE</Button>
......
import React from 'react'; import React, { useEffect } from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { createSearchParams, useNavigate } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import BuildControls from '../../components/BuildControls/BuildControls'; import BuildControls from '../../components/BuildControls/BuildControls';
import Burger from '../../components/Burger/Burger' import Burger from '../../components/Burger/Burger'
import OrderSummary from '../../components/Burger/OrderSummary/OrderSummary'; import OrderSummary from '../../components/Burger/OrderSummary/OrderSummary';
import Modal from '../../components/UI/Modal/Modal'; import Modal from '../../components/UI/Modal/Modal';
import {INGREDIENT_PRICES} from "../../constants/ingredients_prices"; import { addIngredient, removeIngredient } from '../../store/ingredients.slice';
const BurgerBuilder = () => { const BurgerBuilder = () => {
const dispatch = useDispatch()
const navigate = useNavigate() const navigate = useNavigate()
const [ingredients, setIngredients] = useState({ const ingredients = useSelector(state => state.ingredients.basket)
salad: 0, const totalPrice = useSelector(state => state.ingredients.totalPrice)
bacon: 0,
cheese: 0,
meat: 0
})
const [totalPrice, setTotalPrice] = useState(200)
const [purchasable, setPurchasable] = useState(false) const [purchasable, setPurchasable] = useState(false)
const [purchasing, setPurchasing] = useState(false) const [purchasing, setPurchasing] = useState(false)
const addIngredientHandler = (type) => { const addIngredientHandler = (type) => {
const oldCount = ingredients[type] dispatch(addIngredient(type))
const updateCount = oldCount + 1
const updatedIngredients = {...ingredients}
updatedIngredients[type] = updateCount
const priceAddition = INGREDIENT_PRICES[type]
const newPrice = totalPrice + priceAddition
setIngredients(updatedIngredients)
setTotalPrice(newPrice)
updatePurchaseState(updatedIngredients)
} }
const removeIngredientHandler = (type) => { const removeIngredientHandler = (type) => {
const oldCount = ingredients[type] dispatch(removeIngredient(type))
if (oldCount <= 0) return
const updateCount = oldCount - 1
const updatedIngredients = {...ingredients}
updatedIngredients[type] = updateCount
const priceAddition = INGREDIENT_PRICES[type]
const newPrice = totalPrice - priceAddition
setIngredients(updatedIngredients)
setTotalPrice(newPrice)
updatePurchaseState(updatedIngredients)
} }
const disabledInfo = {...ingredients} const disabledInfo = {...ingredients}
...@@ -57,7 +35,7 @@ const BurgerBuilder = () => { ...@@ -57,7 +35,7 @@ const BurgerBuilder = () => {
disabledInfo[key] = disabledInfo[key] <= 0 disabledInfo[key] = disabledInfo[key] <= 0
} }
const updatePurchaseState = (ingredients) => { const updatePurchaseState = () => {
const sum = Object.keys(ingredients) const sum = Object.keys(ingredients)
.map(igKey => ingredients[igKey]) .map(igKey => ingredients[igKey])
.reduce((sum, el) => sum + el, 0) .reduce((sum, el) => sum + el, 0)
...@@ -65,6 +43,10 @@ const BurgerBuilder = () => { ...@@ -65,6 +43,10 @@ const BurgerBuilder = () => {
setPurchasable(sum > 0) setPurchasable(sum > 0)
} }
useEffect(() => {
updatePurchaseState()
}, [ingredients])
const purchaseHandler = () => { const purchaseHandler = () => {
setPurchasing(true) setPurchasing(true)
} }
...@@ -73,9 +55,7 @@ const BurgerBuilder = () => { ...@@ -73,9 +55,7 @@ const BurgerBuilder = () => {
} }
const purchaseContinueHandler = () => { const purchaseContinueHandler = () => {
const params = new createSearchParams(ingredients) navigate({pathname: '/checkout'})
//salad=0&meat=0&cheese=0&bacon=0
navigate({pathname: '/checkout' , search: params.toString()})
} }
return ( return (
...@@ -85,15 +65,13 @@ const BurgerBuilder = () => { ...@@ -85,15 +65,13 @@ const BurgerBuilder = () => {
closed={purchaseCancelHandler} closed={purchaseCancelHandler}
> >
<OrderSummary <OrderSummary
ingredients={ingredients}
price={totalPrice} price={totalPrice}
purchaseCancelled={purchaseCancelHandler} purchaseCancelled={purchaseCancelHandler}
purchaseContinued={purchaseContinueHandler} purchaseContinued={purchaseContinueHandler}
/> />
</Modal> </Modal>
<Burger ingredients={ingredients} /> <Burger />
<BuildControls <BuildControls
ingredients={ingredients}
price={totalPrice} price={totalPrice}
ingredientAdded={addIngredientHandler} ingredientAdded={addIngredientHandler}
ingredientRemoved={removeIngredientHandler} ingredientRemoved={removeIngredientHandler}
......
import React from "react"; import React from "react";
import { useRef } from "react"; import { Outlet, useNavigate } from "react-router-dom";
import { NavLink, Outlet, useNavigate, useSearchParams } from "react-router-dom";
import CheckoutSummary from "../../components/Order/CheckoutSummary/CheckoutSummary"; import CheckoutSummary from "../../components/Order/CheckoutSummary/CheckoutSummary";
import { parseSearch } from "../../helper/parseSearch"; import { useSelector } from "react-redux";
import {INGREDIENT_PRICES} from "../../constants/ingredients_prices";
const Checkout = () => { const Checkout = () => {
const navigate = useNavigate() const navigate = useNavigate()
const [searchParams, setSearchParams] = useSearchParams()
const ingredients = useSelector(state => state.ingredients.basket)
const parsed = parseSearch(searchParams)
const ingredients = useRef(parsed)
const checkoutCancelledHandler = () => { const checkoutCancelledHandler = () => {
navigate(-1) navigate(-1)
} }
const getTotalPrice = (ingredients) => {
return Object.keys(ingredients).reduce((total, ingName) => {
total += INGREDIENT_PRICES[ingName] * ingredients[ingName]
return total
}, 0)
}
const checkoutContinuedHandler = () => { const checkoutContinuedHandler = () => {
const price = getTotalPrice(ingredients.current) navigate('contact-data')
navigate('contact-data', {state: {ingredients: ingredients.current, price}})
} }
return ( return (
......
...@@ -4,10 +4,13 @@ import Button from "../../../components/UI/Button/Button"; ...@@ -4,10 +4,13 @@ import Button from "../../../components/UI/Button/Button";
import {useLocation, useNavigate} from "react-router-dom"; import {useLocation, useNavigate} from "react-router-dom";
import {apiBurger} from "../../../api/apiBurger"; import {apiBurger} from "../../../api/apiBurger";
import Spinner from "../../../components/UI/Spinner/Spinner"; import Spinner from "../../../components/UI/Spinner/Spinner";
import { useSelector } from 'react-redux';
const ContactData = () => { const ContactData = () => {
const navigate = useNavigate() const navigate = useNavigate()
const location = useLocation() const ingredients = useSelector(state => state.ingredients.basket)
const totalPrice = useSelector(state => state.ingredients.totalPrice)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [customer, setCustomer] = useState({ const [customer, setCustomer] = useState({
name: '', name: '',
...@@ -19,10 +22,9 @@ const ContactData = () => { ...@@ -19,10 +22,9 @@ const ContactData = () => {
const orderHandler = async (event) => { const orderHandler = async (event) => {
event.preventDefault() event.preventDefault()
setLoading(true) setLoading(true)
const {ingredients, price} = location.state
const order = { const order = {
ingredients: ingredients, ingredients: ingredients,
price: price, price: totalPrice,
customer: {...customer} customer: {...customer}
} }
try { try {
......
...@@ -3,10 +3,14 @@ import ReactDOM from 'react-dom/client'; ...@@ -3,10 +3,14 @@ import ReactDOM from 'react-dom/client';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import {store} from './store/store'
const root = ReactDOM.createRoot(document.getElementById('root')); const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( root.render(
<App /> <Provider store={store}>
<App />
</Provider>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function
......
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { apiBurger } from "../api/apiBurger";
const namespace = 'ingredients'
export const getIngredients = createAsyncThunk(
`${namespace}/getIngredients`,
async () => {
return await apiBurger.getIngredients()
}
)
export const ingredientsSlice = createSlice({
name: namespace,
initialState: {
ingredients: [],
basket: {},
totalPrice: 200,
loading: false,
prices: {}
},
reducers: {
addIngredient(state, action) {
try {
state.basket = {
...state.basket,
[action.payload]: state.basket[action.payload] + 1 || 1
}
state.totalPrice += state.prices[action.payload]
} catch (err) {
console.log(err);
}
},
removeIngredient(state, action) {
try {
state.basket = {
...state.basket,
[action.payload]: state.basket[action.payload] > 0
? state.basket[action.payload] - 1
: 0
}
state.totalPrice -= state.prices[action.payload]
} catch (err) {
console.log(err)
}
}
},
extraReducers: builder => {
builder
.addCase(getIngredients.pending, (state) => {
state.loading = true
})
.addCase(getIngredients.rejected, (state) => {
state.loading = false
})
.addCase(getIngredients.fulfilled, (state, action) => {
state.loading = false
state.ingredients = action.payload
action.payload && action.payload.forEach(ing => {
state.basket[ing.name] = 0
})
action.payload && action.payload.forEach(ing => {
state.prices[ing.name] = ing.price
})
})
}
})
export const {
addIngredient,
removeIngredient
} = ingredientsSlice.actions
\ No newline at end of file
import { configureStore } from "@reduxjs/toolkit";
import { ingredientsSlice } from "./ingredients.slice";
export const store = configureStore({
reducer: {
ingredients: ingredientsSlice.reducer
},
devTools: true
})
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment