Ver código fonte

create wishlist and search pages

Alex 2 anos atrás
pai
commit
587d33a7a6

+ 352 - 69
package-lock.json

@@ -10,12 +10,14 @@
       "dependencies": {
         "@emotion/react": "^11.7.1",
         "@emotion/styled": "^11.6.0",
+        "@material-ui/icons": "^4.11.2",
         "@mui/base": "^5.0.0-alpha.63",
         "@mui/icons-material": "^5.2.5",
         "@mui/lab": "^5.0.0-alpha.62",
         "@mui/material": "^5.2.5",
         "@mui/styles": "^5.2.3",
         "@mui/system": "^5.2.6",
+        "@mui/x-data-grid": "^5.2.2",
         "@testing-library/jest-dom": "^5.16.1",
         "@testing-library/react": "^12.1.2",
         "@testing-library/user-event": "^13.5.0",
@@ -2850,10 +2852,184 @@
         "node": ">=8"
       }
     },
+    "node_modules/@material-ui/core": {
+      "version": "4.12.3",
+      "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
+      "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
+      "deprecated": "You can now upgrade to @mui/material. See the guide: https://mui.com/guides/migration-v4/",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/styles": "^4.11.4",
+        "@material-ui/system": "^4.12.1",
+        "@material-ui/types": "5.1.0",
+        "@material-ui/utils": "^4.11.2",
+        "@types/react-transition-group": "^4.2.0",
+        "clsx": "^1.0.4",
+        "hoist-non-react-statics": "^3.3.2",
+        "popper.js": "1.16.1-lts",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0 || ^17.0.0",
+        "react-transition-group": "^4.4.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/material-ui"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.6 || ^17.0.0",
+        "react": "^16.8.0 || ^17.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@material-ui/icons": {
+      "version": "4.11.2",
+      "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz",
+      "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==",
+      "dependencies": {
+        "@babel/runtime": "^7.4.4"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "peerDependencies": {
+        "@material-ui/core": "^4.0.0",
+        "@types/react": "^16.8.6 || ^17.0.0",
+        "react": "^16.8.0 || ^17.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@material-ui/styles": {
+      "version": "4.11.4",
+      "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
+      "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.4.4",
+        "@emotion/hash": "^0.8.0",
+        "@material-ui/types": "5.1.0",
+        "@material-ui/utils": "^4.11.2",
+        "clsx": "^1.0.4",
+        "csstype": "^2.5.2",
+        "hoist-non-react-statics": "^3.3.2",
+        "jss": "^10.5.1",
+        "jss-plugin-camel-case": "^10.5.1",
+        "jss-plugin-default-unit": "^10.5.1",
+        "jss-plugin-global": "^10.5.1",
+        "jss-plugin-nested": "^10.5.1",
+        "jss-plugin-props-sort": "^10.5.1",
+        "jss-plugin-rule-value-function": "^10.5.1",
+        "jss-plugin-vendor-prefixer": "^10.5.1",
+        "prop-types": "^15.7.2"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/material-ui"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.6 || ^17.0.0",
+        "react": "^16.8.0 || ^17.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@material-ui/styles/node_modules/csstype": {
+      "version": "2.6.19",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz",
+      "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==",
+      "peer": true
+    },
+    "node_modules/@material-ui/system": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
+      "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/utils": "^4.11.2",
+        "csstype": "^2.5.2",
+        "prop-types": "^15.7.2"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/material-ui"
+      },
+      "peerDependencies": {
+        "@types/react": "^16.8.6 || ^17.0.0",
+        "react": "^16.8.0 || ^17.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@material-ui/system/node_modules/csstype": {
+      "version": "2.6.19",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz",
+      "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==",
+      "peer": true
+    },
+    "node_modules/@material-ui/types": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
+      "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@material-ui/utils": {
+      "version": "4.11.2",
+      "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
+      "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
+      "peer": true,
+      "dependencies": {
+        "@babel/runtime": "^7.4.4",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0 || ^17.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      },
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0",
+        "react-dom": "^16.8.0 || ^17.0.0"
+      }
+    },
     "node_modules/@mui/base": {
-      "version": "5.0.0-alpha.63",
-      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.63.tgz",
-      "integrity": "sha512-/jURXlBAYqZaWw92XfJgc6aiHnDcNVuRxBskub57HXWCMK3OiVVdfUEWJEdCjOacCKiw3+Etc5alI9Omaqrg2g==",
+      "version": "5.0.0-alpha.64",
+      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.64.tgz",
+      "integrity": "sha512-lqUFbAyYPl3uDaTxGWIUWx9Zin5APv5Rrn/oUcnm/71Isd5dJ94zoGHCTdNy2sxhDRcXRshsdC2dfdwIWxhkZA==",
       "dependencies": {
         "@babel/runtime": "^7.16.3",
         "@emotion/is-prop-valid": "^1.1.1",
@@ -2992,13 +3168,13 @@
       }
     },
     "node_modules/@mui/material": {
-      "version": "5.2.5",
-      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.2.5.tgz",
-      "integrity": "sha512-I0A5IgZlJVyVe9PUrXXuknAbdgij2wVynC2/iyBvoMwc79PoksUZTY4qKPfoy0gDyMRlexRGxZ68XpX5pleMgQ==",
+      "version": "5.2.8",
+      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.2.8.tgz",
+      "integrity": "sha512-GYNYoTDw3C07D1rkB9pTS3xMH3gL0p3kb27SVMrMqP3AWrFxfrS73OnsonJh6Uy/F22pYX6rJxiFOhPq5+i4Eg==",
       "dependencies": {
         "@babel/runtime": "^7.16.3",
-        "@mui/base": "5.0.0-alpha.61",
-        "@mui/system": "^5.2.5",
+        "@mui/base": "5.0.0-alpha.64",
+        "@mui/system": "^5.2.8",
         "@mui/types": "^7.1.0",
         "@mui/utils": "^5.2.3",
         "@types/react-transition-group": "^4.4.4",
@@ -3035,37 +3211,6 @@
         }
       }
     },
-    "node_modules/@mui/material/node_modules/@mui/base": {
-      "version": "5.0.0-alpha.61",
-      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.61.tgz",
-      "integrity": "sha512-xB2EksQsLYOwmBQRDdcJjKAflgBYE9KBZS/TBxIKBlfi4w1v7kCi5VCHTHIQgPSjgoTSt3hyI+yHO2fLvCbUWQ==",
-      "dependencies": {
-        "@babel/runtime": "^7.16.3",
-        "@emotion/is-prop-valid": "^1.1.1",
-        "@mui/utils": "^5.2.3",
-        "@popperjs/core": "^2.4.4",
-        "clsx": "^1.1.1",
-        "prop-types": "^15.7.2",
-        "react-is": "^17.0.2"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui"
-      },
-      "peerDependencies": {
-        "@types/react": "^16.8.6 || ^17.0.0",
-        "react": "^17.0.2",
-        "react-dom": "^17.0.2"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
     "node_modules/@mui/private-theming": {
       "version": "5.2.3",
       "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.2.3.tgz",
@@ -3163,9 +3308,9 @@
       }
     },
     "node_modules/@mui/system": {
-      "version": "5.2.6",
-      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.2.6.tgz",
-      "integrity": "sha512-PZ7bmpWOLikWgqn2zWv9/Xa7lxnRBOmfjoMH7c/IVYJs78W3971brXJ3xV9MEWWQcoqiYQeXzUJaNf4rFbKCBA==",
+      "version": "5.2.8",
+      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.2.8.tgz",
+      "integrity": "sha512-tje1HRubQUk+cDJBG5F83X1j0XzVe+qhellKxByrJVOEEDHoSpbc8UW+NCLSuBBHvOikxihuv3SS4VOWOo2/BQ==",
       "dependencies": {
         "@babel/runtime": "^7.16.3",
         "@mui/private-theming": "^5.2.3",
@@ -3236,6 +3381,29 @@
         "react": "^17.0.2"
       }
     },
+    "node_modules/@mui/x-data-grid": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-5.2.2.tgz",
+      "integrity": "sha512-FI/fwsMMATUdEHwiGGkBdiw/p3G6+iUlkoklBzzsB6MY0Mb+Voj+s/waoFM3uyNJ+h4jof8NTS/Gs8IfDiyciA==",
+      "dependencies": {
+        "@mui/utils": "^5.2.3",
+        "clsx": "^1.1.1",
+        "prop-types": "^15.8.0",
+        "reselect": "^4.1.5"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/mui"
+      },
+      "peerDependencies": {
+        "@mui/material": "^5.2.7",
+        "@mui/system": "^5.2.6",
+        "react": "^17.0.2"
+      }
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -13444,6 +13612,12 @@
         "tslib": "^2.1.0"
       }
     },
+    "node_modules/popper.js": {
+      "version": "1.16.1-lts",
+      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
+      "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
+      "peer": true
+    },
     "node_modules/portfinder": {
       "version": "1.0.28",
       "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -15565,6 +15739,11 @@
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
       "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
     },
+    "node_modules/reselect": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz",
+      "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
+    },
     "node_modules/resolve": {
       "version": "1.20.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
@@ -20525,10 +20704,108 @@
         }
       }
     },
