From 32da4e52aea62ef29e58fd50a5889af3a8aef1c2 Mon Sep 17 00:00:00 2001 From: Nikolay Vigdorov Date: Sun, 13 Jun 2021 01:56:32 +0300 Subject: [PATCH] add crud api --- .eslintrc.json | 2 +- package-lock.json | 251 +++++++++++++++++- package.json | 5 + robot.svg | 1 + src/app/components/main-layout/MainLayout.tsx | 28 ++ src/app/components/main-layout/index.ts | 1 + src/app/components/menu/Menu.tsx | 58 ++++ src/app/components/menu/index.ts | 1 + src/app/components/page/Page.scss | 17 -- src/app/components/page/Page.tsx | 67 +++-- src/app/index.tsx | 7 +- src/core/api/CrudAPI.ts | 87 ++++++ src/core/consts/common.ts | 11 +- src/pages/actions/components/page/Page.tsx | 9 + src/pages/actions/components/page/index.ts | 1 + src/pages/actions/routing.tsx | 8 + src/pages/conditions/components/page/Page.tsx | 9 + src/pages/conditions/components/page/index.ts | 1 + src/pages/conditions/routing.tsx | 8 + src/pages/currencies/components/page/Page.tsx | 9 + src/pages/currencies/components/page/index.ts | 1 + src/pages/currencies/routing.tsx | 8 + src/pages/graphs/components/page/Page.tsx | 9 + src/pages/graphs/components/page/index.ts | 1 + src/pages/graphs/routing.tsx | 8 + src/pages/main/components/page/Page.tsx | 12 +- src/pages/users/api/UsersAPI.ts | 4 + src/pages/users/components/page/Page.tsx | 12 + src/pages/users/components/page/index.ts | 1 + src/pages/users/routing.tsx | 8 + 30 files changed, 582 insertions(+), 63 deletions(-) create mode 100644 robot.svg create mode 100644 src/app/components/main-layout/MainLayout.tsx create mode 100644 src/app/components/main-layout/index.ts create mode 100644 src/app/components/menu/Menu.tsx create mode 100644 src/app/components/menu/index.ts delete mode 100644 src/app/components/page/Page.scss create mode 100644 src/core/api/CrudAPI.ts create mode 100644 src/pages/actions/components/page/Page.tsx create mode 100644 src/pages/actions/components/page/index.ts create mode 100644 src/pages/actions/routing.tsx create mode 100644 src/pages/conditions/components/page/Page.tsx create mode 100644 src/pages/conditions/components/page/index.ts create mode 100644 src/pages/conditions/routing.tsx create mode 100644 src/pages/currencies/components/page/Page.tsx create mode 100644 src/pages/currencies/components/page/index.ts create mode 100644 src/pages/currencies/routing.tsx create mode 100644 src/pages/graphs/components/page/Page.tsx create mode 100644 src/pages/graphs/components/page/index.ts create mode 100644 src/pages/graphs/routing.tsx create mode 100644 src/pages/users/api/UsersAPI.ts create mode 100644 src/pages/users/components/page/Page.tsx create mode 100644 src/pages/users/components/page/index.ts create mode 100644 src/pages/users/routing.tsx diff --git a/.eslintrc.json b/.eslintrc.json index c38f6d5..859eda9 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -47,7 +47,7 @@ "import/extensions": 0, "react/prop-types": 0, "no-underscore-dangle": 0, - "import/imports-first": ["warn", "absolute-first"], + "import/imports-first": 0, "import/prefer-default-export": 0, "import/no-unresolved": 0, "import/newline-after-import": "error", diff --git a/package-lock.json b/package-lock.json index 09416a8..41515bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1439,6 +1439,19 @@ "is-negated-glob": "^1.0.0" } }, + "@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "requires": { + "@emotion/memoize": "0.7.1" + } + }, + "@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" + }, "@eslint/eslintrc": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", @@ -5457,6 +5470,16 @@ } } }, + "css-jss": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/css-jss/-/css-jss-10.6.0.tgz", + "integrity": "sha512-4SE0tWggVM6Y4UTcKMoZXFBuhzycY6fKEdONr7wn89SIFd4eXiUZ0f5f4tLwXyFOW2q13JReXp8n9vSLKp48/g==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "jss-preset-default": "10.6.0" + } + }, "css-loader": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.6.tgz", @@ -5600,6 +5623,15 @@ } } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css-what": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", @@ -6019,6 +6051,11 @@ } } }, + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -8851,6 +8888,11 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -8970,6 +9012,14 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indefinite-observable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz", + "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==", + "requires": { + "symbol-observable": "1.2.0" + } + }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -9263,6 +9313,11 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, "is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -10509,6 +10564,155 @@ "universalify": "^2.0.0" } }, + "jss": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.6.0.tgz", + "integrity": "sha512-n7SHdCozmxnzYGXBHe0NsO0eUf9TvsHVq2MXvi4JmTn3x5raynodDVE/9VQmBdWFyyj9HpHZ2B4xNZ7MMy7lkw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "indefinite-observable": "^2.0.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.6.0.tgz", + "integrity": "sha512-JdLpA3aI/npwj3nDMKk308pvnhoSzkW3PXlbgHAzfx0yHWnPPVUjPhXFtLJzgKZge8lsfkUxvYSQ3X2OYIFU6A==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.6.0" + } + }, + "jss-plugin-compose": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.6.0.tgz", + "integrity": "sha512-zBhI5ZDVX30h4N+rPunAfbwHVDWlme0JPiLBT0TSg24aX+QhjpogZSKHv9pn23NqIdiz3aIJmrNVnJ5rwNKQKA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-default-unit": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.6.0.tgz", + "integrity": "sha512-7y4cAScMHAxvslBK2JRK37ES9UT0YfTIXWgzUWD5euvR+JR3q+o8sQKzBw7GmkQRfZijrRJKNTiSt1PBsLI9/w==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-expand": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.6.0.tgz", + "integrity": "sha512-TYVfKS3l8kNaClWW3PA9AhFr9ixhBnKcdGwZDRH3WRGDmdX0RYOhpfScscRXQM1HAlqaXLRqiP+NYGCK6QBgOg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-extend": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.6.0.tgz", + "integrity": "sha512-eY/zKMT+aUOdHegTDzTznq8Nwsv0PEb5AyJfo8A1B9jPxzzLTGcFOl9S6JZoYRxMh9TWxA5lOULMIjgKAKzUcQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-global": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.6.0.tgz", + "integrity": "sha512-I3w7ji/UXPi3VuWrTCbHG9rVCgB4yoBQLehGDTmsnDfXQb3r1l3WIdcO8JFp9m0YMmyy2CU7UOV6oPI7/Tmu+w==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-nested": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.6.0.tgz", + "integrity": "sha512-fOFQWgd98H89E6aJSNkEh2fAXquC9aZcAVjSw4q4RoQ9gU++emg18encR4AT4OOIFl4lQwt5nEyBBRn9V1Rk8g==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.6.0.tgz", + "integrity": "sha512-oMCe7hgho2FllNc60d9VAfdtMrZPo9n1Iu6RNa+3p9n0Bkvnv/XX5San8fTPujrTBScPqv9mOE0nWVvIaohNuw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.6.0.tgz", + "integrity": "sha512-TKFqhRTDHN1QrPTMYRlIQUOC2FFQb271+AbnetURKlGvRl/eWLswcgHQajwuxI464uZk91sPiTtdGi7r7XaWfA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-rule-value-observable": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.6.0.tgz", + "integrity": "sha512-+N6S8UZ+Tu+G2Fbu/UrfLI/JyaTi/KfkPbKsVRfyg/C/IdI+p9+H67HncMIFYEi/KnNj5fqvMNSDe4ag/lqbHw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "symbol-observable": "^1.2.0" + } + }, + "jss-plugin-template": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.6.0.tgz", + "integrity": "sha512-P3iaIR6AqTOoutwP7Y2KVCq4jShEMACrwKf8W9gsS3ppnIeBg4OCAQvLKmqunApkEoIk0711xbW9XPi9CYy3zg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.6.0.tgz", + "integrity": "sha512-doJ7MouBXT1lypLLctCwb4nJ6lDYqrTfVS3LtXgox42Xz0gXusXIIDboeh6UwnSmox90QpVnub7au8ybrb0krQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.6.0" + } + }, + "jss-preset-default": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.6.0.tgz", + "integrity": "sha512-TuHDZiuxGLLJ/LIMLAzO5uf2PnLOCR6yF5GHQLPp59YTascmwEldJfR0tuqjKa8B2F/v708ZvzE1Dw0Ao7UIcA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.6.0", + "jss-plugin-camel-case": "10.6.0", + "jss-plugin-compose": "10.6.0", + "jss-plugin-default-unit": "10.6.0", + "jss-plugin-expand": "10.6.0", + "jss-plugin-extend": "10.6.0", + "jss-plugin-global": "10.6.0", + "jss-plugin-nested": "10.6.0", + "jss-plugin-props-sort": "10.6.0", + "jss-plugin-rule-value-function": "10.6.0", + "jss-plugin-rule-value-observable": "10.6.0", + "jss-plugin-template": "10.6.0", + "jss-plugin-vendor-prefixer": "10.6.0" + } + }, "jsx-ast-utils": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", @@ -18117,8 +18321,7 @@ "querystring": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz", - "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==", - "dev": true + "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==" }, "querystring-es3": { "version": "0.2.1", @@ -18817,6 +19020,11 @@ } } }, + "react-display-name": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", + "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -18839,6 +19047,24 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "react-jss": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.6.0.tgz", + "integrity": "sha512-uCvOHMoQrB+cD8l6K6+gIStqBhTyjPM/55sXHfujlr0E4GclQg0ZR26nyGyh7XB+v9a2FfMp6Y4L2Bc1Z+L1oQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "@emotion/is-prop-valid": "^0.7.3", + "css-jss": "10.6.0", + "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", + "jss": "10.6.0", + "jss-preset-default": "10.6.0", + "prop-types": "^15.6.0", + "shallow-equal": "^1.2.0", + "theming": "^3.3.0", + "tiny-warning": "^1.0.2" + } + }, "react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -21087,6 +21313,11 @@ "kind-of": "^6.0.2" } }, + "shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -21970,6 +22201,11 @@ } } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -22208,6 +22444,17 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "theming": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz", + "integrity": "sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==", + "requires": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" + } + }, "throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", diff --git a/package.json b/package.json index 805c359..32a320e 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "author": "", "license": "ISC", "dependencies": { + "@ant-design/icons": "^4.6.2", "@reatom/core": "^1.1.5", "@reatom/react": "^1.1.5", "antd": "^4.16.2", @@ -32,9 +33,13 @@ "date-fns": "^2.16.1", "fp-ts": "^2.8.5", "history": "^5.0.0", + "jss": "^10.6.0", + "jss-preset-default": "^10.6.0", "lodash": "^4.17.20", + "querystring": "^0.2.1", "react": "^17.0.1", "react-dom": "^17.0.1", + "react-jss": "^10.6.0", "react-router-dom": "^5.2.0", "ts-loader": "^8.0.7", "typescript": "^4.0.3" diff --git a/robot.svg b/robot.svg new file mode 100644 index 0000000..afaa020 --- /dev/null +++ b/robot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/components/main-layout/MainLayout.tsx b/src/app/components/main-layout/MainLayout.tsx new file mode 100644 index 0000000..67c4172 --- /dev/null +++ b/src/app/components/main-layout/MainLayout.tsx @@ -0,0 +1,28 @@ +import {Layout} from 'antd'; +import React, {FC, memo, PropsWithChildren} from 'react'; +import {createUseStyles} from 'react-jss'; +import Menu from '../menu'; + +const useStyles = createUseStyles({ + layout: { + height: '100%', + }, +}); + +const MainLayout: FC> = ({children}) => { + const classes = useStyles(); + return ( + + + + + + + {children} + + + + ); +}; + +export default memo(MainLayout); diff --git a/src/app/components/main-layout/index.ts b/src/app/components/main-layout/index.ts new file mode 100644 index 0000000..358008b --- /dev/null +++ b/src/app/components/main-layout/index.ts @@ -0,0 +1 @@ +export {default} from './MainLayout'; diff --git a/src/app/components/menu/Menu.tsx b/src/app/components/menu/Menu.tsx new file mode 100644 index 0000000..991e2f6 --- /dev/null +++ b/src/app/components/menu/Menu.tsx @@ -0,0 +1,58 @@ +import {Menu} from 'antd'; +import React, {FC, memo, useCallback, useMemo, useState} from 'react'; +import {TeamOutlined, DollarCircleOutlined, ClusterOutlined, InteractionOutlined, DeploymentUnitOutlined} from '@ant-design/icons'; +import {ROUTES} from '_consts/common'; +import {Link, useLocation} from 'react-router-dom'; + +const MENU = [ + { + label: 'Users', + icon: , + url: ROUTES.USERS, + }, + { + label: 'Actions', + icon: , + url: ROUTES.ACTIONS, + }, + { + label: 'Conditions', + icon: , + url: ROUTES.CONDITIONS, + }, + { + label: 'Graphs', + icon: , + url: ROUTES.GRAPHS, + }, + { + label: 'Currencies', + icon: , + url: ROUTES.CURRENCIES, + }, +]; + +const TopMenu: FC = () => { + const {pathname} = useLocation(); + const [selected, setSelected] = useState(pathname); + + const selectedKeys = useMemo(() => [selected], [selected]); + + const handleClick = useCallback((e: {key: string}) => { + setSelected(e.key); + }, [setSelected]); + + return ( + + {MENU.map(({label, icon, url}) => { + return ( + + {label} + + ); + })} + + ); +}; + +export default memo(TopMenu); diff --git a/src/app/components/menu/index.ts b/src/app/components/menu/index.ts new file mode 100644 index 0000000..37b6008 --- /dev/null +++ b/src/app/components/menu/index.ts @@ -0,0 +1 @@ +export {default} from './Menu'; diff --git a/src/app/components/page/Page.scss b/src/app/components/page/Page.scss deleted file mode 100644 index 4581a7a..0000000 --- a/src/app/components/page/Page.scss +++ /dev/null @@ -1,17 +0,0 @@ -html { - height: 100%; -} - -body { - height: 100%; - margin: 0; -} - -#root { - height: 100%; -} - -a { - color: inherit; - text-decoration: none; -} \ No newline at end of file diff --git a/src/app/components/page/Page.tsx b/src/app/components/page/Page.tsx index 652c69a..e305b45 100644 --- a/src/app/components/page/Page.tsx +++ b/src/app/components/page/Page.tsx @@ -1,41 +1,56 @@ -import React, {Fragment, memo} from 'react'; +import React, {memo} from 'react'; import {Route, Switch} from 'react-router-dom'; -import {Container, createStyles, makeStyles} from '@material-ui/core'; import {createStore} from '@reatom/core'; import {context} from '@reatom/react'; import mainPageRouter from '_pages/main/routing'; +import usersPageRouter from '_pages/users/routing'; +import actionsPageRouter from '_pages/actions/routing'; +import conditionsPageRouter from '_pages/conditions/routing'; +import graphsPageRouter from '_pages/graphs/routing'; +import currenciesPageRouter from '_pages/currencies/routing'; import NotFoundPage from '_pages/not-found/components/page'; -import './Page.scss'; +import MainLayout from '../main-layout'; +import jss from 'jss'; +import preset from 'jss-preset-default'; -const useStyles = makeStyles(() => - createStyles({ - container: { - height: '100hv', - display: 'flex', - flexDirection: 'column', +jss.setup(preset()); + +const styles = { + '@global': { + html: { + height: '100%', }, - }), -); + body: { + height: '100%', + margin: '0', + }, + '#root': { + height: '100%', + }, + } +}; + +jss.createStyleSheet(styles).attach(); const Page: React.FC = () => { - const classes = useStyles(); const store = createStore(); return ( - -
- - - - {mainPageRouter} - - - - - - -
-
+ + + + {mainPageRouter} + {usersPageRouter} + {actionsPageRouter} + {conditionsPageRouter} + {graphsPageRouter} + {currenciesPageRouter} + + + + + + ); }; diff --git a/src/app/index.tsx b/src/app/index.tsx index d1b9d54..eb8d89b 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -1,17 +1,12 @@ import React from 'react'; import ReactDOM from 'react-dom'; import {HashRouter} from 'react-router-dom'; +import 'antd/dist/antd.css'; import App from './components/page'; ReactDOM.render( - /* - * Выключаем стрикт мод, пока не починят - * https://github.com/mui-org/material-ui/issues/13394 - */ - // , - // document.getElementById('root') ); diff --git a/src/core/api/CrudAPI.ts b/src/core/api/CrudAPI.ts new file mode 100644 index 0000000..6babbbc --- /dev/null +++ b/src/core/api/CrudAPI.ts @@ -0,0 +1,87 @@ +import {isNotEmpty} from '_referers/common'; +import {http} from '../infrastructure/Http'; + +type Filter = { + field: keyof T; + search: string; +}; + +type Sort = { + field: keyof T; + order: 'ASC' | 'DECS'; +}; + +type RequestEntities = { + filters?: Filter[]; + sort?: Sort; + limit?: number; + offset?: number; +}; + +type EntityWithId = T & { + id: string; +}; + +type ResponseEntities = { + data: EntityWithId[]; + count: number; + total: number; + page: number; + pageCount: number; +}; + +type BulkCreateRequest = { + bulk: T[]; +}; + +export class CrudAPI { + endpoint: string; + + constructor(endpoint: string) { + this.endpoint = endpoint; + } + + request = (options?: RequestEntities): Promise> => { + const {filters, sort, limit = 50, offset = 0} = options ?? {}; + const query = []; + + filters?.forEach(({field, search}) => { + query.push(`filter=${field}||$eq||${search}`); + }); + + if (sort) { + query.push(`sort=${sort.field},${sort.order}`); + } + + query.push(`limit=${limit}`); + query.push(`offset=${offset}`); + + return http.get>([this.endpoint, query.join('&')].filter(isNotEmpty).join('?')); + } + + find = (id: string): Promise => { + return http.get(`${this.endpoint}/${id}`); + } + + create = (entity: T): Promise> => { + return http.post>(this.endpoint, undefined, entity); + } + + update = (id: string, entity: T): Promise> => { + return http.patch>(`${this.endpoint}/${id}`, undefined, entity); + } + + replace = (id: string, entity: T): Promise> => { + return http.put>(`${this.endpoint}/${id}`, undefined, entity); + } + + remove = (id: string): Promise => { + return http.delete(`${this.endpoint}/${id}`); + } + + bulkCreate = (entities: T[]): Promise[]> => { + return http.post, EntityWithId[]>(`${this.endpoint}/bulk`, undefined, { + bulk: entities, + }); + } +} diff --git a/src/core/consts/common.ts b/src/core/consts/common.ts index 68f1ed5..f60b9fa 100644 --- a/src/core/consts/common.ts +++ b/src/core/consts/common.ts @@ -1,3 +1,12 @@ export const ROUTES = { - MAIN: '/' + MAIN: '/', + USERS: '/users', + ACTIONS: '/actions', + CONDITIONS: '/conditions', + GRAPHS: '/graphs', + CURRENCIES: '/currencies', +}; + +export const ENDPOINT = { + USERS: 'http://vigdorov.ru:3011/users', }; diff --git a/src/pages/actions/components/page/Page.tsx b/src/pages/actions/components/page/Page.tsx new file mode 100644 index 0000000..9a4d51a --- /dev/null +++ b/src/pages/actions/components/page/Page.tsx @@ -0,0 +1,9 @@ +import React, {FC, memo} from 'react'; + +const Page: FC = () => { + return ( +
actions
+ ); +}; + +export default memo(Page); diff --git a/src/pages/actions/components/page/index.ts b/src/pages/actions/components/page/index.ts new file mode 100644 index 0000000..ff9a33b --- /dev/null +++ b/src/pages/actions/components/page/index.ts @@ -0,0 +1 @@ +export {default} from './Page'; diff --git a/src/pages/actions/routing.tsx b/src/pages/actions/routing.tsx new file mode 100644 index 0000000..9ac9cfd --- /dev/null +++ b/src/pages/actions/routing.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import {Route} from 'react-router-dom'; +import {ROUTES} from '_consts/common'; +import Page from './components/page'; + +export default ( + +); diff --git a/src/pages/conditions/components/page/Page.tsx b/src/pages/conditions/components/page/Page.tsx new file mode 100644 index 0000000..958ac65 --- /dev/null +++ b/src/pages/conditions/components/page/Page.tsx @@ -0,0 +1,9 @@ +import React, {FC, memo} from 'react'; + +const Page: FC = () => { + return ( +
conditions
+ ); +}; + +export default memo(Page); diff --git a/src/pages/conditions/components/page/index.ts b/src/pages/conditions/components/page/index.ts new file mode 100644 index 0000000..ff9a33b --- /dev/null +++ b/src/pages/conditions/components/page/index.ts @@ -0,0 +1 @@ +export {default} from './Page'; diff --git a/src/pages/conditions/routing.tsx b/src/pages/conditions/routing.tsx new file mode 100644 index 0000000..31b7a8b --- /dev/null +++ b/src/pages/conditions/routing.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import {Route} from 'react-router-dom'; +import {ROUTES} from '_consts/common'; +import Page from './components/page'; + +export default ( + +); diff --git a/src/pages/currencies/components/page/Page.tsx b/src/pages/currencies/components/page/Page.tsx new file mode 100644 index 0000000..018a4a8 --- /dev/null +++ b/src/pages/currencies/components/page/Page.tsx @@ -0,0 +1,9 @@ +import React, {FC, memo} from 'react'; + +const Page: FC = () => { + return ( +
currencies
+ ); +}; + +export default memo(Page); diff --git a/src/pages/currencies/components/page/index.ts b/src/pages/currencies/components/page/index.ts new file mode 100644 index 0000000..ff9a33b --- /dev/null +++ b/src/pages/currencies/components/page/index.ts @@ -0,0 +1 @@ +export {default} from './Page'; diff --git a/src/pages/currencies/routing.tsx b/src/pages/currencies/routing.tsx new file mode 100644 index 0000000..18ac456 --- /dev/null +++ b/src/pages/currencies/routing.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import {Route} from 'react-router-dom'; +import {ROUTES} from '_consts/common'; +import Page from './components/page'; + +export default ( + +); diff --git a/src/pages/graphs/components/page/Page.tsx b/src/pages/graphs/components/page/Page.tsx new file mode 100644 index 0000000..c000f84 --- /dev/null +++ b/src/pages/graphs/components/page/Page.tsx @@ -0,0 +1,9 @@ +import React, {FC, memo} from 'react'; + +const Page: FC = () => { + return ( +
graphs
+ ); +}; + +export default memo(Page); diff --git a/src/pages/graphs/components/page/index.ts b/src/pages/graphs/components/page/index.ts new file mode 100644 index 0000000..ff9a33b --- /dev/null +++ b/src/pages/graphs/components/page/index.ts @@ -0,0 +1 @@ +export {default} from './Page'; diff --git a/src/pages/graphs/routing.tsx b/src/pages/graphs/routing.tsx new file mode 100644 index 0000000..45519d1 --- /dev/null +++ b/src/pages/graphs/routing.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import {Route} from 'react-router-dom'; +import {ROUTES} from '_consts/common'; +import Page from './components/page'; + +export default ( + +); diff --git a/src/pages/main/components/page/Page.tsx b/src/pages/main/components/page/Page.tsx index 8ce105f..abc7dc1 100644 --- a/src/pages/main/components/page/Page.tsx +++ b/src/pages/main/components/page/Page.tsx @@ -1,19 +1,11 @@ import React, {memo} from 'react'; -import {changeNameAction, nameAtom} from '_infrastructure/atom/exampleAtom'; -import {useAction, useAtom} from '@reatom/react'; const MainPage: React.FC = () => { - const name = useAtom(nameAtom); - const handleChangeName = useAction(e => changeNameAction(e.currentTarget.value)); - return (
-
main page
+
Админка Crypto-bot
-
- - -
+
Выбирите нужный раздел
); }; diff --git a/src/pages/users/api/UsersAPI.ts b/src/pages/users/api/UsersAPI.ts new file mode 100644 index 0000000..df16d7e --- /dev/null +++ b/src/pages/users/api/UsersAPI.ts @@ -0,0 +1,4 @@ +import {ENDPOINT} from '_consts/common'; +import {CrudAPI} from '../../../core/api/CrudAPI'; + +export const usersAPI = new CrudAPI(ENDPOINT.USERS); diff --git a/src/pages/users/components/page/Page.tsx b/src/pages/users/components/page/Page.tsx new file mode 100644 index 0000000..101757b --- /dev/null +++ b/src/pages/users/components/page/Page.tsx @@ -0,0 +1,12 @@ +import React, {FC, memo} from 'react'; +import {usersAPI} from '../../api/UsersAPI'; + +usersAPI.request(); + +const Page: FC = () => { + return ( +
users
+ ); +}; + +export default memo(Page); diff --git a/src/pages/users/components/page/index.ts b/src/pages/users/components/page/index.ts new file mode 100644 index 0000000..ff9a33b --- /dev/null +++ b/src/pages/users/components/page/index.ts @@ -0,0 +1 @@ +export {default} from './Page'; diff --git a/src/pages/users/routing.tsx b/src/pages/users/routing.tsx new file mode 100644 index 0000000..9dda350 --- /dev/null +++ b/src/pages/users/routing.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import {Route} from 'react-router-dom'; +import {ROUTES} from '_consts/common'; +import Page from './components/page'; + +export default ( + +);