diff --git a/.vscode/settings.json b/.vscode/settings.json index 3b305db91..2ff85f1b2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.formatOnSave": false, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" } } diff --git a/package-lock.json b/package-lock.json index 610d3e076..292bf7576 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "eplay", "version": "0.1.0", "dependencies": { + "@reduxjs/toolkit": "^2.5.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -15,13 +16,21 @@ "@types/node": "^16.18.23", "@types/react": "^18.0.31", "@types/react-dom": "^18.0.11", + "formik": "^2.4.6", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^9.2.0", + "react-router-dom": "^6.26.2", + "react-router-hash-link": "^2.4.3", "react-scripts": "5.0.1", + "react-spinners": "^0.15.0", + "styled-components": "^6.1.13", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "yup": "^1.6.1" }, "devDependencies": { + "@types/react-router-hash-link": "^2.4.9", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^5.53.0", "@typescript-eslint/parser": "^5.53.0", @@ -2148,6 +2157,24 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3112,6 +3139,46 @@ } } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.5.0.tgz", + "integrity": "sha512-awNe2oTodsZ6LmRqmkFhtb/KH03hUhxOamEQy411m3Njj3BbFvoBovxo4Q1cBWnV1ErprVj9MlF0UPXkng0eyg==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "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.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/@remix-run/router": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz", + "integrity": "sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3859,11 +3926,16 @@ "@types/node": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, "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==", - "dev": true, "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -3963,12 +4035,11 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "18.0.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.31.tgz", - "integrity": "sha512-EEG67of7DsvRDU6BLLI0p+k1GojDLz9+lZsnCpCRTa/lOokvyPBvp8S5x+A24hME3yyQuIipcP70KJ6H7Qupww==", + "version": "18.3.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.17.tgz", + "integrity": "sha512-opAQ5no6LqJNo9TqnxBKsgnkIYHozW9KSTlFVoSUJYh1Fl/sswkEoqIugRSm7tbh6pABtYjGAjW+GOS23j8qbw==", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, @@ -3980,6 +4051,38 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/react-router-hash-link": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/react-router-hash-link/-/react-router-hash-link-2.4.9.tgz", + "integrity": "sha512-zl/VMj+lfJZhvjOAQXIlBVPNKSK+/fRG8AUHhlP9++LhlA2ziLeTmbRxIMJI3PCiCTS+W/FosEoDRoNOGH0OzA==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-dom": "^5.3.0" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -3993,11 +4096,6 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, "node_modules/@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -4044,6 +4142,11 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==" + }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.5", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", @@ -4057,6 +4160,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==" + }, "node_modules/@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -5403,6 +5511,14 @@ "node": ">= 6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -5838,6 +5954,14 @@ "postcss": "^8.4" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, "node_modules/css-declaration-sorter": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", @@ -6019,6 +6143,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -6206,9 +6340,9 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -8108,6 +8242,38 @@ "node": ">= 6" } }, + "node_modules/formik": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz", + "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==", + "funding": [ + { + "type": "individual", + "url": "https://opencollective.com/formik" + } + ], + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.1", + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "react-fast-compare": "^2.0.1", + "tiny-warning": "^1.0.2", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/formik/node_modules/deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -8512,7 +8678,6 @@ "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==", - "dev": true, "dependencies": { "react-is": "^16.7.0" } @@ -8520,8 +8685,7 @@ "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==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/hoopy": { "version": "0.1.4", @@ -11623,6 +11787,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -11959,9 +12128,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -12608,9 +12777,9 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -12619,12 +12788,16 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -13893,6 +14066,11 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -14202,11 +14380,38 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, "node_modules/react-is": { "version": "17.0.2", "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.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "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", @@ -14215,6 +14420,48 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.2.tgz", + "integrity": "sha512-tvN1iuT03kHgOFnLPfLJ8V95eijteveqdOSk+srqfePtQvqCExB8eHOYnlilbOcyJyKnYkr1vJvf7YqotAJu1A==", + "dependencies": { + "@remix-run/router": "1.19.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.2.tgz", + "integrity": "sha512-z7YkaEW0Dy35T3/QKPYB1LjMK2R1fxnHO8kWpUMTBdfVzZrWOiY9a7CtN8HqdWtDUWd5FY6Dl8HFsqVwH4uOtQ==", + "dependencies": { + "@remix-run/router": "1.19.2", + "react-router": "6.26.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-router-hash-link": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/react-router-hash-link/-/react-router-hash-link-2.4.3.tgz", + "integrity": "sha512-NU7GWc265m92xh/aYD79Vr1W+zAIXDWp3L2YZOYP4rCqPnJ6LI6vh3+rKgkidtYijozHclaEQTAHaAaMWPVI4A==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router-dom": ">=4" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -14287,6 +14534,15 @@ } } }, + "node_modules/react-spinners": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.15.0.tgz", + "integrity": "sha512-ZO3/fNB9Qc+kgpG3SfdlMnvTX6LtLmTnOogb3W6sXIaU/kZ1ydEViPfZ06kSOaEsor58C/tzXw2wROGQu3X2pA==", + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -14342,6 +14598,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/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -14468,6 +14737,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -14993,6 +15267,11 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -15075,9 +15354,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -15395,6 +15674,33 @@ "webpack": "^5.0.0" } }, + "node_modules/styled-components": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", + "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.38", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", @@ -15410,6 +15716,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==" + }, "node_modules/sucrase": { "version": "3.31.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.31.0.tgz", @@ -15807,6 +16118,16 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -15839,6 +16160,11 @@ "node": ">=0.6" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, "node_modules/tough-cookie": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", @@ -15913,9 +16239,9 @@ } }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -16144,6 +16470,14 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -17153,6 +17487,28 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yup": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz", + "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 8a7c7fe75..ab444c735 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@reduxjs/toolkit": "^2.5.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -10,11 +11,18 @@ "@types/node": "^16.18.23", "@types/react": "^18.0.31", "@types/react-dom": "^18.0.11", + "formik": "^2.4.6", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-redux": "^9.2.0", + "react-router-dom": "^6.26.2", + "react-router-hash-link": "^2.4.3", "react-scripts": "5.0.1", + "react-spinners": "^0.15.0", + "styled-components": "^6.1.13", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "yup": "^1.6.1" }, "scripts": { "start": "react-scripts start", @@ -41,6 +49,7 @@ ] }, "devDependencies": { + "@types/react-router-hash-link": "^2.4.9", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^5.53.0", "@typescript-eslint/parser": "^5.53.0", diff --git a/public/index.html b/public/index.html index aa069f27c..e0fab60c1 100644 --- a/public/index.html +++ b/public/index.html @@ -25,6 +25,9 @@ Learn how to configure a non-root public URL by running `npm run build`. --> React App + + + diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e0534..000000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.tsx b/src/App.tsx index d53c68d8a..ea9264129 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,25 +1,29 @@ -import React from 'react' -import logo from './logo.svg' -import './App.css' +import { Provider } from 'react-redux' +import { BrowserRouter } from 'react-router-dom' + +import { Header } from './components/Header' +import { GlobalCss } from './styles' + +import { Rotas } from './routes' +import { Footer } from './components/Footer' +import { store } from './store' +import { Cart } from './components/Cart' function App() { return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
-
+ +
+ + +
+
+
+ +
+
) } diff --git "a/src/assets/images/1 - Mistborn Primeira Era - O imp\303\251rio final.pdf" "b/src/assets/images/1 - Mistborn Primeira Era - O imp\303\251rio final.pdf" new file mode 100644 index 000000000..b4d4f4604 Binary files /dev/null and "b/src/assets/images/1 - Mistborn Primeira Era - O imp\303\251rio final.pdf" differ diff --git a/src/assets/images/banner-homem-aranha.png b/src/assets/images/banner-homem-aranha.png new file mode 100644 index 000000000..b1efdf7da Binary files /dev/null and b/src/assets/images/banner-homem-aranha.png differ diff --git a/src/assets/images/barcode.png b/src/assets/images/barcode.png new file mode 100644 index 000000000..43a383eba Binary files /dev/null and b/src/assets/images/barcode.png differ diff --git a/src/assets/images/carrinho.svg b/src/assets/images/carrinho.svg new file mode 100644 index 000000000..096e47b83 --- /dev/null +++ b/src/assets/images/carrinho.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/credit-card.png b/src/assets/images/credit-card.png new file mode 100644 index 000000000..8c97f04c2 Binary files /dev/null and b/src/assets/images/credit-card.png differ diff --git a/src/assets/images/diablo.png b/src/assets/images/diablo.png new file mode 100644 index 000000000..1a80c0363 Binary files /dev/null and b/src/assets/images/diablo.png differ diff --git a/src/assets/images/fechar.png b/src/assets/images/fechar.png new file mode 100644 index 000000000..ccddafbb9 Binary files /dev/null and b/src/assets/images/fechar.png differ diff --git a/src/assets/images/fifa.png b/src/assets/images/fifa.png new file mode 100644 index 000000000..74022352c Binary files /dev/null and b/src/assets/images/fifa.png differ diff --git a/src/assets/images/fundo_hogwarts.png b/src/assets/images/fundo_hogwarts.png new file mode 100644 index 000000000..50fd6eb7a Binary files /dev/null and b/src/assets/images/fundo_hogwarts.png differ diff --git a/src/assets/images/image_hogwarts.png b/src/assets/images/image_hogwarts.png new file mode 100644 index 000000000..e0b11bd88 Binary files /dev/null and b/src/assets/images/image_hogwarts.png differ diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg new file mode 100644 index 000000000..7962d3ba9 --- /dev/null +++ b/src/assets/images/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/images/play.png b/src/assets/images/play.png new file mode 100644 index 000000000..e911712c2 Binary files /dev/null and b/src/assets/images/play.png differ diff --git a/src/assets/images/resident.png b/src/assets/images/resident.png new file mode 100644 index 000000000..d22fa6aff Binary files /dev/null and b/src/assets/images/resident.png differ diff --git a/src/assets/images/star_wars.png b/src/assets/images/star_wars.png new file mode 100644 index 000000000..2578845cc Binary files /dev/null and b/src/assets/images/star_wars.png differ diff --git a/src/assets/images/streetFighter.png b/src/assets/images/streetFighter.png new file mode 100644 index 000000000..61338d72c Binary files /dev/null and b/src/assets/images/streetFighter.png differ diff --git a/src/assets/images/zelda.png b/src/assets/images/zelda.png new file mode 100644 index 000000000..c962705a0 Binary files /dev/null and b/src/assets/images/zelda.png differ diff --git a/src/assets/images/zoom.png b/src/assets/images/zoom.png new file mode 100644 index 000000000..9de1f92e5 Binary files /dev/null and b/src/assets/images/zoom.png differ diff --git a/src/components/Banner/index.tsx b/src/components/Banner/index.tsx new file mode 100644 index 000000000..ccde2e851 --- /dev/null +++ b/src/components/Banner/index.tsx @@ -0,0 +1,39 @@ +import { Tags } from '../Tags' +import { Button } from '../Button' +import { parseToBrl } from '../../utils' +import { Loader } from '../Loader' + +import { useGetFeaturedGameQuery } from '../../services/api' + +import * as S from './style' + +export const Banner = () => { + const { data: game } = useGetFeaturedGameQuery() + + if (!game) { + return + } + + return ( + +
+ Destaque do dia +
+ {game.name} + + De {parseToBrl(game?.prices.old)} +
+ por apenas {parseToBrl(game?.prices.discount)} +
+
+ +
+
+ ) +} diff --git a/src/components/Banner/style.ts b/src/components/Banner/style.ts new file mode 100644 index 000000000..90f025433 --- /dev/null +++ b/src/components/Banner/style.ts @@ -0,0 +1,51 @@ +import styled from 'styled-components' +import { TagsContainer } from '../Tags/style' + +export const Image = styled.div` + width: 100%; + height: 560px; + padding: 32px 0 56px 0; + display: block; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + position: relative; + + .container { + position: relative; + padding-top: 340px; + max-height: 100%; + display: flex; + justify-content: space-between; + align-items: flex-end; + z-index: 1; + } + + ${TagsContainer} { + position: absolute; + top: 0; + } + + &::after { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + content: ''; + } +` + +export const Title = styled.h2` + font-size: 32px; + max-width: 450px; +` + +export const Price = styled.p` + font-size: 24px; + margin-top: 24px; + span { + text-decoration: line-through; + } +` diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx new file mode 100644 index 000000000..343de2ec6 --- /dev/null +++ b/src/components/Button/index.tsx @@ -0,0 +1,38 @@ +import { ButtonContainer, ButtonLink } from './style' + +export type Props = { + type: 'button' | 'link' | 'submit' + title: string + to?: string + onClick?: () => void + children: string + variant?: 'primary' | 'secundary' +} + +export const Button = ({ + type, + title, + to, + onClick, + children, + variant = 'primary' +}: Props) => { + if (type === 'button' || type === 'submit') { + return ( + + {children} + + ) + } + + return ( + + {children} + + ) +} diff --git a/src/components/Button/style.ts b/src/components/Button/style.ts new file mode 100644 index 000000000..d4956bf9f --- /dev/null +++ b/src/components/Button/style.ts @@ -0,0 +1,27 @@ +import styled from 'styled-components' +import { colors } from '../../styles' +import { Link } from 'react-router-dom' +import { Props } from '.' + +export const ButtonContainer = styled.button` + border: 2px solid + ${(props) => (props.variant === 'primary' ? colors.green : colors.white)}; + color: ${colors.white}; + border-radius: 8px; + background: ${(props) => + props.variant === 'primary' ? colors.green : 'transparent'}; + padding: 8px 16px; + font-size: 16px; + font-weight: bold; + cursor: pointer; +` + +export const ButtonLink = styled(Link)` + border: 2px solid ${colors.white}; + color: ${colors.white}; + border-radius: 8px; + background: transparent; + padding: 8px 16px; + font-size: 16px; + font-weight: bold; +` diff --git a/src/components/Card/index.tsx b/src/components/Card/index.tsx new file mode 100644 index 000000000..ae75880d6 --- /dev/null +++ b/src/components/Card/index.tsx @@ -0,0 +1,15 @@ +import { Container } from './style' + +type Props = { + children: JSX.Element + title: string +} + +export const Card = ({ children, title }: Props) => { + return ( + +

{title}

+ {children} +
+ ) +} diff --git a/src/components/Card/style.ts b/src/components/Card/style.ts new file mode 100644 index 000000000..2622c301c --- /dev/null +++ b/src/components/Card/style.ts @@ -0,0 +1,30 @@ +import styled from 'styled-components' +import { colors } from '../../styles' + +export const Container = styled.div` + border-radius: 8px; + background-color: ${colors.gray}; + padding: 24px; + margin-bottom: 40px; + + h2, + h3 { + font-size: 18px; + font-weight: 700; + color: ${colors.white}; + margin-bottom: 24px; + } + + h3 { + margin-top: 24px; + } + + p { + font-size: 14px; + line-height: 22px; + } + + .margin-top { + margin-top: 16px; + } +` diff --git a/src/components/Cart/index.tsx b/src/components/Cart/index.tsx new file mode 100644 index 000000000..5acefb6cb --- /dev/null +++ b/src/components/Cart/index.tsx @@ -0,0 +1,63 @@ +import { useDispatch, useSelector } from 'react-redux' +import { useNavigate } from 'react-router-dom' + +import { Tags } from '../Tags' +import { Button } from '../Button' +import { getTotalPrice, parseToBrl } from '../../utils' + +import { RootReducer } from '../../store' +import { close, remove } from '../../store/reducers/cart' + +import * as S from './style' + +export const Cart = () => { + const { isOpen, items } = useSelector((state: RootReducer) => state.cart) + const navigate = useNavigate() + + const dispatch = useDispatch() + + const closeCart = () => { + dispatch(close()) + } + + const removeItem = (id: number) => { + dispatch(remove(id)) + } + + const goToCheckout = () => { + navigate('/checkout') + closeCart() + } + + return ( + + + +
    + {items.map((item) => ( + + +
    +

    {item.name}

    + {item.details.category} + {item.details.system} +

    {parseToBrl(item.prices.current)}

    +
    +
+
+ {items.length} jogo(s) no carrinho + + Total de {parseToBrl(getTotalPrice(items))} + em até 6x sem juros + +
+ +
+
+ ) +} diff --git a/src/components/Cart/style.ts b/src/components/Cart/style.ts new file mode 100644 index 000000000..40e0fb16b --- /dev/null +++ b/src/components/Cart/style.ts @@ -0,0 +1,87 @@ +import styled from 'styled-components' +import { colors } from '../../styles' +import { ButtonContainer } from '../Button/style' +import { TagsContainer } from '../Tags/style' + +import fechar from '../../assets/images/fechar.png' + +export const Overlay = styled.div` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #000; + opacity: 0.7; +` + +export const CartContainer = styled.div` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1; + display: none; + justify-content: end; + + &.isOpen { + display: flex; + } +` + +export const Sidebar = styled.aside` + padding: 40px 16px; + background-color: ${colors.gray}; + height: 100%; + width: 360px; + z-index: 1; + + ${ButtonContainer} { + width: 100%; + margin-top: 24px; + } +` + +export const CartItem = styled.li` + display: flex; + border-bottom: 1px solid ${colors.lightgray}; + padding: 8px 0; + position: relative; + + img { + height: 80px; + width: 80px; + margin-right: 23px; + object-fit: cover; + } + + ${TagsContainer} { + margin: 8px 8px 16px 0; + } + + button { + background-image: url(${fechar}); + width: 16px; + height: 16px; + border: none; + background-color: transparent; + cursor: pointer; + position: absolute; + top: 8px; + right: 0; + } +` +export const Quantity = styled.p` + margin: 32px 0 16px 0; + font-size: 16px; +` + +export const Prices = styled.p` + font-size: 14px; + span { + display: block; + font-size: 12px; + color: ${colors.lightgray}; + } +` diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx new file mode 100644 index 000000000..7c638622e --- /dev/null +++ b/src/components/Footer/index.tsx @@ -0,0 +1,77 @@ +import * as S from './style' + +const current = new Date().getFullYear() + +export const Footer = () => ( + +
+ + Categorias + +
  • + + RPG + +
  • +
  • + + Ação + +
  • +
  • + + Esportes + +
  • +
  • + + Simulação + +
  • +
  • + + Luta + +
  • +
    +
    + + Acesso rápido + +
  • + + Promoções + +
  • +
  • + + Em breve + +
  • +
    +
    +

    {current} - © E-PLAY Todos os direitos reservados

    +
    +
    +) diff --git a/src/components/Footer/style.ts b/src/components/Footer/style.ts new file mode 100644 index 000000000..4d704fa0e --- /dev/null +++ b/src/components/Footer/style.ts @@ -0,0 +1,30 @@ +import styled from 'styled-components' +import { colors } from '../../styles' +import { HashLink } from 'react-router-hash-link' + +export const ContainerFooter = styled.footer` + background-color: ${colors.gray}; + font-size: 14px; + padding-bottom: 32px; + margin-top: 40px; +` + +export const SectionFooter = styled.section` + margin-bottom: 64px; +` + +export const Title = styled.h4` + font-size: 16px; + font-weight: bold; + margin-bottom: 16px; +` + +export const Links = styled.ul` + display: flex; + flex-wrap: wrap; +` + +export const Link = styled(HashLink)` + color: ${colors.lightgray}; + margin-right: 8px; +` diff --git a/src/components/Gallery/index.tsx b/src/components/Gallery/index.tsx new file mode 100644 index 000000000..a11215493 --- /dev/null +++ b/src/components/Gallery/index.tsx @@ -0,0 +1,91 @@ +import { useState } from 'react' + +import { Section } from '../Section' + +import { GalleryItem } from '../../pages/Home' + +import zoom from '../../assets/images/zoom.png' +import play from '../../assets/images/play.png' +import closeIcon from '../../assets/images/fechar.png' + +import * as S from './style' + +type Props = { + defaultCover: string + nome: string + items: GalleryItem[] +} + +interface ModalState extends GalleryItem { + isVisible: boolean +} + +export const Gallery = ({ defaultCover, nome, items }: Props) => { + const [modal, setModal] = useState({ + isVisible: false, + type: 'image', + url: '' + }) + + const getMediaCover = (item: GalleryItem) => { + if (item.type === 'image') return item.url + return defaultCover + } + const getMediaIcon = (item: GalleryItem) => { + if (item.type === 'image') return zoom + return play + } + + const closeModal = () => { + setModal({ + isVisible: false, + type: 'image', + url: '' + }) + } + + return ( + <> +
    + + {items.map((media, index) => ( + { + setModal({ + isVisible: true, + type: media.type, + url: media.url + }) + }} + > + {`Midia + + {nome} + + + ))} + +
    + closeModal()} + > + +
    +

    {nome}

    + Botao de fechar +
    + {modal.type === 'image' ? ( + + ) : ( +