+    "@material-ui/core": {
+      "version": "4.12.3",
+      "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
+      "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
+      "peer": true,
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/styles": "^4.11.4",
+        "@material-ui/system": "^4.12.1",
+        "@material-ui/types": "5.1.0",
+        "@material-ui/utils": "^4.11.2",
+        "@types/react-transition-group": "^4.2.0",
+        "clsx": "^1.0.4",
+        "hoist-non-react-statics": "^3.3.2",
+        "popper.js": "1.16.1-lts",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0 || ^17.0.0",
+        "react-transition-group": "^4.4.0"
+      }
+    },
+    "@material-ui/icons": {
+      "version": "4.11.2",
+      "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz",
+      "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==",
+      "requires": {
+        "@babel/runtime": "^7.4.4"
+      }
+    },
+    "@material-ui/styles": {
+      "version": "4.11.4",
+      "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
+      "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
+      "peer": true,
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@emotion/hash": "^0.8.0",
+        "@material-ui/types": "5.1.0",
+        "@material-ui/utils": "^4.11.2",
+        "clsx": "^1.0.4",
+        "csstype": "^2.5.2",
+        "hoist-non-react-statics": "^3.3.2",
+        "jss": "^10.5.1",
+        "jss-plugin-camel-case": "^10.5.1",
+        "jss-plugin-default-unit": "^10.5.1",
+        "jss-plugin-global": "^10.5.1",
+        "jss-plugin-nested": "^10.5.1",
+        "jss-plugin-props-sort": "^10.5.1",
+        "jss-plugin-rule-value-function": "^10.5.1",
+        "jss-plugin-vendor-prefixer": "^10.5.1",
+        "prop-types": "^15.7.2"
+      },
+      "dependencies": {
+        "csstype": {
+          "version": "2.6.19",
+          "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz",
+          "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==",
+          "peer": true
+        }
+      }
+    },
+    "@material-ui/system": {
+      "version": "4.12.1",
+      "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
+      "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
+      "peer": true,
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/utils": "^4.11.2",
+        "csstype": "^2.5.2",
+        "prop-types": "^15.7.2"
+      },
+      "dependencies": {
+        "csstype": {
+          "version": "2.6.19",
+          "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz",
+          "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==",
+          "peer": true
+        }
+      }
+    },
+    "@material-ui/types": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
+      "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
+      "peer": true,
+      "requires": {}
+    },
+    "@material-ui/utils": {
+      "version": "4.11.2",
+      "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
+      "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
+      "peer": true,
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0 || ^17.0.0"
+      }
+    },
     "@mui/base": {
-      "version": "5.0.0-alpha.63",
-      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.63.tgz",
-      "integrity": "sha512-/jURXlBAYqZaWw92XfJgc6aiHnDcNVuRxBskub57HXWCMK3OiVVdfUEWJEdCjOacCKiw3+Etc5alI9Omaqrg2g==",
+      "version": "5.0.0-alpha.64",
+      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.64.tgz",
+      "integrity": "sha512-lqUFbAyYPl3uDaTxGWIUWx9Zin5APv5Rrn/oUcnm/71Isd5dJ94zoGHCTdNy2sxhDRcXRshsdC2dfdwIWxhkZA==",
       "requires": {
         "@babel/runtime": "^7.16.3",
         "@emotion/is-prop-valid": "^1.1.1",
@@ -20584,13 +20861,13 @@
       }
     },
     "@mui/material": {
-      "version": "5.2.5",
-      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.2.5.tgz",
-      "integrity": "sha512-I0A5IgZlJVyVe9PUrXXuknAbdgij2wVynC2/iyBvoMwc79PoksUZTY4qKPfoy0gDyMRlexRGxZ68XpX5pleMgQ==",
+      "version": "5.2.8",
+      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.2.8.tgz",
+      "integrity": "sha512-GYNYoTDw3C07D1rkB9pTS3xMH3gL0p3kb27SVMrMqP3AWrFxfrS73OnsonJh6Uy/F22pYX6rJxiFOhPq5+i4Eg==",
       "requires": {
         "@babel/runtime": "^7.16.3",
-        "@mui/base": "5.0.0-alpha.61",
-        "@mui/system": "^5.2.5",
+        "@mui/base": "5.0.0-alpha.64",
+        "@mui/system": "^5.2.8",
         "@mui/types": "^7.1.0",
         "@mui/utils": "^5.2.3",
         "@types/react-transition-group": "^4.4.4",
@@ -20600,22 +20877,6 @@
         "prop-types": "^15.7.2",
         "react-is": "^17.0.2",
         "react-transition-group": "^4.4.2"
-      },
-      "dependencies": {
-        "@mui/base": {
-          "version": "5.0.0-alpha.61",
-          "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.61.tgz",
-          "integrity": "sha512-xB2EksQsLYOwmBQRDdcJjKAflgBYE9KBZS/TBxIKBlfi4w1v7kCi5VCHTHIQgPSjgoTSt3hyI+yHO2fLvCbUWQ==",
-          "requires": {
-            "@babel/runtime": "^7.16.3",
-            "@emotion/is-prop-valid": "^1.1.1",
-            "@mui/utils": "^5.2.3",
-            "@popperjs/core": "^2.4.4",
-            "clsx": "^1.1.1",
-            "prop-types": "^15.7.2",
-            "react-is": "^17.0.2"
-          }
-        }
       }
     },
     "@mui/private-theming": {
@@ -20663,9 +20924,9 @@
       }
     },
     "@mui/system": {
-      "version": "5.2.6",
-      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.2.6.tgz",
-      "integrity": "sha512-PZ7bmpWOLikWgqn2zWv9/Xa7lxnRBOmfjoMH7c/IVYJs78W3971brXJ3xV9MEWWQcoqiYQeXzUJaNf4rFbKCBA==",
+      "version": "5.2.8",
+      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.2.8.tgz",
+      "integrity": "sha512-tje1HRubQUk+cDJBG5F83X1j0XzVe+qhellKxByrJVOEEDHoSpbc8UW+NCLSuBBHvOikxihuv3SS4VOWOo2/BQ==",
       "requires": {
         "@babel/runtime": "^7.16.3",
         "@mui/private-theming": "^5.2.3",
@@ -20695,6 +20956,17 @@
         "react-is": "^17.0.2"
       }
     },
