diff --git a/package-lock.json b/package-lock.json
index 659badc..e249977 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,43 @@
"@jridgewell/trace-mapping": "^0.3.9"
}
},
+ "@ant-design/colors": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
+ "integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
+ "requires": {
+ "@ctrl/tinycolor": "^3.4.0"
+ }
+ },
+ "@ant-design/icons": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.7.0.tgz",
+ "integrity": "sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g==",
+ "requires": {
+ "@ant-design/colors": "^6.0.0",
+ "@ant-design/icons-svg": "^4.2.1",
+ "@babel/runtime": "^7.11.2",
+ "classnames": "^2.2.6",
+ "rc-util": "^5.9.4"
+ }
+ },
+ "@ant-design/icons-svg": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz",
+ "integrity": "sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw=="
+ },
+ "@ant-design/react-slick": {
+ "version": "0.29.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.29.2.tgz",
+ "integrity": "sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA==",
+ "requires": {
+ "@babel/runtime": "^7.10.4",
+ "classnames": "^2.2.5",
+ "json2mq": "^0.2.0",
+ "lodash": "^4.17.21",
+ "resize-observer-polyfill": "^1.5.1"
+ }
+ },
"@apideck/better-ajv-errors": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz",
@@ -1382,6 +1419,11 @@
"resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz",
"integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg=="
},
+ "@ctrl/tinycolor": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
+ "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
+ },
"@eslint/eslintrc": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz",
@@ -2071,6 +2113,11 @@
"reselect": "^4.1.5"
}
},
+ "@remix-run/router": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz",
+ "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ=="
+ },
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -3172,6 +3219,57 @@
"color-convert": "^1.9.0"
}
},
+ "antd": {
+ "version": "4.23.4",
+ "resolved": "https://registry.npmjs.org/antd/-/antd-4.23.4.tgz",
+ "integrity": "sha512-2VdDSPXEjCc2m2qBgv6DKpKnsKIGyQtJBdcGn223EqHxDWHqCaRxeJIA9bcW50ntHFkwdeBa+IeWLBor377dkA==",
+ "requires": {
+ "@ant-design/colors": "^6.0.0",
+ "@ant-design/icons": "^4.7.0",
+ "@ant-design/react-slick": "~0.29.1",
+ "@babel/runtime": "^7.18.3",
+ "@ctrl/tinycolor": "^3.4.0",
+ "classnames": "^2.2.6",
+ "copy-to-clipboard": "^3.2.0",
+ "lodash": "^4.17.21",
+ "memoize-one": "^6.0.0",
+ "moment": "^2.29.2",
+ "rc-cascader": "~3.7.0",
+ "rc-checkbox": "~2.3.0",
+ "rc-collapse": "~3.3.0",
+ "rc-dialog": "~8.9.0",
+ "rc-drawer": "~5.1.0",
+ "rc-dropdown": "~4.0.0",
+ "rc-field-form": "~1.27.0",
+ "rc-image": "~5.7.0",
+ "rc-input": "~0.1.2",
+ "rc-input-number": "~7.3.9",
+ "rc-mentions": "~1.9.1",
+ "rc-menu": "~9.6.3",
+ "rc-motion": "^2.6.1",
+ "rc-notification": "~4.6.0",
+ "rc-pagination": "~3.1.17",
+ "rc-picker": "~2.6.10",
+ "rc-progress": "~3.3.2",
+ "rc-rate": "~2.9.0",
+ "rc-resize-observer": "^1.2.0",
+ "rc-segmented": "~2.1.0",
+ "rc-select": "~14.1.13",
+ "rc-slider": "~10.0.0",
+ "rc-steps": "~4.1.0",
+ "rc-switch": "~3.2.0",
+ "rc-table": "~7.26.0",
+ "rc-tabs": "~12.1.0-alpha.1",
+ "rc-textarea": "~0.3.0",
+ "rc-tooltip": "~5.2.0",
+ "rc-tree": "~5.7.0",
+ "rc-tree-select": "~5.5.0",
+ "rc-trigger": "^5.2.10",
+ "rc-upload": "~4.3.0",
+ "rc-util": "^5.22.5",
+ "scroll-into-view-if-needed": "^2.2.25"
+ }
+ },
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
@@ -3220,6 +3318,11 @@
"is-string": "^1.0.7"
}
},
+ "array-tree-filter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
+ "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw=="
+ },
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -3274,6 +3377,11 @@
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
},
+ "async-validator": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+ "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
+ },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -3302,6 +3410,28 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz",
"integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w=="
},
+ "axios": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.1.2.tgz",
+ "integrity": "sha512-bznQyETwElsXl2RK7HLLwb5GPpOLlycxHCtrpDR/4RqqBzjARaOTo3jz4IgtntWUYee7Ne4S8UHd92VCuzPaWA==",
+ "requires": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ },
+ "dependencies": {
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ }
+ }
+ },
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -3794,6 +3924,11 @@
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz",
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
},
+ "classnames": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
+ "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
+ },
"clean-css": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz",
@@ -3927,6 +4062,11 @@
}
}
},
+ "compute-scroll-into-view": {
+ "version": "1.0.17",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz",
+ "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg=="
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -3980,6 +4120,14 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
+ "copy-to-clipboard": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz",
+ "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==",
+ "requires": {
+ "toggle-selection": "^1.0.6"
+ }
+ },
"core-js": {
"version": "3.25.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.5.tgz",
@@ -4298,6 +4446,16 @@
"whatwg-url": "^8.0.0"
}
},
+ "date-fns": {
+ "version": "2.29.3",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
+ "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA=="
+ },
+ "dayjs": {
+ "version": "1.11.5",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz",
+ "integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA=="
+ },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -4461,6 +4619,11 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz",
"integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg=="
},
+ "dom-align": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.3.tgz",
+ "integrity": "sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA=="
+ },
"dom-converter": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
@@ -7957,6 +8120,14 @@
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
},
+ "json2mq": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
+ "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==",
+ "requires": {
+ "string-convert": "^0.2.0"
+ }
+ },
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -8175,6 +8346,11 @@
"fs-monkey": "^1.0.3"
}
},
+ "memoize-one": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
+ },
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -8303,6 +8479,11 @@
"minimist": "^1.2.6"
}
},
+ "moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -9551,6 +9732,11 @@
}
}
},
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -9628,6 +9814,411 @@
}
}
},
+ "rc-align": {
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.12.tgz",
+ "integrity": "sha512-3DuwSJp8iC/dgHzwreOQl52soj40LchlfUHtgACOUtwGuoFIOVh6n/sCpfqCU8kO5+iz6qR0YKvjgB8iPdE3aQ==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "dom-align": "^1.7.0",
+ "lodash": "^4.17.21",
+ "rc-util": "^5.3.0",
+ "resize-observer-polyfill": "^1.5.1"
+ }
+ },
+ "rc-cascader": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.7.0.tgz",
+ "integrity": "sha512-SFtGpwmYN7RaWEAGTS4Rkc62ZV/qmQGg/tajr/7mfIkleuu8ro9Hlk6J+aA0x1YS4zlaZBtTcSaXM01QMiEV/A==",
+ "requires": {
+ "@babel/runtime": "^7.12.5",
+ "array-tree-filter": "^2.1.0",
+ "classnames": "^2.3.1",
+ "rc-select": "~14.1.0",
+ "rc-tree": "~5.7.0",
+ "rc-util": "^5.6.1"
+ }
+ },
+ "rc-checkbox": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz",
+ "integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1"
+ }
+ },
+ "rc-collapse": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.3.1.tgz",
+ "integrity": "sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.3.4",
+ "rc-util": "^5.2.1",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-dialog": {
+ "version": "8.9.0",
+ "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.9.0.tgz",
+ "integrity": "sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.6",
+ "rc-motion": "^2.3.0",
+ "rc-util": "^5.21.0"
+ }
+ },
+ "rc-drawer": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-5.1.0.tgz",
+ "integrity": "sha512-pU3Tsn99pxGdYowXehzZbdDVE+4lDXSGb7p8vA9mSmr569oc2Izh4Zw5vLKSe/Xxn2p5MSNbLVqD4tz+pK6SOw==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.6",
+ "rc-motion": "^2.6.1",
+ "rc-util": "^5.21.2"
+ }
+ },
+ "rc-dropdown": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.0.1.tgz",
+ "integrity": "sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==",
+ "requires": {
+ "@babel/runtime": "^7.18.3",
+ "classnames": "^2.2.6",
+ "rc-trigger": "^5.3.1",
+ "rc-util": "^5.17.0"
+ }
+ },
+ "rc-field-form": {
+ "version": "1.27.2",
+ "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.27.2.tgz",
+ "integrity": "sha512-NaTjkSB8JsHRgm52wkDorsDzFf2HH6GmCQ2AqkwO8zo+zIqybw8K1lkzDBMDJI8nw1pFuD46U5QsYZv4blYvdw==",
+ "requires": {
+ "@babel/runtime": "^7.18.0",
+ "async-validator": "^4.1.0",
+ "rc-util": "^5.8.0"
+ }
+ },
+ "rc-image": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.7.1.tgz",
+ "integrity": "sha512-QyMfdhoUfb5W14plqXSisaYwpdstcLYnB0MjX5ccIK2rydQM9sDPuekQWu500DDGR2dBaIF5vx9XbWkNFK17Fg==",
+ "requires": {
+ "@babel/runtime": "^7.11.2",
+ "classnames": "^2.2.6",
+ "rc-dialog": "~8.9.0",
+ "rc-util": "^5.0.6"
+ }
+ },
+ "rc-input": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.1.2.tgz",
+ "integrity": "sha512-ZPmwcFspgfYpUfbSx3KnLk9gImBcLOrlQCr4oTJ4jBoIXgJLTfm26yelzRgBJewhkvD8uJbgX0sQ/yOzuOHnJg==",
+ "requires": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.18.1"
+ }
+ },
+ "rc-input-number": {
+ "version": "7.3.9",
+ "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.9.tgz",
+ "integrity": "sha512-u0+miS+SATdb6DtssYei2JJ1WuZME+nXaG6XGtR8maNyW5uGDytfDu60OTWLQEb0Anv/AcCzehldV8CKmKyQfA==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.23.0"
+ }
+ },
+ "rc-mentions": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.9.2.tgz",
+ "integrity": "sha512-uxb/lzNnEGmvraKWNGE6KXMVXvt8RQv9XW8R0Dqi3hYsyPiAZeHRCHQKdLARuk5YBhFhZ6ga55D/8XuY367g3g==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.6",
+ "rc-menu": "~9.6.0",
+ "rc-textarea": "^0.3.0",
+ "rc-trigger": "^5.0.4",
+ "rc-util": "^5.22.5"
+ }
+ },
+ "rc-menu": {
+ "version": "9.6.4",
+ "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.6.4.tgz",
+ "integrity": "sha512-6DiNAjxjVIPLZXHffXxxcyE15d4isRL7iQ1ru4MqYDH2Cqc5bW96wZOdMydFtGLyDdnmEQ9jVvdCE9yliGvzkw==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.4.3",
+ "rc-overflow": "^1.2.0",
+ "rc-trigger": "^5.1.2",
+ "rc-util": "^5.12.0",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-motion": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.6.2.tgz",
+ "integrity": "sha512-4w1FaX3dtV749P8GwfS4fYnFG4Rb9pxvCYPc/b2fw1cmlHJWNNgOFIz7ysiD+eOrzJSvnLJWlNQQncpNMXwwpg==",
+ "requires": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.21.0"
+ }
+ },
+ "rc-notification": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.6.0.tgz",
+ "integrity": "sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.2.0",
+ "rc-util": "^5.20.1"
+ }
+ },
+ "rc-overflow": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.8.tgz",
+ "integrity": "sha512-QJ0UItckWPQ37ZL1dMEBAdY1dhfTXFL9k6oTTcyydVwoUNMnMqCGqnRNA98axSr/OeDKqR6DVFyi8eA5RQI/uQ==",
+ "requires": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.19.2"
+ }
+ },
+ "rc-pagination": {
+ "version": "3.1.17",
+ "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.17.tgz",
+ "integrity": "sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1"
+ }
+ },
+ "rc-picker": {
+ "version": "2.6.10",
+ "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.10.tgz",
+ "integrity": "sha512-9wYtw0DFWs9FO92Qh2D76P0iojUr8ZhLOtScUeOit6ks/F+TBLrOC1uze3IOu+u9gbDAjmosNWLKbBzx/Yuv2w==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1",
+ "date-fns": "2.x",
+ "dayjs": "1.x",
+ "moment": "^2.24.0",
+ "rc-trigger": "^5.0.4",
+ "rc-util": "^5.4.0",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-progress": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz",
+ "integrity": "sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.6",
+ "rc-util": "^5.16.1"
+ }
+ },
+ "rc-rate": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.2.tgz",
+ "integrity": "sha512-SaiZFyN8pe0Fgphv8t3+kidlej+cq/EALkAJAc3A0w0XcPaH2L1aggM8bhe1u6GAGuQNAoFvTLjw4qLPGRKV5g==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.0.1"
+ }
+ },
+ "rc-resize-observer": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz",
+ "integrity": "sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.15.0",
+ "resize-observer-polyfill": "^1.5.1"
+ }
+ },
+ "rc-segmented": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.1.0.tgz",
+ "integrity": "sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==",
+ "requires": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-motion": "^2.4.4",
+ "rc-util": "^5.17.0"
+ }
+ },
+ "rc-select": {
+ "version": "14.1.13",
+ "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.1.13.tgz",
+ "integrity": "sha512-WMEsC3gTwA1dbzWOdVIXDmWyidYNLq68AwvvUlRROw790uGUly0/vmqDozXrIr0QvN/A3CEULx12o+WtLCAefg==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.0.1",
+ "rc-overflow": "^1.0.0",
+ "rc-trigger": "^5.0.4",
+ "rc-util": "^5.16.1",
+ "rc-virtual-list": "^3.2.0"
+ }
+ },
+ "rc-slider": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.0.1.tgz",
+ "integrity": "sha512-igTKF3zBet7oS/3yNiIlmU8KnZ45npmrmHlUUio8PNbIhzMcsh+oE/r2UD42Y6YD2D/s+kzCQkzQrPD6RY435Q==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.18.1",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-steps": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.4.tgz",
+ "integrity": "sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w==",
+ "requires": {
+ "@babel/runtime": "^7.10.2",
+ "classnames": "^2.2.3",
+ "rc-util": "^5.0.1"
+ }
+ },
+ "rc-switch": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz",
+ "integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1",
+ "rc-util": "^5.0.1"
+ }
+ },
+ "rc-table": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.26.0.tgz",
+ "integrity": "sha512-0cD8e6S+DTGAt5nBZQIPFYEaIukn17sfa5uFL98faHlH/whZzD8ii3dbFL4wmUDEL4BLybhYop+QUfZJ4CPvNQ==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.5",
+ "rc-resize-observer": "^1.1.0",
+ "rc-util": "^5.22.5",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-tabs": {
+ "version": "12.1.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-12.1.0-alpha.1.tgz",
+ "integrity": "sha512-M+B88WEnGSuE+mR54fpgPbZLAakzxa/H6FmEetLBl5WG4I3AcwSk9amuIPC/tu0KXBl+H6Bg5ZwrrEUOBUvgzg==",
+ "requires": {
+ "@babel/runtime": "^7.11.2",
+ "classnames": "2.x",
+ "rc-dropdown": "~4.0.0",
+ "rc-menu": "~9.6.0",
+ "rc-motion": "^2.6.2",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.5.0"
+ }
+ },
+ "rc-textarea": {
+ "version": "0.3.7",
+ "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.7.tgz",
+ "integrity": "sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "^2.2.1",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.7.0",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-tooltip": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.2.2.tgz",
+ "integrity": "sha512-jtQzU/18S6EI3lhSGoDYhPqNpWajMtS5VV/ld1LwyfrDByQpYmw/LW6U7oFXXLukjfDHQ7Ju705A82PRNFWYhg==",
+ "requires": {
+ "@babel/runtime": "^7.11.2",
+ "classnames": "^2.3.1",
+ "rc-trigger": "^5.0.0"
+ }
+ },
+ "rc-tree": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.7.0.tgz",
+ "integrity": "sha512-F+Ewkv/UcutshnVBMISP+lPdHDlcsL+YH/MQDVWbk+QdkfID7vXiwrHMEZn31+2Rbbm21z/HPceGS8PXGMmnQg==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-motion": "^2.0.1",
+ "rc-util": "^5.16.1",
+ "rc-virtual-list": "^3.4.8"
+ }
+ },
+ "rc-tree-select": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.5.0.tgz",
+ "integrity": "sha512-XS0Jvw4OjFz/Xvb2byEkBWv55JFKFz0HVvTBa/cPOHJaQh/3EaYwymEMnCCvGEzS1+5CfDVwMtA8j/v4rt1DHw==",
+ "requires": {
+ "@babel/runtime": "^7.10.1",
+ "classnames": "2.x",
+ "rc-select": "~14.1.0",
+ "rc-tree": "~5.7.0",
+ "rc-util": "^5.16.1"
+ }
+ },
+ "rc-trigger": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.1.tgz",
+ "integrity": "sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ==",
+ "requires": {
+ "@babel/runtime": "^7.18.3",
+ "classnames": "^2.2.6",
+ "rc-align": "^4.0.0",
+ "rc-motion": "^2.0.0",
+ "rc-util": "^5.19.2"
+ }
+ },
+ "rc-upload": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.4.tgz",
+ "integrity": "sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ==",
+ "requires": {
+ "@babel/runtime": "^7.18.3",
+ "classnames": "^2.2.5",
+ "rc-util": "^5.2.0"
+ }
+ },
+ "rc-util": {
+ "version": "5.24.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.24.4.tgz",
+ "integrity": "sha512-2a4RQnycV9eV7lVZPEJ7QwJRPlZNc06J7CwcwZo4vIHr3PfUqtYgl1EkUV9ETAc6VRRi8XZOMFhYG63whlIC9Q==",
+ "requires": {
+ "@babel/runtime": "^7.18.3",
+ "react-is": "^16.12.0",
+ "shallowequal": "^1.1.0"
+ }
+ },
+ "rc-virtual-list": {
+ "version": "3.4.8",
+ "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.8.tgz",
+ "integrity": "sha512-qSN+Rv4i/E7RCTvTMr1uZo7f3crJJg/5DekoCagydo9zsXrxj07zsFSxqizqW+ldGA16lwa8So/bIbV9Ofjddg==",
+ "requires": {
+ "classnames": "^2.2.6",
+ "rc-resize-observer": "^1.0.0",
+ "rc-util": "^5.15.0"
+ }
+ },
"react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
@@ -9779,6 +10370,23 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
},
+ "react-router": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz",
+ "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==",
+ "requires": {
+ "@remix-run/router": "1.0.2"
+ }
+ },
+ "react-router-dom": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.2.tgz",
+ "integrity": "sha512-yM1kjoTkpfjgczPrcyWrp+OuQMyB1WleICiiGfstnQYo/S8hPEEnVjr/RdmlH6yKK4Tnj1UGXFSa7uwAtmDoLQ==",
+ "requires": {
+ "@remix-run/router": "1.0.2",
+ "react-router": "6.4.2"
+ }
+ },
"react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -10068,6 +10676,11 @@
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz",
"integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ=="
},
+ "resize-observer-polyfill": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
+ },
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -10279,6 +10892,14 @@
"ajv-keywords": "^3.5.2"
}
},
+ "scroll-into-view-if-needed": {
+ "version": "2.2.29",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz",
+ "integrity": "sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==",
+ "requires": {
+ "compute-scroll-into-view": "^1.0.17"
+ }
+ },
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -10426,6 +11047,11 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
+ "shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -10595,6 +11221,11 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
},
+ "string-convert": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
+ "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A=="
+ },
"string-length": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -10942,6 +11573,11 @@
"is-number": "^7.0.0"
}
},
+ "toggle-selection": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+ },
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
diff --git a/package.json b/package.json
index 022cd16..4e29e8c 100644
--- a/package.json
+++ b/package.json
@@ -11,9 +11,12 @@
"@types/node": "^17.0.45",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
+ "antd": "^4.23.4",
+ "axios": "^1.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.4",
+ "react-router-dom": "^6.4.2",
"react-scripts": "5.0.1",
"typescript": "^4.8.4",
"web-vitals": "^2.1.4"
diff --git a/public/cover.png b/public/cover.png
new file mode 100644
index 0000000..085102a
Binary files /dev/null and b/public/cover.png differ
diff --git a/public/index.html b/public/index.html
index 1dbdca6..bc133c4 100644
--- a/public/index.html
+++ b/public/index.html
@@ -24,6 +24,9 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
+
+
+
React Redux App
diff --git a/public/logo.svg b/public/logo.svg
new file mode 100644
index 0000000..8ee6eb7
--- /dev/null
+++ b/public/logo.svg
@@ -0,0 +1,22 @@
+
diff --git a/public/logout.svg b/public/logout.svg
new file mode 100644
index 0000000..7b14930
--- /dev/null
+++ b/public/logout.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/rub.svg b/public/rub.svg
new file mode 100644
index 0000000..419af90
--- /dev/null
+++ b/public/rub.svg
@@ -0,0 +1,10 @@
+
diff --git a/src/App.css b/src/App.css
index 01cc586..e69de29 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,39 +0,0 @@
-.App {
- text-align: center;
-}
-
-.App-logo {
- height: 40vmin;
- pointer-events: none;
-}
-
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-float infinite 3s ease-in-out;
- }
-}
-
-.App-header {
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
-}
-
-.App-link {
- color: rgb(112, 76, 182);
-}
-
-@keyframes App-logo-float {
- 0% {
- transform: translateY(0);
- }
- 50% {
- transform: translateY(10px);
- }
- 100% {
- transform: translateY(0px);
- }
-}
diff --git a/src/App.test.tsx b/src/App.test.tsx
deleted file mode 100644
index 659cc13..0000000
--- a/src/App.test.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react';
-import { render } from '@testing-library/react';
-import { Provider } from 'react-redux';
-import { store } from './app/store';
-import App from './App';
-
-test('renders learn react link', () => {
- const { getByText } = render(
-
-
-
- );
-
- expect(getByText(/learn/i)).toBeInTheDocument();
-});
diff --git a/src/App.tsx b/src/App.tsx
index e8da502..26364c5 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,57 +1,45 @@
import React from 'react';
-import logo from './logo.svg';
-import { Counter } from './features/counter/Counter';
import './App.css';
+import { Provider } from 'react-redux';
+import { adminStore} from './app/adminStore';
+import {
+ BrowserRouter as Router,
+ Route,
+ Routes,
+ Link,
+ createBrowserRouter,
+ createRoutesFromElements
+} from "react-router-dom";
+import { AdminPage } from './admin';
+import { AdminMarket } from './admin/adminMarket';
+import { AdminMarketPopUp } from './admin/adminMarketPopUp';
+import { AddAdminMarketProduct } from './admin/addAdminMarketCard';
function App() {
+
return (
-
+
+
+
+ {/* A
looks through its children s and
+ renders the first one that matches the current URL. */}
+
+
);
}
diff --git a/src/admin/addAdminMarketCard/addAdminMarket.css b/src/admin/addAdminMarketCard/addAdminMarket.css
new file mode 100644
index 0000000..8b2c69b
--- /dev/null
+++ b/src/admin/addAdminMarketCard/addAdminMarket.css
@@ -0,0 +1,112 @@
+.addProduct{
+ padding-top: 200px;
+ width: 100%;
+ height: 100vh;
+ background: linear-gradient(85.91deg, #096DD9 0%, #40A9FF 100%);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.addProductCard{
+ background: #FAFAFA;
+ border-radius: 16px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 32px 64px;
+ gap: 36px;
+ width: 75%;
+ font-family: 'Roboto', sans-serif;
+ font-style: normal;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 22px;
+ /* identical to box height, or 157% */
+
+ text-align: right;
+
+ /* Character/Title .85 */
+
+ color: rgba(0, 0, 0, 0.85);
+}
+
+.addProductH1{
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 500;
+ font-size: 24px;
+ line-height: 32px;
+ color: rgba(0, 0, 0, 0.85)
+}
+
+.addBodyWrapper{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 50px
+}
+
+.InpWrapper{
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ gap: 25px;
+ width: 100%;
+}
+.fieldsWrapper{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 20px
+}
+
+.btn1{
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 5px 36px;
+ filter: drop-shadow(0px 2px 0px rgba(0, 0, 0, 0.016));
+ border-radius: 16px;
+ border: 1px solid #1890FF;
+ font-style: normal;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 24px;
+ /* identical to box height, or 150% */
+
+ text-align: center;
+}
+
+.btn2{
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 5px 36px;
+ filter: drop-shadow(0px 2px 0px rgba(0, 0, 0, 0.016));
+ border-radius: 16px;
+ background: #1890FF;
+ border: 1px solid #1890FF;
+ font-style: normal;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 24px;
+ /* identical to box height, or 150% */
+
+ text-align: center;
+
+ /* Character / Primary(inverse) */
+
+ color: #FFFFFF;
+}
+
+.addBtnWrapper{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap:25px
+}
\ No newline at end of file
diff --git a/src/admin/addAdminMarketCard/index.tsx b/src/admin/addAdminMarketCard/index.tsx
new file mode 100644
index 0000000..7814332
--- /dev/null
+++ b/src/admin/addAdminMarketCard/index.tsx
@@ -0,0 +1,93 @@
+import "./addAdminMarket.css"
+import React, { useState } from "react"
+import { useNavigate, useParams } from "react-router-dom"
+import { useAppDispatch, useAppSelector } from "../../app/hooks"
+import { RootAdminState } from "../../app/adminStore"
+import { fetchAddProduct, fetchChangeProduct, getProductByID, getUser } from "../../app/admin/adminSlice"
+import { Button, Input } from "antd"
+import { ProductIE } from "../../app/interfaces"
+import { FileUploader } from "../../components/fileUploader"
+import { Header } from "../../components/Header"
+import { PrevMarketCard } from "../../components/prevMarketCard"
+
+export const AddAdminMarketProduct:React.FC = () =>{
+ const [name, setName] = useState("")
+ const [descr, setDescr] = useState("")
+ const [cost, setCost] = useState(0)
+ const [file, setFile] = useState() as any
+ let user = useAppSelector((state:RootAdminState)=>getUser(state))
+
+ let dispatch = useAppDispatch()
+ let navigate = useNavigate()
+ const onDiscard = () =>{
+ setName("")
+ setCost(0)
+ setDescr("")
+ }
+
+ const onAcceept = () =>{
+ fetchAddProduct(dispatch, {image: file, name:name, cost:cost, descr:descr})
+ alert("Успешно создан товар:" + name)
+ navigate("/admin/market")
+ }
+ const { TextArea } = Input;
+
+ return(
+
+
+
+
Создать новый продукт (NFT сертификат)
+
+
+
+
+
+
Название
+
setName(e.target.value)} placeholder="Название товара">
+
+
+
+
Стоимость
+
setCost(Number(e.target.value))} placeholder="100">
+
+
+
Изображение
+
+ setFile(file)}>
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/admin/adminMarket/adminMarket.css b/src/admin/adminMarket/adminMarket.css
new file mode 100644
index 0000000..c77cb92
--- /dev/null
+++ b/src/admin/adminMarket/adminMarket.css
@@ -0,0 +1,34 @@
+.marketCard{
+ background: #FAFAFA;
+ border-radius: 16px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 32px 64px;
+ gap: 36px;
+ width: 75%;
+ font-family: 'Roboto', sans-serif;
+ font-style: normal;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 22px;
+ text-align: right;
+ color: rgba(0, 0, 0, 0.85);
+}
+.market{
+ padding-top: 200px;
+ width: 100%;
+ height: 100vh;
+ background: linear-gradient(85.91deg, #096DD9 0%, #40A9FF 100%);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.productWrapper{
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ gap:50px
+}
\ No newline at end of file
diff --git a/src/admin/adminMarket/index.tsx b/src/admin/adminMarket/index.tsx
new file mode 100644
index 0000000..2ee3138
--- /dev/null
+++ b/src/admin/adminMarket/index.tsx
@@ -0,0 +1,56 @@
+import React, { useState } from "react"
+import { getProducts, getUser } from "../../app/admin/adminSlice";
+import { RootAdminState } from "../../app/adminStore";
+import { useAppSelector } from "../../app/hooks";
+import { Header } from "../../components/Header";
+import { AdminMarketCard } from "../adminMarketCard";
+import "./adminMarket.css"
+import {
+ BrowserRouter as Router,
+ Route,
+ Routes,
+ Link
+ } from "react-router-dom";
+import { AdminMarketPopUp } from "../adminMarketPopUp";
+
+export const AdminMarket:React.FC = () =>{
+ const [opened, setOpened] = useState(false);
+ let user = useAppSelector((state:RootAdminState)=>getUser(state))
+ let cards: JSX.Element[] = []
+ let products = useAppSelector(
+ (state: RootAdminState)=>getProducts(state)).forEach(
+ product=>cards.push())
+
+ return(
+
+
+
+
Market Place товаров и услуг
+
+ {cards}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/admin/adminMarketCard/adminMarketCard.css b/src/admin/adminMarketCard/adminMarketCard.css
new file mode 100644
index 0000000..007207b
--- /dev/null
+++ b/src/admin/adminMarketCard/adminMarketCard.css
@@ -0,0 +1,50 @@
+.adminCard{
+ width: 240px;
+ max-height: 400px;
+ display: flex;
+ flex-direction: column;
+ background: #FFFFFF;
+ border-radius: 16px;
+ border: 1px solid #1890FF;
+
+}
+
+.adminImg{
+ height: 50%;
+ border-radius: 16px 16px 0px 0px;
+}
+
+.adminCardWrapper{
+ padding: 15px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items:flex-start;
+ gap: 15px;
+ text-align: left;
+}
+
+.adminCost{
+ border: 1px solid #1890FF;
+ border-radius: 16px;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 5px 16px;
+ gap:10px;
+}
+.adminCardH2{
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ color: rgba(0, 0, 0, 0.85)
+}
+
+.adminCardDescr{
+ font-size: 14px;
+ line-height: 22px;
+ color: rgba(0, 0, 0, 0.45);
+ max-width: 210px;
+ overflow-x:hidden
+}
\ No newline at end of file
diff --git a/src/admin/adminMarketCard/index.tsx b/src/admin/adminMarketCard/index.tsx
new file mode 100644
index 0000000..8c3fe7b
--- /dev/null
+++ b/src/admin/adminMarketCard/index.tsx
@@ -0,0 +1,28 @@
+import { Button } from "antd";
+import React, { useState } from "react"
+import { useNavigate, useParams } from "react-router-dom";
+import { fetchDelProduct, getProductByID } from "../../app/admin/adminSlice";
+import { RootAdminState } from "../../app/adminStore";
+import { useAppDispatch, useAppSelector } from "../../app/hooks";
+import { ProductIE } from "../../app/interfaces";
+import "./adminMarketCard.css"
+
+
+export const AdminMarketCard:React.FC = (props) =>{
+ let dispatch = useAppDispatch()
+ let navigate = useNavigate()
+
+ return(
+
+
+
+
+
{props.cost}
+
+
{props.name}
+
{props.description}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/admin/adminMarketPopUp/adminMarketPopUp.css b/src/admin/adminMarketPopUp/adminMarketPopUp.css
new file mode 100644
index 0000000..8ab03ed
--- /dev/null
+++ b/src/admin/adminMarketPopUp/adminMarketPopUp.css
@@ -0,0 +1,112 @@
+.changeProduct{
+ padding-top: 200px;
+ width: 100%;
+ height: 100vh;
+ background: linear-gradient(85.91deg, #096DD9 0%, #40A9FF 100%);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.changeProductCard{
+ background: #FAFAFA;
+ border-radius: 16px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 32px 64px;
+ gap: 36px;
+ width: 75%;
+ font-family: 'Roboto', sans-serif;
+ font-style: normal;
+ font-weight: 400;
+ font-size: 14px;
+ line-height: 22px;
+ /* identical to box height, or 157% */
+
+ text-align: right;
+
+ /* Character/Title .85 */
+
+ color: rgba(0, 0, 0, 0.85);
+}
+
+.addProductH1{
+ font-family: 'Roboto';
+ font-style: normal;
+ font-weight: 500;
+ font-size: 24px;
+ line-height: 32px;
+ color: rgba(0, 0, 0, 0.85)
+}
+
+.addBodyWrapper{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 50px
+}
+
+.InpWrapper{
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ gap: 25px;
+ width: 100%;
+}
+.fieldsWrapper{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 20px
+}
+
+.btn1{
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 5px 36px;
+ filter: drop-shadow(0px 2px 0px rgba(0, 0, 0, 0.016));
+ border-radius: 16px;
+ border: 1px solid #1890FF;
+ font-style: normal;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 24px;
+ /* identical to box height, or 150% */
+
+ text-align: center;
+}
+
+.btn2{
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 5px 36px;
+ filter: drop-shadow(0px 2px 0px rgba(0, 0, 0, 0.016));
+ border-radius: 16px;
+ background: #1890FF;
+ border: 1px solid #1890FF;
+ font-style: normal;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 24px;
+ /* identical to box height, or 150% */
+
+ text-align: center;
+
+ /* Character / Primary(inverse) */
+
+ color: #FFFFFF;
+}
+
+.addBtnWrapper{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ gap:25px
+}
\ No newline at end of file
diff --git a/src/admin/adminMarketPopUp/index.tsx b/src/admin/adminMarketPopUp/index.tsx
new file mode 100644
index 0000000..4692ba5
--- /dev/null
+++ b/src/admin/adminMarketPopUp/index.tsx
@@ -0,0 +1,80 @@
+import "./adminMarketPopUp.css"
+import React, { useState } from "react"
+import { useNavigate, useParams } from "react-router-dom"
+import { useAppDispatch, useAppSelector } from "../../app/hooks"
+import { RootAdminState } from "../../app/adminStore"
+import { fetchChangeProduct, getProductByID, getUser } from "../../app/admin/adminSlice"
+import { Button, Input } from "antd"
+import { ProductIE } from "../../app/interfaces"
+import { PrevMarketCard } from "../../components/prevMarketCard"
+import { Header } from "../../components/Header"
+
+export const AdminMarketPopUp:React.FC = () =>{
+ let {id} = useParams()
+ let product = useAppSelector((state: RootAdminState)=>getProductByID(state, Number(id)))
+ const [cost, setCost] = useState(product.cost)
+ const [name, setName] = useState(product.name)
+ const [descr, setDescr] = useState(product.description)
+ let user = useAppSelector((state:RootAdminState)=>getUser(state))
+
+ let dispatch = useAppDispatch()
+ let navigate = useNavigate()
+ const onSave = () =>{
+ console.log("cocb")
+ fetchChangeProduct(dispatch, {
+ cost: cost,
+ name: name,
+ description: descr,
+ id:product.id,
+ image: product.image
+ } as ProductIE)
+ navigate("/admin/market")
+ }
+
+ return(
+
+
+
+
Изменение товара
+
+
+
+
+
Цена
+
setCost(Number(e.target.value))} placeholder="Цена">
+
+
+
Название
+
setName(e.target.value)} placeholder="Название">
+
+
+
Описание
+
setDescr(e.target.value)} placeholder="Описание">
+
+
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/admin/index.tsx b/src/admin/index.tsx
new file mode 100644
index 0000000..624a983
--- /dev/null
+++ b/src/admin/index.tsx
@@ -0,0 +1,75 @@
+import React, { useState } from "react";
+import 'antd/dist/antd.css';
+import { Button, Input } from 'antd';
+import { fetchAddProduct, fetchDelProduct, fetchSendCoins, getProducts, getUser } from "../app/admin/adminSlice";
+import { adminFetcher, useAppDispatch, useAppSelector } from "../app/hooks";
+import { useSelector } from "react-redux";
+import { RootAdminState } from "../app/adminStore";
+import { Header } from "../components/Header";
+
+export const AdminPage:React.FC = () => {
+ const [respProducts, setRespProducts] = useState([-1 as any])
+ let products = useAppSelector((state:RootAdminState)=>getProducts(state))
+ let user = useAppSelector((state:RootAdminState)=>getUser(state))
+ let dispatch = useAppDispatch()
+ if (products.length == 0){
+ adminFetcher.get("marketplace/product/").then(
+ (response)=> setRespProducts(response.data as any)
+ )
+ }
+
+ if (respProducts[0] != -1){
+ respProducts.forEach((product)=>{
+ fetchAddProduct(dispatch, product)
+ })
+ }
+
+
+ return(
+
+ );
+}
diff --git a/src/app/admin/adminSlice.ts b/src/app/admin/adminSlice.ts
new file mode 100644
index 0000000..88c0780
--- /dev/null
+++ b/src/app/admin/adminSlice.ts
@@ -0,0 +1,118 @@
+import { createAsyncThunk, createSlice, createSelector, PayloadAction } from '@reduxjs/toolkit'
+import { stat } from 'fs'
+import { Market, Roles, SortTypes, UserIE, ProductIE} from '../interfaces'
+import { AppAdminDispatch, RootAdminState } from '../adminStore'
+import { adminFetcher, useAppDispatch } from '../hooks'
+import { host, token } from '../consts'
+
+
+
+
+
+const initState = {
+ user: {
+ wallet:"123214",
+ balance: 100,
+ id:1,
+ role:Roles.admin,
+ name:"Firesieht"
+ } as UserIE, //потом достается запросом
+ market: {
+ sortType: SortTypes.sortByPriceSmaller,
+ products: []
+ } as Market // потом достается запросом
+}
+
+const adminSlice = createSlice(
+ {
+ name: "adminSlice",
+ initialState: initState,
+ reducers:{
+ sendCoins(state, action: PayloadAction){
+ state.user.balance = state.user.balance - action.payload
+ },
+ addProduct(state, action: PayloadAction){
+ state.market.products = state.market.products.concat([action.payload])
+ },
+ delProduct(state, action:PayloadAction){
+ let products = state.market.products
+ let ind = 0
+ products.forEach((product, index)=>{
+ if (product.id == action.payload){
+ ind = index
+ }
+ })
+ products.splice(ind, 1)
+ state.market.products = products
+ },
+ changeProduct(state, action:PayloadAction){
+ let products = state.market.products
+ products.forEach((product,index)=>{
+ if (product.id == action.payload.id){
+ products[index] = action.payload
+ }
+ })
+ state.market.products = products
+ }
+ }
+ }
+)
+
+
+export async function fetchSendCoins(dispatch:AppAdminDispatch, params:{userID:number, amount:number}) {
+ //тут идет фетч
+ dispatch(sendCoins(params.amount))
+}
+
+export async function fetchAddProduct(dispatch:AppAdminDispatch, params:{image: FormData, descr: string, name:string, cost:number}) {
+ //тут идет фетч
+ let data = {
+ image: "",
+ description: params.descr,
+ name: params.name,
+ cost: params.cost,
+ id: params.cost
+ } as ProductIE //vмоковая даата
+ adminFetcher.post("marketplace/product/", {
+
+ })
+
+ dispatch(addProduct(data))
+}
+
+export async function fetchDelProduct(dispatch:AppAdminDispatch, id:number) {
+ //тут идет фетч
+ dispatch(delProduct(id))
+}
+
+export async function fetchChangeProduct(dispatch:AppAdminDispatch, params:ProductIE) {
+ dispatch(changeProduct(params))
+}
+
+export const getProducts = createSelector(
+ (state:RootAdminState) => state.adminSlice.market.products,
+ (field)=>field
+)
+
+export const getProductByID = createSelector(
+ (state:RootAdminState, id:number) => state.adminSlice.market.products.filter((product)=>product.id == id)[0],
+ (field)=>field
+)
+
+export const getSortType = createSelector(
+ (state:RootAdminState) => state.adminSlice.market.sortType,
+ (field)=>field
+)
+export const getUser = createSelector(
+ (state:RootAdminState) => state.adminSlice.user,
+ (field)=>field
+)
+
+export const {
+ sendCoins,
+ addProduct,
+ delProduct,
+ changeProduct,
+} = adminSlice.actions
+
+export default adminSlice.reducer
\ No newline at end of file
diff --git a/src/app/adminStore.ts b/src/app/adminStore.ts
new file mode 100644
index 0000000..1902f0d
--- /dev/null
+++ b/src/app/adminStore.ts
@@ -0,0 +1,16 @@
+import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
+import adminSlice from './admin/adminSlice';
+export const adminStore = configureStore({
+ reducer: {
+ adminSlice: adminSlice,
+ },
+});
+
+export type AppAdminDispatch = typeof adminStore.dispatch;
+export type RootAdminState = ReturnType;
+export type AppAdminThunk = ThunkAction<
+ ReturnType,
+ RootAdminState,
+ unknown,
+ Action
+>;
diff --git a/src/app/consts.ts b/src/app/consts.ts
new file mode 100644
index 0000000..2538250
--- /dev/null
+++ b/src/app/consts.ts
@@ -0,0 +1,2 @@
+export const host = "https://dev.akarpov.ru/api/"
+export const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY1ODI0ODQxLCJpYXQiOjE2NjUyMjQ4NDEsImp0aSI6ImIyMjgzZjg0MmQ0NjQ4ZDU5MGY3N2Y1NzU2NDU3YjUyIiwidXNlcl9pZCI6NH0.-jAQjFLV9WCZEbthdpO-JDbRaL3N3eTCNr9Vo-PAUEk"
\ No newline at end of file
diff --git a/src/app/hooks.ts b/src/app/hooks.ts
index 520e84e..350cd1c 100644
--- a/src/app/hooks.ts
+++ b/src/app/hooks.ts
@@ -1,6 +1,17 @@
+import axios from 'axios';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
-import type { RootState, AppDispatch } from './store';
+import type { RootAdminState, AppAdminDispatch } from './adminStore';
+import { host, token } from './consts';
// Use throughout your app instead of plain `useDispatch` and `useSelector`
-export const useAppDispatch = () => useDispatch();
-export const useAppSelector: TypedUseSelectorHook = useSelector;
+export const useAppDispatch = () => useDispatch();
+export const useAppSelector: TypedUseSelectorHook = useSelector;
+export const adminFetcher = axios.create(
+ {
+ baseURL: host,
+ timeout: 1000,
+ headers: {
+ Authorization: 'Bearer ' + token
+ }
+ }
+)
\ No newline at end of file
diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts
new file mode 100644
index 0000000..e65eb84
--- /dev/null
+++ b/src/app/interfaces.ts
@@ -0,0 +1,57 @@
+export enum Roles{
+ user,
+ admin,
+ hr
+}
+export enum Specialities{
+ designer,
+ frontend,
+ backend,
+ DevOps,
+ smm,
+}
+
+
+export interface UserIE{
+ wallet:string,
+ id:number
+ role:Roles
+ balance: number,
+ name:string,
+}
+
+
+
+export interface EmployerIE extends UserIE{
+ jobTittle:Specialities,
+ respect: number,
+}
+
+
+export interface EventIE{
+ name:string,
+ description: string,
+ date: Date,
+ time:Date,
+ org: number;
+ visitors: number[]
+}
+
+export interface ProductIE{
+ name:string,
+ description:string,
+ image: string,
+ cost: number,
+ id: number,
+}
+
+export enum SortTypes{
+ sortByPriceSmaller,
+ sortByPriceBigger,
+ sortByLetter
+}
+
+export interface Market{
+ sortType: SortTypes,
+ products: ProductIE[],
+}
diff --git a/src/app/store.ts b/src/app/store.ts
deleted file mode 100644
index 133ff34..0000000
--- a/src/app/store.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
-import counterReducer from '../features/counter/counterSlice';
-
-export const store = configureStore({
- reducer: {
- counter: counterReducer,
- },
-});
-
-export type AppDispatch = typeof store.dispatch;
-export type RootState = ReturnType;
-export type AppThunk = ThunkAction<
- ReturnType,
- RootState,
- unknown,
- Action
->;
diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css
new file mode 100644
index 0000000..10c8220
--- /dev/null
+++ b/src/components/Header/Header.css
@@ -0,0 +1,53 @@
+.header{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ background: #262626;
+ position: fixed;
+ top:0px;
+ width: 100%;
+ padding:10px 20px;
+ font-family: 'Roboto', sans-serif;
+ font-style: normal;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 24px;
+
+ color: #FFFFFF;
+}
+.links{
+ display: flex;
+ flex-direction: row;
+ gap:16px;
+ font-style: normal;
+ font-weight: 700;
+ font-size: 14px;
+ line-height: 22px;
+
+}
+.link{
+ filter: drop-shadow(0px 2px 0px rgba(0, 0, 0, 0.043));
+ border-radius: 101px;
+ padding: 8px 16px;
+ border: 1px solid #1890FF;
+
+
+}
+
+.activeLink{
+ background: #1890FF;
+ /* drop-shadow / button-primary */
+
+ box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.043);
+ border-radius: 101px;
+ padding: 8px 16px;
+
+}
+
+.userInfo{
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx
new file mode 100644
index 0000000..601deb5
--- /dev/null
+++ b/src/components/Header/index.tsx
@@ -0,0 +1,39 @@
+import "./Header.css"
+import React from "react"
+import { Link, useLocation, useParams } from "react-router-dom"
+import axios, { AxiosHeaders } from 'axios';
+import { host, token } from "../../app/consts";
+
+interface HeaderIE{
+ links: {
+ link:string,
+ name:string
+ }[],
+ name:string
+}
+
+export const Header:React.FC = (props) =>{
+ let location = useLocation()
+ const onClick = () =>{
+
+ }
+
+
+ return(
+
+ );
+}
diff --git a/src/components/fileUploader.tsx b/src/components/fileUploader.tsx
new file mode 100644
index 0000000..e65bf8e
--- /dev/null
+++ b/src/components/fileUploader.tsx
@@ -0,0 +1,38 @@
+import React, { useState } from "react";
+import { Button, message, Upload } from "antd"
+import Icon, { UploadOutlined } from '@ant-design/icons';
+import 'antd/dist/antd.css';
+import { host } from "../app/consts";
+
+
+interface FileUploaderIE{
+ onResponse: (response:any)=>void
+}
+export const FileUploader:React.FC = (data) =>{
+
+ const props = {
+ name: 'file',
+ action: host + '/api/',
+ headers: {
+ authorization: 'authorization-text',
+ },
+
+ onChange(info:any) {
+ if (info.file.status !== 'uploading') {
+ }
+
+ if (info.file.status === 'done') {
+ data.onResponse(info.file.response)
+ message.success(`${info.file.name} file uploaded successfully`);
+ } else if (info.file.status === 'error') {
+ message.error(`${info.file.name} file upload failed.`);
+ }
+ },
+ };
+
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/prevMarketCard/index.tsx b/src/components/prevMarketCard/index.tsx
new file mode 100644
index 0000000..773fb5f
--- /dev/null
+++ b/src/components/prevMarketCard/index.tsx
@@ -0,0 +1,25 @@
+import React from "react"
+import "./prevMarketCard.css"
+interface PrevMarketCardIE{
+ image:string,
+ cost: number,
+ descr: string,
+ name:string
+}
+
+export const PrevMarketCard:React.FC = (props) =>{
+
+ return(
+
+
+
+
+
+
{props.cost}
+
+
{props.name}
+
{props.descr.split(" ").slice(0,6).join(" ")}
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/prevMarketCard/prevMarketCard.css b/src/components/prevMarketCard/prevMarketCard.css
new file mode 100644
index 0000000..4b3c2e3
--- /dev/null
+++ b/src/components/prevMarketCard/prevMarketCard.css
@@ -0,0 +1,50 @@
+.prevCard{
+ width: 240px;
+ max-height: 400px;
+ display: flex;
+ flex-direction: column;
+ background: #FFFFFF;
+ border-radius: 16px;
+ border: 1px solid #1890FF;
+
+}
+
+.prevImg{
+ height: 50%;
+ border-radius: 16px 16px 0px 0px;
+}
+
+.prevCardWrapper{
+ padding: 15px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items:flex-start;
+ gap: 15px;
+ text-align: left;
+}
+
+.prevCost{
+ border: 1px solid #1890FF;
+ border-radius: 16px;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ padding: 5px 16px;
+ gap:10px;
+}
+.prevCardH2{
+ font-weight: 400;
+ font-size: 16px;
+ line-height: 24px;
+ color: rgba(0, 0, 0, 0.85)
+}
+
+.prevCardDescr{
+ font-size: 14px;
+ line-height: 22px;
+ color: rgba(0, 0, 0, 0.45);
+ max-width: 210px;
+ overflow-x:hidden
+}
\ No newline at end of file
diff --git a/src/features/counter/Counter.module.css b/src/features/counter/Counter.module.css
deleted file mode 100644
index 025bb72..0000000
--- a/src/features/counter/Counter.module.css
+++ /dev/null
@@ -1,79 +0,0 @@
-.row {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.row > button {
- margin-left: 4px;
- margin-right: 8px;
-}
-
-.row:not(:last-child) {
- margin-bottom: 16px;
-}
-
-.value {
- font-size: 78px;
- padding-left: 16px;
- padding-right: 16px;
- margin-top: 2px;
- font-family: 'Courier New', Courier, monospace;
-}
-
-.button {
- appearance: none;
- background: none;
- font-size: 32px;
- padding-left: 12px;
- padding-right: 12px;
- outline: none;
- border: 2px solid transparent;
- color: rgb(112, 76, 182);
- padding-bottom: 4px;
- cursor: pointer;
- background-color: rgba(112, 76, 182, 0.1);
- border-radius: 2px;
- transition: all 0.15s;
-}
-
-.textbox {
- font-size: 32px;
- padding: 2px;
- width: 64px;
- text-align: center;
- margin-right: 4px;
-}
-
-.button:hover,
-.button:focus {
- border: 2px solid rgba(112, 76, 182, 0.4);
-}
-
-.button:active {
- background-color: rgba(112, 76, 182, 0.2);
-}
-
-.asyncButton {
- composes: button;
- position: relative;
-}
-
-.asyncButton:after {
- content: '';
- background-color: rgba(112, 76, 182, 0.15);
- display: block;
- position: absolute;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- opacity: 0;
- transition: width 1s linear, opacity 0.5s ease 1s;
-}
-
-.asyncButton:active:after {
- width: 0%;
- opacity: 1;
- transition: 0s;
-}
diff --git a/src/features/counter/Counter.tsx b/src/features/counter/Counter.tsx
deleted file mode 100644
index ece5191..0000000
--- a/src/features/counter/Counter.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import React, { useState } from 'react';
-
-import { useAppSelector, useAppDispatch } from '../../app/hooks';
-import {
- decrement,
- increment,
- incrementByAmount,
- incrementAsync,
- incrementIfOdd,
- selectCount,
-} from './counterSlice';
-import styles from './Counter.module.css';
-
-export function Counter() {
- const count = useAppSelector(selectCount);
- const dispatch = useAppDispatch();
- const [incrementAmount, setIncrementAmount] = useState('2');
-
- const incrementValue = Number(incrementAmount) || 0;
-
- return (
-
-
-
- {count}
-
-
-
- setIncrementAmount(e.target.value)}
- />
-
-
-
-
-
- );
-}
diff --git a/src/features/counter/counterAPI.ts b/src/features/counter/counterAPI.ts
deleted file mode 100644
index 0a9cdd3..0000000
--- a/src/features/counter/counterAPI.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// A mock function to mimic making an async request for data
-export function fetchCount(amount = 1) {
- return new Promise<{ data: number }>((resolve) =>
- setTimeout(() => resolve({ data: amount }), 500)
- );
-}
diff --git a/src/features/counter/counterSlice.spec.ts b/src/features/counter/counterSlice.spec.ts
deleted file mode 100644
index 098163b..0000000
--- a/src/features/counter/counterSlice.spec.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import counterReducer, {
- CounterState,
- increment,
- decrement,
- incrementByAmount,
-} from './counterSlice';
-
-describe('counter reducer', () => {
- const initialState: CounterState = {
- value: 3,
- status: 'idle',
- };
- it('should handle initial state', () => {
- expect(counterReducer(undefined, { type: 'unknown' })).toEqual({
- value: 0,
- status: 'idle',
- });
- });
-
- it('should handle increment', () => {
- const actual = counterReducer(initialState, increment());
- expect(actual.value).toEqual(4);
- });
-
- it('should handle decrement', () => {
- const actual = counterReducer(initialState, decrement());
- expect(actual.value).toEqual(2);
- });
-
- it('should handle incrementByAmount', () => {
- const actual = counterReducer(initialState, incrementByAmount(2));
- expect(actual.value).toEqual(5);
- });
-});
diff --git a/src/features/counter/counterSlice.ts b/src/features/counter/counterSlice.ts
deleted file mode 100644
index 015dca0..0000000
--- a/src/features/counter/counterSlice.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { RootState, AppThunk } from '../../app/store';
-import { fetchCount } from './counterAPI';
-
-export interface CounterState {
- value: number;
- status: 'idle' | 'loading' | 'failed';
-}
-
-const initialState: CounterState = {
- value: 0,
- status: 'idle',
-};
-
-// The function below is called a thunk and allows us to perform async logic. It
-// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
-// will call the thunk with the `dispatch` function as the first argument. Async
-// code can then be executed and other actions can be dispatched. Thunks are
-// typically used to make async requests.
-export const incrementAsync = createAsyncThunk(
- 'counter/fetchCount',
- async (amount: number) => {
- const response = await fetchCount(amount);
- // The value we return becomes the `fulfilled` action payload
- return response.data;
- }
-);
-
-export const counterSlice = createSlice({
- name: 'counter',
- initialState,
- // The `reducers` field lets us define reducers and generate associated actions
- reducers: {
- increment: (state) => {
- // Redux Toolkit allows us to write "mutating" logic in reducers. It
- // doesn't actually mutate the state because it uses the Immer library,
- // which detects changes to a "draft state" and produces a brand new
- // immutable state based off those changes
- state.value += 1;
- },
- decrement: (state) => {
- state.value -= 1;
- },
- // Use the PayloadAction type to declare the contents of `action.payload`
- incrementByAmount: (state, action: PayloadAction) => {
- state.value += action.payload;
- },
- },
- // The `extraReducers` field lets the slice handle actions defined elsewhere,
- // including actions generated by createAsyncThunk or in other slices.
- extraReducers: (builder) => {
- builder
- .addCase(incrementAsync.pending, (state) => {
- state.status = 'loading';
- })
- .addCase(incrementAsync.fulfilled, (state, action) => {
- state.status = 'idle';
- state.value += action.payload;
- })
- .addCase(incrementAsync.rejected, (state) => {
- state.status = 'failed';
- });
- },
-});
-
-export const { increment, decrement, incrementByAmount } = counterSlice.actions;
-
-// The function below is called a selector and allows us to select a value from
-// the state. Selectors can also be defined inline where they're used instead of
-// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
-export const selectCount = (state: RootState) => state.counter.value;
-
-// We can also write thunks by hand, which may contain both sync and async logic.
-// Here's an example of conditionally dispatching actions based on current state.
-export const incrementIfOdd =
- (amount: number): AppThunk =>
- (dispatch, getState) => {
- const currentValue = selectCount(getState());
- if (currentValue % 2 === 1) {
- dispatch(incrementByAmount(amount));
- }
- };
-
-export default counterSlice.reducer;
diff --git a/src/index.css b/src/index.css
index ec2585e..ebbd87e 100644
--- a/src/index.css
+++ b/src/index.css
@@ -11,3 +11,11 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
+a{
+ text-decoration: none !important;
+ color: #FFFFFF !important;
+}
+a:active{
+ text-decoration: none !important;
+ color: #FFFFFF;
+}
diff --git a/src/index.tsx b/src/index.tsx
index 0e6466f..392ee03 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,23 +1,44 @@
import React from 'react';
import { createRoot } from 'react-dom/client';
-import { Provider } from 'react-redux';
-import { store } from './app/store';
+
import App from './App';
-import reportWebVitals from './reportWebVitals';
import './index.css';
+import { Provider } from 'react-redux';
+import { adminStore} from './app/adminStore';
+import { AdminPage } from './admin';
+import { AdminMarket } from './admin/adminMarket';
+import { AdminMarketPopUp } from './admin/adminMarketPopUp';
+import { AddAdminMarketProduct } from './admin/addAdminMarketCard';
+import {
+ Route,
+ createBrowserRouter,
+ createRoutesFromElements,
+ RouterProvider,
+ Link,
+ Routes
+} from "react-router-dom";
const container = document.getElementById('root')!;
const root = createRoot(container);
+const router = createBrowserRouter(
+ createRoutesFromElements(
+
+ }>
+ }>
+ }>
+ }>
+
+
+
+
+ )
+);
+
root.render(
-
-
-
+
+
);
-// If you want to start measuring performance in your app, pass a function
-// to log results (for example: reportWebVitals(console.log))
-// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
-reportWebVitals();
diff --git a/src/logo.svg b/src/logo.svg
deleted file mode 100644
index 8466738..0000000
--- a/src/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
deleted file mode 100644
index 6431bc5..0000000
--- a/src/react-app-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts
deleted file mode 100644
index 49a2a16..0000000
--- a/src/reportWebVitals.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ReportHandler } from 'web-vitals';
-
-const reportWebVitals = (onPerfEntry?: ReportHandler) => {
- if (onPerfEntry && onPerfEntry instanceof Function) {
- import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
- getCLS(onPerfEntry);
- getFID(onPerfEntry);
- getFCP(onPerfEntry);
- getLCP(onPerfEntry);
- getTTFB(onPerfEntry);
- });
- }
-};
-
-export default reportWebVitals;