+    "@mui/x-data-grid": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-5.2.2.tgz",
+      "integrity": "sha512-FI/fwsMMATUdEHwiGGkBdiw/p3G6+iUlkoklBzzsB6MY0Mb+Voj+s/waoFM3uyNJ+h4jof8NTS/Gs8IfDiyciA==",
+      "requires": {
+        "@mui/utils": "^5.2.3",
+        "clsx": "^1.1.1",
+        "prop-types": "^15.8.0",
+        "reselect": "^4.1.5"
+      }
+    },
     "@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -28242,6 +28514,12 @@
         "tslib": "^2.1.0"
       }
     },
+    "popper.js": {
+      "version": "1.16.1-lts",
+      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
+      "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
+      "peer": true
+    },
     "portfinder": {
       "version": "1.0.28",
       "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -29655,6 +29933,11 @@
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
       "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
     },
+    "reselect": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz",
+      "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
+    },
     "resolve": {
       "version": "1.20.0",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",

+ 2 - 0
package.json

@@ -5,12 +5,14 @@
   "dependencies": {
     "@emotion/react": "^11.7.1",
     "@emotion/styled": "^11.6.0",
+    "@material-ui/icons": "^4.11.2",
     "@mui/base": "^5.0.0-alpha.63",
     "@mui/icons-material": "^5.2.5",
     "@mui/lab": "^5.0.0-alpha.62",
     "@mui/material": "^5.2.5",
     "@mui/styles": "^5.2.3",
     "@mui/system": "^5.2.6",
+    "@mui/x-data-grid": "^5.2.2",
     "@testing-library/jest-dom": "^5.16.1",
     "@testing-library/react": "^12.1.2",
     "@testing-library/user-event": "^13.5.0",

+ 6 - 0
src/App.js

@@ -16,6 +16,9 @@ import CatalogPage from "./pages/CatalogPage";
 import Header from "./components/Header";
 import Footer from "./components/Footer";
 import ProductPage from "./pages/ProductPage";
+import WishListPage from "./pages/WishListPage";
+import SearchPage from "./pages/SearchPage";
+import MyOrdersPage from "./pages/MyOrdersPage";
 
 const history = createHistory();
 
@@ -34,6 +37,9 @@ function App() {
                   <Route path="/contact" component={ContactPage} />
                   <Route path="/my-account" component={MyAccountPage} />
                   <Route path="/privacy-policy" component={PrivacyPolicy} />
+                  <Route path="/search" component={SearchPage} />
+                  <Route path="/wish-list" component={WishListPage} />
+                  <Route path="/my-orders" component={MyOrdersPage} />
                   <Route path="/profile" component={ProfilePage} />
                   <Route path="*" component={Page404} />
               </Switch>

+ 29 - 0
src/actions/ActionGoodFind.js

@@ -1,3 +1,5 @@
+import {actionSearchResult} from "../reducers/SearchReducer";
+
 const {actionPromise} = require("../reducers/PromiseReducer");
 const {gql} = require("./PathDB");
 
@@ -11,3 +13,30 @@ export const actionGoodFindOne = (_id) =>
                 }
             }
     }`, { q: JSON.stringify([{ _id }]) }))
+
+export const actionGoodFind = (text) =>
+    actionPromise('goodFind', gql(`
+        query goodFind($query: String){
+            GoodFind(query: $query){
+                _id, name, description, price, images{
+                    _id, url
+                }
+            }
+        }`, {query: JSON.stringify([
+                {
+                    $or: [{name: `/${text}/`}, {description: `/${text}/`}]
+                },
+                {
+                    sort: [{title: 1}]
+                }
+            ])}
+        )
+    )
+
+export const actionFullGoodFind = (text) =>
+    async dispatch => {
+        let value = await dispatch(actionGoodFind(text))
+        if (value){
+            dispatch(actionSearchResult(value))
+        }
+    }

+ 17 - 0
src/actions/ActionOrderFind.js

@@ -0,0 +1,17 @@
+import {actionPromise} from "../reducers/PromiseReducer";
+import {gql} from "./PathDB";
+
+export const actionOrderFind = () => {
+    return actionPromise('orderFind', gql(`query orderFind {
+        OrderFind(query:"[{}]") {
+            _id total createdAt orderGoods{
+                _id count price good{
+                    _id name description images{
+                        _id url
+                    }
+                }
+            }
+        }
+    }`)
+    )
+}

+ 44 - 0
src/components/NotFoundBlock.jsx

@@ -0,0 +1,44 @@
+import {Box, Container, Typography, useMediaQuery} from "@mui/material";
+import imgUrl from "../img/not-found/1.png";
+
+export const NotFoundBlock = ({img=imgUrl, headerText='OOPS! THAT PAGE CAN’T BE FOUND', text='The page you are trying to reach is not available.'}) => {
+    const matches = useMediaQuery('(max-width:899px)');
+    const matches2 = useMediaQuery('(max-width:450px)');
+
+    return (
+        <main style={{backgroundColor: "#f3f3f3", padding: matches ? "20px 0" : "50px 0"}}>
+            <Container maxWidth="lg">
+                <Box sx={{
+                    backgroundColor: "#fff",
+                    height: matches2 ? "250px" : "350px",
+                    display: "flex",
+                    flexDirection: "column",
+                    justifyContent: "center",
+                    alignItems: "center"
+                }}>
+                    <img style={{
+                        maxWidth: matches2 ? "100px" : "150px"
+                    }} src={img} alt={headerText}/>
+                    <Typography
+                        variant={matches2 ? "h6" : "h5"}
+                        fontFamily="sarif"
+                        fontWeight="300"
+                        marginBottom="20px"
+                        marginTop="20px"
+                        textAlign="center"
+                        sx={{textTransform: 'uppercase'}}
+                    >
+                        {headerText}
+                    </Typography>
+                    <Typography
+                        variant={matches2 ? "body1" : "h7"}
+                        textAlign="center"
+                        fontWeight="300"
+                    >
+                        {text}
+                    </Typography>
+                </Box>
+            </Container>
+        </main>
+    )
+}

BIN
src/img/not-found/2.png


+ 2 - 37
src/pages/404Page.jsx

@@ -1,46 +1,11 @@
 import Breadcrumbs from "../components/Breadcrumbs";
-import imgUrl from "../img/not-found/1.png"
-import {Box, Container, Typography, useMediaQuery} from "@mui/material";
+import {NotFoundBlock} from "../components/NotFoundBlock";
 
 const Page404 = () => {
-    const matches = useMediaQuery('(max-width:899px)');
-    const matches2 = useMediaQuery('(max-width:450px)');
     return (
         <>
             <Breadcrumbs links={['404 page']} title={'PAGE NOT FOUND'} />
-            <main style={{backgroundColor: "#f3f3f3", padding: matches ? "20px 0" : "50px 0"}}>
-                <Container maxWidth="lg">
-                    <Box sx={{
-                        backgroundColor: "#fff",
-                        height: matches2 ? "250px" : "350px",
-                        display: "flex",
-                        flexDirection: "column",
-                        justifyContent: "center",
-                        alignItems: "center"
-                    }}>
-                        <img style={{
-                            maxWidth: matches2 ? "100px" : "150px"
-                        }} src={imgUrl} alt="PAGE NOT FOUND"/>
-                        <Typography
-                            variant={matches2 ? "h6" : "h5"}
-                            fontFamily="sarif"
-                            fontWeight="300"
-                            marginBottom="20px"
-                            marginTop="20px"
-                            textAlign="center"
-                        >
-                            OOPS! THAT PAGE CAN’T BE FOUND
-                        </Typography>
-                        <Typography
-                            variant={matches2 ? "body1" : "h7"}
-                            textAlign="center"
-                            fontWeight="300"
-                        >
-                            The page you are trying to reach is not available.
-                        </Typography>
-                    </Box>
-                </Container>
-            </main>
+            <NotFoundBlock/>
         </>
     )
 }

+ 3 - 40
src/pages/CatalogPage.jsx

@@ -24,8 +24,8 @@ import {Pagination} from "@mui/material";
 import {actionWishListAdd, actionWishListRemove} from "../reducers/WishListReducer";
 import FavoriteIcon from '@mui/icons-material/Favorite';
 import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import imgUrl from "../img/not-found/1.png";
 import imgNotFound from "../img/catalog/imgNotFound.png";
+import {NotFoundBlock} from "../components/NotFoundBlock";
 
 const CategoryItem = ({object: {_id, name, subCategories}={}}) => {
     const [expanded, setExpanded] = useState(false);
@@ -151,43 +151,6 @@ const GoodCard = ({good:{_id, name, description, price, images}={}, wishlist={},
 const CGoodCard = connect(state => ({wishlist: state.wishlist, cart: state.cart}),
     {onCartAdd: actionCartAdd, onWishListAdd: actionWishListAdd, onCartRemove: actionCardRemove, onWishListRemove: actionWishListRemove})(GoodCard)
 
-const GoodNotFound = () => {
-    const matches2 = useMediaQuery('(max-width:450px)');
-    return (
-        <Container maxWidth="lg">
-            <Box sx={{
-                backgroundColor: "#fff",
-                height: matches2 ? "250px" : "350px",
-                display: "flex",
-                flexDirection: "column",
-                justifyContent: "center",
-                alignItems: "center"
-            }}>
-                <img style={{
-                    maxWidth: matches2 ? "100px" : "150px"
-                }} src={imgUrl} alt="PAGE NOT FOUND"/>
-                <Typography
-                    variant={matches2 ? "h6" : "h5"}
-                    fontFamily="sarif"
-                    fontWeight="300"
-                    marginBottom="20px"
-                    marginTop="20px"
-                    textAlign="center"
-                >
-                    OOPS! THAT PAGE CAN’T BE FOUND
-                </Typography>
-                <Typography
-                    variant={matches2 ? "body1" : "h7"}
-                    textAlign="center"
-                    fontWeight="300"
-                >
-                    The page you are trying to reach is not available.
-                </Typography>
-            </Box>
-        </Container>
-    )
-}
-
 const Goods = ({_id='5dc49f4d5df9d670df48cc64', category={}}) => {
     const itemsPerPage = 6
     const [page, setPage] = useState(1)
@@ -312,7 +275,7 @@ const Goods = ({_id='5dc49f4d5df9d670df48cc64', category={}}) => {
                         </Box>
                     </Box>
                 </Box>
-                : <GoodNotFound/>)
+                : <NotFoundBlock/>)
             }
         </>
     )
@@ -334,7 +297,7 @@ const Products = () => {
         <Grid xs={12} lg={9} item>
             <Switch>
                 <Route path="/catalog/category/:_id" component={CBlockGood} />
-                <Route path="*" component={GoodNotFound} />
+                <Route path="*" component={NotFoundBlock} />
             </Switch>
         </Grid>
     )

+ 15 - 0
src/pages/MyOrdersPage.jsx

@@ -0,0 +1,15 @@
+import Breadcrumb from "../components/Breadcrumbs";
+import {useMediaQuery} from "@mui/material";
+
+const MyOrdersPage = () => {
+    const matches = useMediaQuery('(max-width:768px)');
+    return (
+        <>
+            <Breadcrumb links={['My orders']} />
+            <main style={{backgroundColor: "#f3f3f3", padding: matches ? "20px 0" : "50px 0"}}>
+
+            </main>
+        </>
+    )
+}
+export default MyOrdersPage

+ 116 - 0
src/pages/SearchPage.jsx

@@ -0,0 +1,116 @@
+import {
+    Box,
+    CircularProgress,
+    Container,
+    IconButton,
+    InputAdornment,
+    TextField,
+    Typography,
+    useMediaQuery
+} from "@mui/material";
+import SearchIcon from "@material-ui/icons/Search";
+import {connect} from "react-redux";
+import {actionFullGoodFind} from "../actions/ActionGoodFind";
+import {useState} from "react";
+import {backURL} from "../actions/PathDB";
+import imgNotFound from "../img/catalog/imgNotFound.png";
+import Link from "react-router-dom/es/Link";
+import {actionSearchRemove} from "../reducers/SearchReducer";
+
+const NotFound = () => {
+    return (
+        <Typography
+            textAlign='center'
+            color='#000'
+            letterSpacing='1px'
+            variant='body1'
+        >
+            No results found
+        </Typography>
+    )
+}
+const ItemFound = ({item:{_id, name, price, images, description}}) => {
+    return (
+        <Link style={{textDecoration: 'none', display: 'flex', alignItems: 'center', marginBottom: '30px'}} to={`/good/${_id}`}>
+            <Box width='60px' height='60px' borderRadius='10px' overflow='hidden' marginRight='60px' position='relative'>
+                <img style={{position: 'absolute',top: '0', left: '0', width: '100%', height: '100%', objectFit: 'cover'}} src={images[0]?.url ? backURL + '/' + images[0]?.url : imgNotFound} alt={name}/>
+            </Box>
+            <Box sx={{display: 'flex', flexDirection:'column', justifyContent: 'space-between', alignItems:'flex-start'}}>
+                <Typography
+                    color='#000'
+                    letterSpacing='1px'
+                    fontFamily='sarif'
+                    fontWeight='600'
+                    variant='h6'
+                >
+                    {name}
+                </Typography>
+                <Typography
+                    letterSpacing='1px'
+                    variant='body1'
+                    fontWeight='300'
+                    color='#616161'
+                    margin='10px 0'
+                >
+                    {description.length > 60 ? 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' : description}
+                </Typography>
+                <Typography
+                    color='#000'
+                    letterSpacing='1px'
+                    variant='body1'
+                    fontWeight='600'
+                >
+                    ${parseFloat(price).toFixed(2)}
+                </Typography>
+            </Box>
+        </Link>
+    )
+}
+
+const SearchPage = ({searchResult, onSearch, onSearchRemove}) => {
+    const matches = useMediaQuery('(max-width:899px)')
+    const [value, setValue] = useState('')
+    const [click, setClick] = useState(false)
+    return(
+        <>
+            <main style={{backgroundColor: "#f3f3f3", marginTop: '85px', padding: matches ? "20px 0" : "50px 0", minHeight: 'calc(100vh - (185px + 290px))'}}>
+                <Container maxWidth="sm">
+                    <Typography
+                        variant='h5'
+                        fontFamily='sarif'
+                        letterSpacing='3px'
+                        marginBottom='30px'
+                    >
+                        WHAT YOU ARE LOOKING FOR?
+                    </Typography>
+                    <TextField
+                        color={'primary'}
+                        fullWidth
+                        variant="standard"
+                        value={value}
+                        placeholder="Start typing..."
+                        onChange={(event) => {setClick(false); setValue(event.target.value); onSearchRemove()}}
+                        InputProps={{
+                            sx: {padding: '10px', outline:'none', color: '#616161', fontWeight: '300', letterSpacing: '1px', marginBottom: '50px'},
+                            endAdornment: (
+                                <InputAdornment position="end">
+                                    <IconButton onClick={() => {setClick(true); onSearchRemove(); onSearch(value)}}>
+                                        <SearchIcon />
+                                    </IconButton>
+                                </InputAdornment>
+                            )
+                        }}
+                    />
+                    {(value !== '' && click) && (searchResult?.searchResult ?
+                        Object.values(searchResult.searchResult).length > 0  ?
+                            Object.values(searchResult.searchResult).map(item => <ItemFound item={item}/>) : <NotFound/> :
+                        <CircularProgress color="inherit"/>
+                    )}
+                </Container>
+            </main>
+        </>
+    )
+}
+const CSearchPage = connect(state=>({searchResult: state.search}), {onSearch: actionFullGoodFind, onSearchRemove: actionSearchRemove})(SearchPage)
+export default CSearchPage
+// TODO MOBILE VERSION

+ 107 - 0
src/pages/WishListPage.jsx

@@ -0,0 +1,107 @@
+import Breadcrumb from "../components/Breadcrumbs";
+import {Box, Button, Container, Divider, Grid, Typography, useMediaQuery} from "@mui/material";
+import {connect} from 'react-redux';
+import {actionWishListRemove} from "../reducers/WishListReducer";
+import {actionCardChange} from "../reducers/CartReducer";
+import Link from "react-router-dom/es/Link";
+import {backURL} from "../actions/PathDB";
+import imgNotFound from "../img/catalog/imgNotFound.png";
+import CloseIcon from '@mui/icons-material/Close';
+import {NotFoundBlock} from "../components/NotFoundBlock";
+import imgUrl from "../img/not-found/2.png"
+import FavoriteBorderIcon from "@mui/icons-material/FavoriteBorder";
+
+const ItemHeaderLine = ({text, align='left'}) => {
+    return (
+        <Typography
+            color='#616161'
+            variant='body1'
+            letterSpacing='1px'
+            textAlign={align}
+        >
+            {text || ''}
+        </Typography>
+    )
+}
+const LinkProductItem = ({item: [_id, name, images]}) => {
+    return (
+        <Link style={{textDecoration: 'none', display: 'flex', alignItems: 'center'}} to={`/good/${_id}`}>
+            <Box width='60px' height='60px' borderRadius='10px' overflow='hidden' marginRight='20px'>
+                <img style={{width: '100%', height: '100%', objectFit: 'cover'}} src={images[0]?.url ? backURL + '/' + images[0]?.url : imgNotFound} alt={name}/>
+            </Box>
+            <ItemHeaderLine text={name}/>
+        </Link>
+    )
+}
+const AddToCart = ({good, addToCart}) => {
+    return (
+        <Button
+            sx={{height: '40px', width: '70%', borderRadius: '0', color: '#000', borderColor: '#000', fontSize: '16px', fontWeight: '300'}}
+            variant="outlined"
+            color={"inherit"}
+            onClick={() => addToCart(good)}
+        >
+            ADD TO CART
+        </Button>
+    )
+}
+const RemoveFromWishList = ({good, onWishListRemove}) => {
+    return (
+        <Button
+            size="small"
+            color="inherit"
+            onClick={() => onWishListRemove(good)}
+        >
+            <CloseIcon/>
+        </Button>
+    )
+}
+const TableLine = ({columnName, role='header'}) => {
+    const good = {'_id': columnName[0][0], 'name': columnName[0][1], 'images': columnName[0][2], 'price': columnName[1]};
+    return (
+        <Grid container justifyContent='space-between' marginBottom='20px' alignItems='center'>
+            <Grid item xs={3} md={5}>
+                {role === 'header' ? <ItemHeaderLine text={columnName[0]}/> : <LinkProductItem item={columnName[0]}/>}
+            </Grid>
+            <Grid item xs={3} md={2}>
+                <ItemHeaderLine text={role === 'header' ? columnName[1] : '$'+columnName[1]} align={'center'}/>
+            </Grid>
+            <Grid item xs={3} md={3} display='flex' justifyContent='center'>
+                {role === 'header' ? <ItemHeaderLine text={columnName[3]} align={'center'}/> : <AddToCart good={good} addToCart={columnName[3]}/>}
+            </Grid>
+            <Grid item xs={3} md={1} display='flex' justifyContent='center'>
+                {role === 'header' ? <ItemHeaderLine text={columnName[2]} align={'center'}/> : <RemoveFromWishList good={good} onWishListRemove={columnName[2]}/>}
+            </Grid>
+        </Grid>
+    )
+}
+
+const WishListPage = ({wishlist, addToCart, onWishListRemove}) => {
+    const matches = useMediaQuery('(max-width:899px)')
+    let rows = []
+    for (const key of Object.values(wishlist)) {
+        for (const item in key) {
+            rows.push(key[item])
+        }
+    }
+    return (
+        <>
+            <Breadcrumb links={['wish list']}/>
+            {Object.values(wishlist).length > 0 ?
+                <main style={{backgroundColor: "#f3f3f3", padding: matches ? "20px 0" : "50px 0"}}>
+                    <Container maxWidth="lg">
+                        <TableLine columnName={['PRODUCT', 'PRICE', 'REMOVE', 'ADD TO CART']}/>
+                        <Divider sx={{marginBottom: '20px'}}/>
+                        {rows.map(item => <TableLine columnName={[[item?._id, item?.name, item?.images], item?.price, onWishListRemove, addToCart]} role={'item'}/>)}
+                        <Divider/>
+                    </Container>
+                </main> :
+                <NotFoundBlock img={imgUrl} headerText={'YOUR WISHLIST IS CURRENTLY EMPTY'} text={<Box display='flex' alignItems='center'><Typography component='span'>Click the</Typography><FavoriteBorderIcon sx={{margin: '0 10px'}}/><Typography component='span'>icons to add products</Typography></Box>}/>
+            }
+        </>
+    )
+}
+const CWishListPage = connect(state => ({wishlist: state.wishlist}), {addToCart: actionCardChange, onWishListRemove: actionWishListRemove})(WishListPage)
+
+export default CWishListPage
+// TODO MOBILE VERSION

+ 3 - 1
src/reducers/CombineReducers.js

@@ -6,6 +6,7 @@ import {UserReducer} from "./UserReducer";
 import {CategoryReducer} from "./CategoryReducer";
 import {WishListReducer} from "./WishListReducer";
 import {localStoredReducer} from "./LocalStoredReducer";
+import {SearchReducer} from "./SearchReducer";
 
 export const rootReducer = combineReducers({
     auth: AuthReducer,
@@ -13,5 +14,6 @@ export const rootReducer = combineReducers({
     cart: localStoredReducer(CartReducer, 'cart'),
     user: UserReducer,
     category: localStoredReducer(CategoryReducer,'category'),
-    wishlist: localStoredReducer(WishListReducer, 'wishlist')
+    wishlist: localStoredReducer(WishListReducer, 'wishlist'),
+    search: SearchReducer
 })

+ 14 - 0
src/reducers/SearchReducer.js

@@ -0,0 +1,14 @@
+export const SearchReducer = (state={}, { type, value }) => {
+    if (type === 'SEARCH_RESULT'){
+        return {
+            searchResult: {...value}
+        }
+    }
+    if (type === 'SEARCH_REMOVE'){
+        return {}
+    }
+    return state
+}
+
+export const actionSearchResult = value => ({type: 'SEARCH_RESULT', value})
+export const actionSearchRemove = () => ({type: 'SEARCH_REMOVE'})