From 91aebfd83cd82295d22f86be8dcc84783b247178 Mon Sep 17 00:00:00 2001 From: Dominik Zogg Date: Thu, 2 Apr 2020 20:50:59 +0200 Subject: [PATCH] tailwindcss --- config-overrides.js | 23 ++ package-lock.json | 326 ++++++++++------ package.json | 12 +- src/App.tsx | 36 +- src/Component/Form/PetFilterForm.tsx | 11 +- src/Component/Form/PetFilterFormProps.ts | 4 +- src/Component/Form/PetForm.tsx | 41 ++- src/Component/Form/PetFormProps.ts | 6 +- src/Component/Form/TextField.tsx | 15 +- src/Component/Navigation/Left.tsx | 15 - src/Component/Navigation/Top.tsx | 37 -- src/Component/Page/Home.tsx | 8 +- src/Component/Page/NotFound.tsx | 8 +- src/Component/Page/Pet/Create.tsx | 19 +- src/Component/Page/Pet/List.tsx | 49 +-- src/Component/Page/Pet/Read.tsx | 58 ++- src/Component/Page/Pet/Update.tsx | 21 +- src/Component/Partial/HttpError.tsx | 27 +- src/Component/Partial/Pagination.tsx | 51 +++ src/Component/Partial/PaginationProps.ts | 8 + src/__tests__/App.test.tsx | 181 +++++++-- .../Component/Form/PetFilterForm.test.tsx | 44 +-- src/__tests__/Component/Form/PetForm.test.tsx | 262 +++++++------ .../Component/Form/TextField.test.tsx | 6 +- .../Component/Navigation/Left.test.tsx | 40 -- .../Component/Navigation/Top.test.tsx | 109 ------ src/__tests__/Component/Page/Home.test.tsx | 6 +- .../Component/Page/NotFound.test.tsx | 6 +- .../Component/Page/Pet/Create.test.tsx | 24 +- .../Component/Page/Pet/List.test.tsx | 236 ++++++------ .../Component/Page/Pet/Read.test.tsx | 108 +++--- .../Component/Page/Pet/Update.test.tsx | 42 +-- .../Component/Partial/HttpError.test.tsx | 22 +- src/index.css | 347 +++++++++++++++--- src/index.tsx | 1 - tailwind.config.js | 7 + 36 files changed, 1262 insertions(+), 954 deletions(-) create mode 100644 config-overrides.js delete mode 100644 src/Component/Navigation/Left.tsx delete mode 100644 src/Component/Navigation/Top.tsx create mode 100644 src/Component/Partial/Pagination.tsx create mode 100644 src/Component/Partial/PaginationProps.ts delete mode 100644 src/__tests__/Component/Navigation/Left.test.tsx delete mode 100644 src/__tests__/Component/Navigation/Top.test.tsx create mode 100644 tailwind.config.js diff --git a/config-overrides.js b/config-overrides.js new file mode 100644 index 0000000..8d1d84b --- /dev/null +++ b/config-overrides.js @@ -0,0 +1,23 @@ +module.exports = { + webpack: function (config, env) { + + config.module.rules.push({ + test: /\.css$/, + use: [ + { + loader: 'postcss-loader', + options: { + ident: 'postcss', + plugins: [ + require('tailwindcss'), + require('postcss-nested'), + require('autoprefixer'), + ], + }, + }, + ] + }); + + return config; + } +}; diff --git a/package-lock.json b/package-lock.json index f09d3c9..19dc495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1376,15 +1376,6 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, - "@semantic-ui-react/event-stack": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.1.tgz", - "integrity": "sha512-SA7VOu/tY3OkooR++mm9voeQrJpYXjJaMHO1aFCcSouS2xhqMR9Gnz0LEGLOR0h9ueWPBKaQzKIrx3FTTJZmUQ==", - "requires": { - "exenv": "^1.2.2", - "prop-types": "^15.6.2" - } - }, "@sinonjs/commons": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", @@ -1393,25 +1384,6 @@ "type-detect": "4.0.8" } }, - "@stardust-ui/react-component-event-listener": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@stardust-ui/react-component-event-listener/-/react-component-event-listener-0.38.0.tgz", - "integrity": "sha512-sIP/e0dyOrrlb8K7KWumfMxj/gAifswTBC4o68Aa+C/GA73ccRp/6W1VlHvF/dlOR4KLsA+5SKnhjH36xzPsWg==", - "requires": { - "@babel/runtime": "^7.1.2", - "prop-types": "^15.7.2" - } - }, - "@stardust-ui/react-component-ref": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@stardust-ui/react-component-ref/-/react-component-ref-0.38.0.tgz", - "integrity": "sha512-xjs6WnvJVueSIXMWw0C3oWIgAPpcD03qw43oGOjUXqFktvpNkB73JoKIhS4sCrtQxBdct75qqr4ZL6JiyPcESw==", - "requires": { - "@babel/runtime": "^7.1.2", - "prop-types": "^15.7.2", - "react-is": "^16.6.3" - } - }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", @@ -2463,6 +2435,23 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==" }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "acorn-walk": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", + "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==" + } + } + }, "acorn-walk": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", @@ -3524,6 +3513,11 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -3691,11 +3685,6 @@ } } }, - "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" - }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -4106,15 +4095,6 @@ "sha.js": "^2.4.8" } }, - "create-react-context": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", - "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", - "requires": { - "gud": "^1.0.0", - "warning": "^4.0.3" - } - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -4270,6 +4250,11 @@ "source-map": "^0.6.1" } }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=" + }, "css-what": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.2.1.tgz", @@ -4541,6 +4526,11 @@ } } }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, "del": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", @@ -4644,6 +4634,16 @@ } } }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, "diff-sequences": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", @@ -5558,11 +5558,6 @@ "strip-eof": "^1.0.0" } }, - "exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" - }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -8781,11 +8776,6 @@ } } }, - "jquery": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", - "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8929,11 +8919,6 @@ "object.assign": "^4.1.0" } }, - "keyboard-key": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", - "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" - }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -9144,6 +9129,11 @@ "lodash._reinterpolate": "^3.0.0" } }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -9659,6 +9649,14 @@ "tslib": "^1.10.0" } }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "requires": { + "lodash.toarray": "^4.4.0" + } + }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", @@ -9824,6 +9822,11 @@ "sort-keys": "^1.0.0" } }, + "normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -10386,11 +10389,6 @@ "ts-pnp": "^1.1.6" } }, - "popper.js": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", - "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" - }, "portfinder": { "version": "1.0.25", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", @@ -10696,6 +10694,42 @@ "postcss": "^7.0.2" } }, + "postcss-functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz", + "integrity": "sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4=", + "requires": { + "glob": "^7.1.2", + "object-assign": "^4.1.1", + "postcss": "^6.0.9", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "postcss-gap-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", @@ -10722,6 +10756,15 @@ "postcss": "^7.0.2" } }, + "postcss-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz", + "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==", + "requires": { + "camelcase-css": "^2.0.1", + "postcss": "^7.0.18" + } + }, "postcss-lab-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", @@ -10937,6 +10980,15 @@ "postcss": "^7.0.6" } }, + "postcss-nested": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.1.tgz", + "integrity": "sha512-AMayXX8tS0HCp4O4lolp4ygj9wBn32DJWXvG6gCv+ZvJrEa00GUxJcJEEzMh87BIe6FrWdYkpR2cuyqHKrxmXw==", + "requires": { + "postcss": "^7.0.21", + "postcss-selector-parser": "^6.0.2" + } + }, "postcss-nesting": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", @@ -11378,6 +11430,11 @@ } } }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -11602,6 +11659,21 @@ "whatwg-fetch": "^3.0.0" } }, + "react-app-rewired": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.1.5.tgz", + "integrity": "sha512-Gr8KfCeL9/PTQs8Vvxc7v8wQ9vCFMnYPhcAkrMlzkLiMFXS+BgSwm11MoERjZm7dpA2WjTi+Pvbu/w7rujAV+A==", + "requires": { + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "react-dev-utils": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", @@ -11816,20 +11888,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" }, - "react-popper": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz", - "integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==", - "requires": { - "@babel/runtime": "^7.1.2", - "create-react-context": "^0.3.0", - "deep-equal": "^1.1.1", - "popper.js": "^1.14.4", - "prop-types": "^15.6.1", - "typed-styles": "^0.0.7", - "warning": "^4.0.2" - } - }, "react-router": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz", @@ -11998,6 +12056,22 @@ "strip-indent": "^3.0.0" } }, + "reduce-css-calc": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.7.tgz", + "integrity": "sha512-fDnlZ+AybAS3C7Q9xDq5y8A2z+lT63zLbynew/lur/IR24OQF5x98tfNwf79mzEdfywZ0a2wpM860FhFfMxZlA==", + "requires": { + "css-unit-converter": "^1.1.1", + "postcss-value-parser": "^3.3.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + } + } + }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -12532,32 +12606,6 @@ "node-forge": "0.9.0" } }, - "semantic-ui-css": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/semantic-ui-css/-/semantic-ui-css-2.4.1.tgz", - "integrity": "sha512-Pkp0p9oWOxlH0kODx7qFpIRYpK1T4WJOO4lNnpNPOoWKCrYsfHqYSKgk5fHfQtnWnsAKy7nLJMW02bgDWWFZFg==", - "requires": { - "jquery": "x.*" - } - }, - "semantic-ui-react": { - "version": "0.88.2", - "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.88.2.tgz", - "integrity": "sha512-+02kN2z8PuA/cMdvDUsHhbJmBzxxgOXVHMFr9XK7zGb0wkW9A6OPQMFokWz7ozlVtKjN6r7zsb+Qvjk/qq1OWw==", - "requires": { - "@babel/runtime": "^7.1.2", - "@semantic-ui-react/event-stack": "^3.1.0", - "@stardust-ui/react-component-event-listener": "~0.38.0", - "@stardust-ui/react-component-ref": "~0.38.0", - "classnames": "^2.2.6", - "keyboard-key": "^1.0.4", - "lodash": "^4.17.15", - "prop-types": "^15.7.2", - "react-is": "^16.8.6", - "react-popper": "^1.3.4", - "shallowequal": "^1.1.0" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -12747,11 +12795,6 @@ } } }, - "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": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -13518,6 +13561,62 @@ } } }, + "tailwindcss": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.2.0.tgz", + "integrity": "sha512-CKvY0ytB3ze5qvynG7qv4XSpQtFNGPbu9pUn8qFdkqgD8Yo/vGss8mhzbqls44YCXTl4G62p3qVZBj45qrd6FQ==", + "requires": { + "autoprefixer": "^9.4.5", + "bytes": "^3.0.0", + "chalk": "^3.0.0", + "detective": "^5.2.0", + "fs-extra": "^8.0.0", + "lodash": "^4.17.15", + "node-emoji": "^1.8.1", + "normalize.css": "^8.0.1", + "postcss": "^7.0.11", + "postcss-functions": "^3.0.0", + "postcss-js": "^2.0.0", + "postcss-nested": "^4.1.1", + "postcss-selector-parser": "^6.0.0", + "pretty-hrtime": "^1.0.3", + "reduce-css-calc": "^2.1.6", + "resolve": "^1.14.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -13844,11 +13943,6 @@ "mime-types": "~2.1.24" } }, - "typed-styles": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", - "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -14153,14 +14247,6 @@ "makeerror": "1.0.x" } }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } - }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", diff --git a/package.json b/package.json index e8ce9fd..db69421 100644 --- a/package.json +++ b/package.json @@ -17,14 +17,15 @@ "fetch-mock": "^9.3.1", "jest-environment-jsdom-sixteen": "^1.0.3", "node-fetch": "^2.6.0", + "postcss-loader": "^3.0.0", "qs": "^6.9.3", "react": "^16.13.1", + "react-app-rewired": "^2.1.5", "react-dom": "^16.13.1", "react-hook-form": "^5.2.0", "react-router-dom": "^5.1.2", "react-scripts": "3.4.1", - "semantic-ui-css": "^2.4.1", - "semantic-ui-react": "^0.88.2", + "tailwindcss": "^1.2.0", "typescript": "~3.8.3" }, "browserslist": { @@ -49,9 +50,8 @@ ] }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jest-environment-jsdom-sixteen", - "eject": "react-scripts eject" + "start": "react-app-rewired start", + "build": "react-app-rewired build", + "test": "react-app-rewired test --env=jest-environment-jsdom-sixteen" } } diff --git a/src/App.tsx b/src/App.tsx index e5be9cf..b87d5c0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,24 +1,38 @@ -import React from 'react'; -import Top from './Component/Navigation/Top'; -import Left from './Component/Navigation/Left'; +import React, { useState } from 'react'; import Home from './Component/Page/Home'; import PetList from './Component/Page/Pet/List'; import PetCreate from './Component/Page/Pet/Create'; import PetRead from './Component/Page/Pet/Read'; import PetUpdate from './Component/Page/Pet/Update'; import NotFound from './Component/Page/NotFound'; -import { BrowserRouter, Switch, Route } from 'react-router-dom'; +import { BrowserRouter, Switch, Route, NavLink } from 'react-router-dom'; const App: React.FC = () => { + const [displayMenu, setDisplayMenu] = useState(false); + + const toggleMenu = () => { + setDisplayMenu(!displayMenu); + }; + return ( - -
- -
+
+ + +
diff --git a/src/Component/Form/PetFilterForm.tsx b/src/Component/Form/PetFilterForm.tsx index 64f2719..c0b6afa 100644 --- a/src/Component/Form/PetFilterForm.tsx +++ b/src/Component/Form/PetFilterForm.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Form, Button } from 'semantic-ui-react'; import { useForm } from 'react-hook-form'; import InvalidParameterByNameDenormalizer from '../../Denormalizer/InvalidParameterByNameDenormalizer'; import PetFilterFormProps from './PetFilterFormProps'; @@ -20,12 +19,12 @@ const PetFilterForm: React.FC = ({ submitPetFilter, filters, }; return ( -
- + +
- - - + +
+ ); }; diff --git a/src/Component/Form/PetFilterFormProps.ts b/src/Component/Form/PetFilterFormProps.ts index de048ff..4ec38ed 100644 --- a/src/Component/Form/PetFilterFormProps.ts +++ b/src/Component/Form/PetFilterFormProps.ts @@ -1,5 +1,5 @@ -import BadRequest from "../../Model/Error/BadRequest"; -import PetFilters from "../../Model/Pet/PetFilters"; +import BadRequest from '../../Model/Error/BadRequest'; +import PetFilters from '../../Model/Pet/PetFilters'; type PetFilterFormProps = { submitPetFilter: { (filters: PetFilters): void; }, diff --git a/src/Component/Form/PetForm.tsx b/src/Component/Form/PetForm.tsx index 0821f7f..b7b96e7 100644 --- a/src/Component/Form/PetForm.tsx +++ b/src/Component/Form/PetForm.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Button, Form } from 'semantic-ui-react'; import { useForm, useFieldArray } from 'react-hook-form'; import InvalidParameterByNameDenormalizer from '../../Denormalizer/InvalidParameterByNameDenormalizer'; import PetFormProps from './PetFormProps'; @@ -22,25 +21,27 @@ const PetForm: React.FC = ({ submitPet, pet, error }: PetFormProps }; return ( -
- - - - - {vaccinations.fields.map((vaccination, i) => { - return ( -
- - - - -
- ); - })} - -
- - +
+
+ + +
+ +
+ {vaccinations.fields.map((item, i) => { + return ( +
+ + +
+ ); + })} + +
+
+ +
+
); }; diff --git a/src/Component/Form/PetFormProps.ts b/src/Component/Form/PetFormProps.ts index 63a9255..7a99a85 100644 --- a/src/Component/Form/PetFormProps.ts +++ b/src/Component/Form/PetFormProps.ts @@ -1,6 +1,6 @@ -import PetRequest from "../../Model/Pet/PetRequest"; -import PetResponse from "../../Model/Pet/PetResponse"; -import UnprocessableEntity from "../../Model/Error/UnprocessableEntity"; +import PetRequest from '../../Model/Pet/PetRequest'; +import PetResponse from '../../Model/Pet/PetResponse'; +import UnprocessableEntity from '../../Model/Error/UnprocessableEntity'; type PetFormProps = { submitPet: { (pet: PetRequest): void; }, diff --git a/src/Component/Form/TextField.tsx b/src/Component/Form/TextField.tsx index 68c7168..524f2e5 100644 --- a/src/Component/Form/TextField.tsx +++ b/src/Component/Form/TextField.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { Form } from 'semantic-ui-react'; import InvalidParameter from '../../Model/Error/InvalidParameter'; type Props = { @@ -11,13 +10,17 @@ type Props = { const TextField: React.FC = ({ register, name, label, invalidParameters }: Props) => { return ( - 0 ? 'error' : ''}> +
0 ? ' error' : ''}`}> - {invalidParameters && invalidParameters.map((invalidParameter: InvalidParameter, i) => ( -
{invalidParameter.reason}
- ))} - + {invalidParameters.length > 0 ? ( +
    + {invalidParameters.map((invalidParameter: InvalidParameter, i) => ( +
  • {invalidParameter.reason}
  • + ))} +
+ ) : ''} +
); }; diff --git a/src/Component/Navigation/Left.tsx b/src/Component/Navigation/Left.tsx deleted file mode 100644 index 298d70b..0000000 --- a/src/Component/Navigation/Left.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { NavLink } from 'react-router-dom'; - -const Left: React.FC = () => { - return ( - - ); -}; - -export default Left; - diff --git a/src/Component/Navigation/Top.tsx b/src/Component/Navigation/Top.tsx deleted file mode 100644 index d044412..0000000 --- a/src/Component/Navigation/Top.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useState } from 'react'; -import { NavLink } from 'react-router-dom'; - -const Top: React.FC = () => { - const [displayMenu, setDisplayMenu] = useState(false); - - const toggleMenu = () => { - setDisplayMenu(!displayMenu); - }; - - return ( - - ); -}; - -export default Top; diff --git a/src/Component/Page/Home.tsx b/src/Component/Page/Home.tsx index 8cb8178..9676e19 100644 --- a/src/Component/Page/Home.tsx +++ b/src/Component/Page/Home.tsx @@ -7,11 +7,9 @@ const Home: React.FC = () => { }, []); return ( -
-
-

Home

-
-
+
+

Home

+
); }; diff --git a/src/Component/Page/NotFound.tsx b/src/Component/Page/NotFound.tsx index 89eca02..c3e093f 100644 --- a/src/Component/Page/NotFound.tsx +++ b/src/Component/Page/NotFound.tsx @@ -7,11 +7,9 @@ const NotFound: React.FC = () => { }, []); return ( -
-
-

Not Found

-
-
+
+

Not Found

+
); }; diff --git a/src/Component/Page/Pet/Create.tsx b/src/Component/Page/Pet/Create.tsx index 780d914..55b5286 100644 --- a/src/Component/Page/Pet/Create.tsx +++ b/src/Component/Page/Pet/Create.tsx @@ -1,5 +1,4 @@ import React, { useState } from 'react'; -import { Button } from 'semantic-ui-react'; import { CreatePet } from '../../../ApiClient/Pet'; import { Link, useHistory } from 'react-router-dom'; import HttpError from '../../../Model/Error/HttpError'; @@ -29,22 +28,14 @@ const Create: React.FC = () => { }; return ( -
+
{httpError instanceof HttpError ? ( ) : ''} -
-

Create Pet

-
-
-
- -
-
-
- -
-
+

Create Pet

+ + List +
); }; diff --git a/src/Component/Page/Pet/List.tsx b/src/Component/Page/Pet/List.tsx index 9d43336..89d7f87 100644 --- a/src/Component/Page/Pet/List.tsx +++ b/src/Component/Page/Pet/List.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from 'react'; -import { Button, Pagination, PaginationProps } from 'semantic-ui-react'; import { de } from 'date-fns/locale'; import { format } from 'date-fns'; import { Link, useHistory, useLocation } from 'react-router-dom'; @@ -11,6 +10,7 @@ import PetResponse from '../../../Model/Pet/PetResponse'; import PetList from '../../../Model/Pet/PetList'; import qs from 'qs'; import PetFilterForm from '../../Form/PetFilterForm'; +import Pagination from '../../Partial/Pagination'; const List: React.FC = () => { @@ -20,11 +20,12 @@ const List: React.FC = () => { const query = qs.parse(location.search.substr(1)); const page = parseInt(query.page ? query.page : '1'); - const offset = (page * 10) - 10; + const perPage = 1; + const offset = (page * perPage) - perPage; const filters = query.filters ? query.filters : {}; const sort = query.sort ? query.sort : {}; - const queryString = qs.stringify({ limit: 10, offset: offset, filters: filters, sort: sort }); + const queryString = qs.stringify({ limit: perPage, offset: offset, filters: filters, sort: sort }); const [petList, setPetList] = useState(); const [httpError, setHttpError] = useState(); @@ -60,8 +61,8 @@ const List: React.FC = () => { fetchPetList(queryString); }; - const changePage = (e: any, data: PaginationProps) => { - history.push(`/pet?${qs.stringify({ ...query, page: data.activePage })}`); + const changePage = (page: number) => { + history.push(`/pet?${qs.stringify({ ...query, page: page })}`); }; const submitPetFilter = (filters: any) => { @@ -69,32 +70,22 @@ const List: React.FC = () => { }; if (!petList && !httpError) { - return (
); + return (
); } return ( -
+
{httpError instanceof HttpError ? ( ) : ''} -
-

List Pets

-
- {petList && petList._links.create ? ( -
- -
- ) : ''} - {petList ? ( -
-
- -
-
- ) : ''} +

List Pets

{petList ? ( -
- +
+ {petList._links.create ? ( + Create + ) : ''} + +
@@ -121,23 +112,23 @@ const List: React.FC = () => { ))}
Id{pet.tag} {pet._links.read ? ( - + Read ) : ''} {pet._links.update ? ( - + Update ) : ''} {pet._links.delete ? ( - + ) : ''}
- +
) : ''} -
+
); }; diff --git a/src/Component/Page/Pet/Read.tsx b/src/Component/Page/Pet/Read.tsx index 1a9c149..4d47ace 100644 --- a/src/Component/Page/Pet/Read.tsx +++ b/src/Component/Page/Pet/Read.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from 'react'; -import { Button, List } from 'semantic-ui-react'; import { de } from 'date-fns/locale'; import { format } from 'date-fns'; import { Link, RouteComponentProps } from 'react-router-dom'; @@ -35,53 +34,40 @@ const Read: React.FC = ({ match }: Props) => { }; if (!pet && !httpError) { - return (
); + return (
); } return ( -
+
{httpError instanceof HttpError ? ( ) : ''} -
-

Read Pet

-
+

Read Pet

{pet ? ( -
- - - Id - {pet.id} - - - CreatedAt - {format(Date.parse(pet.createdAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })} - - - UpdatedAt - {pet.updatedAt && format(Date.parse(pet.updatedAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })} - - - Name - {pet.name} - - - Tag - {pet.tag} - - - Vaccinations +
+
+
Id
+
{pet.id}
+
CreatedAt
+
{format(Date.parse(pet.createdAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })}
+
UpdatedAt
+
{pet.updatedAt && format(Date.parse(pet.updatedAt), 'dd.MM.yyyy - HH:mm:ss', { locale: de })}
+
Name
+
{pet.name}
+
Tag
+
{pet.tag}
+
Vaccinations
+
{pet.vaccinations.length > 0 ? (
    {pet.vaccinations.map((vaccination, i) => (
  • {vaccination.name}
  • ))}
) : ''} - - +
+
+ List
) : ''} -
- -
-
+ +
); }; diff --git a/src/Component/Page/Pet/Update.tsx b/src/Component/Page/Pet/Update.tsx index f9ecba1..2a2ce17 100644 --- a/src/Component/Page/Pet/Update.tsx +++ b/src/Component/Page/Pet/Update.tsx @@ -1,5 +1,4 @@ import React, { useState, useEffect } from 'react'; -import { Button } from 'semantic-ui-react'; import { Link, RouteComponentProps, useHistory } from 'react-router-dom'; import { ReadPet, UpdatePet } from '../../../ApiClient/Pet'; import HttpError from '../../../Model/Error/HttpError'; @@ -51,28 +50,20 @@ const Update: React.FC = ({ match }: Props) => { }; if (!pet && !httpError) { - return (
); + return (
); } return ( -
+
{httpError instanceof HttpError ? ( ) : ''} -
-

Update Pet

-
+

Update Pet

{pet ? ( -
-
- -
-
+ ) : ''} -
- -
-
+ List +
); }; diff --git a/src/Component/Partial/HttpError.tsx b/src/Component/Partial/HttpError.tsx index 9739de9..2df7824 100644 --- a/src/Component/Partial/HttpError.tsx +++ b/src/Component/Partial/HttpError.tsx @@ -1,28 +1,25 @@ import React from 'react'; -import { Message } from 'semantic-ui-react'; import HttpErrorType from '../../Model/Error/HttpError'; import HttpErrorWithInvalidArguments from '../../Model/Error/HttpErrorWithInvalidArguments'; import InvalidParameter from '../../Model/Error/InvalidParameter'; type Props = { - httpError: HttpErrorType + httpError: HttpErrorType; }; const HttpError: React.FC = ({ httpError }: Props) => { return ( -
- - {httpError.title} - {httpError.detail ? (

{httpError.detail}

): ''} - {httpError.instance ? (

{httpError.instance}

): ''} - {httpError instanceof HttpErrorWithInvalidArguments && httpError.invalidParameters.length > 0 ? ( -
    - {httpError.invalidParameters.map((invalidParameter: InvalidParameter, i) => ( -
  • {invalidParameter.name}: {invalidParameter.reason}
  • - ))} -
- ) : ''} -
+
+

{httpError.title}

+ {httpError.detail ? (

{httpError.detail}

) : ''} + {httpError.instance ? (

{httpError.instance}

) : ''} + {httpError instanceof HttpErrorWithInvalidArguments && httpError.invalidParameters.length > 0 ? ( +
    + {httpError.invalidParameters.map((invalidParameter: InvalidParameter, i) => ( +
  • {invalidParameter.name}: {invalidParameter.reason}
  • + ))} +
+ ) : ''}
); }; diff --git a/src/Component/Partial/Pagination.tsx b/src/Component/Partial/Pagination.tsx new file mode 100644 index 0000000..b8ff04e --- /dev/null +++ b/src/Component/Partial/Pagination.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import PaginationProps from './PaginationProps'; + +const Pagination: React.FC = ({ submitPage, currentPage, totalPages, maxPages }: PaginationProps) => { + if (totalPages <= 1 || maxPages <=1) { + return (
); + } + + const pages = [currentPage]; + for (let i = 1; ; i++) { + if (currentPage - i >= 1) { + pages.push(currentPage - i); + + if (pages.length === maxPages || pages.length === totalPages) { + break; + } + } + + if (currentPage + i <= totalPages) { + pages.push(currentPage + i); + + if (pages.length === maxPages || pages.length === totalPages) { + break; + } + } + } + + pages.sort(); + + return ( +
    + {currentPage > 2 ? ( +
  • + ) : ''} + {currentPage > 1 ? ( +
  • + ) : ''} + {pages.map((page: number) => ( +
  • + ))} + {currentPage < totalPages ? ( +
  • + ) : ''} + {currentPage < totalPages - 1 ? ( +
  • + ) : ''} +
+ ); +}; + +export default Pagination; diff --git a/src/Component/Partial/PaginationProps.ts b/src/Component/Partial/PaginationProps.ts new file mode 100644 index 0000000..d5ec272 --- /dev/null +++ b/src/Component/Partial/PaginationProps.ts @@ -0,0 +1,8 @@ +type PaginationProps = { + submitPage: { (page: number): void; }; + currentPage: number; + totalPages: number; + maxPages: number; +}; + +export default PaginationProps; diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index 5d0b438..4abcce8 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -1,22 +1,10 @@ import React from 'react'; import ReactRouterDom, { MemoryRouter } from 'react-router-dom'; -import { render } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import App from '../App'; ReactRouterDom.BrowserRouter = ({children}) =>
{children}
-jest.mock('../Component/Navigation/Left', () => { - return () => { - return (
); - }; -}); - -jest.mock('../Component/Navigation/Top', () => { - return () => { - return (
); - }; -}); - jest.mock('../Component/Page/Home', () => { return () => { return (
); @@ -53,6 +41,47 @@ jest.mock('../Component/Page/NotFound', () => { }; }); +test('toggle', async () => { + const { container, findByTestId } = render( + + + + ); + + const navigationToggle = await findByTestId('navigation-toggle'); + + fireEvent.click(navigationToggle); + + await findByTestId('navigation-toggle'); + + expect(container.outerHTML).toBe(` +
+
+
+ + +
+
+
+
+
+
+ `.replace(/\n {2,}/g, '')); +}); + test('home page', () => { const { container } = render( @@ -63,10 +92,23 @@ test('home page', () => { expect(container.outerHTML).toBe(`
-
-
-
-
+
+ + +
@@ -85,10 +127,23 @@ test('not found', () => { expect(container.outerHTML).toBe(`
-
-
-
-
+
+ + +
@@ -107,10 +162,23 @@ test('pet list', () => { expect(container.outerHTML).toBe(`
-
-
-
-
+
+ + +
@@ -129,10 +197,23 @@ test('pet create', () => { expect(container.outerHTML).toBe(`
-
-
-
-
+
+ + +
@@ -151,10 +232,23 @@ test('pet read', () => { expect(container.outerHTML).toBe(`
-
-
-
-
+
+ + +
@@ -173,10 +267,23 @@ test('pet update', () => { expect(container.outerHTML).toBe(`
-
-
-
-
+
+ + +
diff --git a/src/__tests__/Component/Form/PetFilterForm.test.tsx b/src/__tests__/Component/Form/PetFilterForm.test.tsx index 06d2dfd..945b1e9 100644 --- a/src/__tests__/Component/Form/PetFilterForm.test.tsx +++ b/src/__tests__/Component/Form/PetFilterForm.test.tsx @@ -16,14 +16,14 @@ test('without error', () => { expect(container.outerHTML).toBe(`
-
-
-
+ +
+
- -
+ +
`.replace(/\n {2,}/g, '')); @@ -49,15 +49,17 @@ test('with error', () => { expect(container.outerHTML).toBe(`
-
-
-
+ +
+
-
Should not be empty
+
    +
  • Should not be empty
  • +
- -
+ +
`.replace(/\n {2,}/g, '')); @@ -80,14 +82,14 @@ test('submit', async () => { expect(container.outerHTML).toBe(`
-
-
-
+ +
+
- -
+ +
`.replace(/\n {2,}/g, '')); @@ -112,14 +114,14 @@ test('submit empty', async () => { expect(container.outerHTML).toBe(`
-
-
-
+ +
+
- -
+ +
`.replace(/\n {2,}/g, '')); diff --git a/src/__tests__/Component/Form/PetForm.test.tsx b/src/__tests__/Component/Form/PetForm.test.tsx index db80321..e686acf 100644 --- a/src/__tests__/Component/Form/PetForm.test.tsx +++ b/src/__tests__/Component/Form/PetForm.test.tsx @@ -25,29 +25,31 @@ test('without error', () => { expect(container.outerHTML).toBe(`
-
-
- - -
-
- - -
-
- -
-
< - label>Name - -
-
- + +
+
+ + +
+
+ + +
+
+ +
+
+
+ + +
+ +
+
- -
- + +
`.replace(/\n {2,}/g, '')); @@ -81,31 +83,37 @@ test('with error', () => { expect(container.outerHTML).toBe(`
-
-
- - -
Should not be empty
-
-
- - -
-
- -
-
< - label>Name - -
Should not be empty
-
-
- + +
+
+ + +
    +
  • Should not be empty
  • +
+
+
+ + +
+
+ +
+
+
+ + +
    +
  • Should not be empty
  • +
+
+ +
+
- -
- + +
`.replace(/\n {2,}/g, '')); @@ -135,38 +143,38 @@ test('add vaccination', async () => { expect(container.outerHTML).toBe(`
-
-
- - -
-
- - -
-
- -
-
- - -
-
- -
+ +
+
+ +
-
-
- - -
-
- +
+ + +
+
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
- -
- + +
`.replace(/\n {2,}/g, '')); @@ -196,20 +204,24 @@ test('remove vaccination', async () => { expect(container.outerHTML).toBe(`
-
-
- - -
-
- - -
-
- - -
- + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+ +
`.replace(/\n {2,}/g, '')); @@ -236,20 +248,24 @@ test('submit minimal', async () => { expect(container.outerHTML).toBe(`
-
-
- - -
-
- - -
-
- - -
- + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+ +
`.replace(/\n {2,}/g, '')); @@ -282,29 +298,31 @@ test('submit maximal', async () => { expect(container.outerHTML).toBe(`
-
-
- - -
-
- - -
-
- -
-
< - label>Name - -
-
- + +
+
+ + +
+
+ + +
+
+ +
+
+
+ + +
+ +
+
- -
- + +
`.replace(/\n {2,}/g, '')); diff --git a/src/__tests__/Component/Form/TextField.test.tsx b/src/__tests__/Component/Form/TextField.test.tsx index 2de1066..6658ab1 100644 --- a/src/__tests__/Component/Form/TextField.test.tsx +++ b/src/__tests__/Component/Form/TextField.test.tsx @@ -16,10 +16,12 @@ test('default', () => { expect(container.outerHTML).toBe(`
-
+
-
Should not be empty
+
    +
  • Should not be empty
  • +
`.replace(/\n {2,}/g, '')); diff --git a/src/__tests__/Component/Navigation/Left.test.tsx b/src/__tests__/Component/Navigation/Left.test.tsx deleted file mode 100644 index f7e7e1f..0000000 --- a/src/__tests__/Component/Navigation/Left.test.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import Left from '../../../Component/Navigation/Left'; -import { MemoryRouter } from 'react-router-dom'; - -test('default', () => { - const { container } = render( - - - - ); - - expect(container.outerHTML).toBe(` -
- -
- `.replace(/\n {2,}/g, '')); -}); - -test('pet', () => { - const { container } = render( - - - - ); - - expect(container.outerHTML).toBe(` -
- -
- `.replace(/\n {2,}/g, '')); -}); diff --git a/src/__tests__/Component/Navigation/Top.test.tsx b/src/__tests__/Component/Navigation/Top.test.tsx deleted file mode 100644 index e9d3055..0000000 --- a/src/__tests__/Component/Navigation/Top.test.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import { fireEvent, render } from '@testing-library/react'; -import Top from '../../../Component/Navigation/Top'; -import { MemoryRouter } from 'react-router-dom'; - -test('default', () => { - const { container } = render( - - - - ); - - expect(container.outerHTML).toBe(` -
- -
- `.replace(/\n {2,}/g, '')); -}); - -test('pet', () => { - const { container } = render( - - - - ); - - expect(container.outerHTML).toBe(` -
- -
- `.replace(/\n {2,}/g, '')); -}); - -test('toggle', async () => { - const { container, findByTestId } = render( - - - - ); - - const toggle = await findByTestId('navigation-top-toggle'); - - fireEvent.click(toggle); - - await findByTestId('navigation-top-toggle'); - - expect(container.outerHTML).toBe(` -
- -
- `.replace(/\n {2,}/g, '')); -}); diff --git a/src/__tests__/Component/Page/Home.test.tsx b/src/__tests__/Component/Page/Home.test.tsx index dbe688a..844d75e 100644 --- a/src/__tests__/Component/Page/Home.test.tsx +++ b/src/__tests__/Component/Page/Home.test.tsx @@ -15,9 +15,9 @@ test('default', () => { expect(container.outerHTML).toBe(`
-
-

Home

-
+
+

Home

+
`.replace(/\n {2,}/g, '')); }); diff --git a/src/__tests__/Component/Page/NotFound.test.tsx b/src/__tests__/Component/Page/NotFound.test.tsx index 9414d1f..14cfa92 100644 --- a/src/__tests__/Component/Page/NotFound.test.tsx +++ b/src/__tests__/Component/Page/NotFound.test.tsx @@ -15,9 +15,9 @@ test('default', () => { expect(container.outerHTML).toBe(`
-
-

Not Found

-
+
+

Not Found

+
`.replace(/\n {2,}/g, '')); }); diff --git a/src/__tests__/Component/Page/Pet/Create.test.tsx b/src/__tests__/Component/Page/Pet/Create.test.tsx index 5cdd4f1..86a60a5 100644 --- a/src/__tests__/Component/Page/Pet/Create.test.tsx +++ b/src/__tests__/Component/Page/Pet/Create.test.tsx @@ -23,7 +23,7 @@ jest.mock('../../../../Component/Form/PetForm', () => { jest.mock('../../../../Component/Partial/HttpError', () => { return ({ httpError }: { httpError: HttpError; }) => { - return (
httpError: {httpError.title}
); + return (
httpError: {httpError.title}
); }; }); @@ -38,11 +38,11 @@ test('default', () => { expect(container.outerHTML).toBe(`
-
-

Create Pet

-
- -
+
+

Create Pet

+ + List +
`.replace(/\n {2,}/g, '')); }); @@ -68,12 +68,12 @@ test('unprocessable entity', async () => { expect(container.outerHTML).toBe(`
-
-
httpError: title
-

Create Pet

-
- -
+
+
httpError: title
+

Create Pet

+ + List +
`.replace(/\n {2,}/g, '')); }); diff --git a/src/__tests__/Component/Page/Pet/List.test.tsx b/src/__tests__/Component/Page/Pet/List.test.tsx index 92c07c6..8c52078 100644 --- a/src/__tests__/Component/Page/Pet/List.test.tsx +++ b/src/__tests__/Component/Page/Pet/List.test.tsx @@ -13,6 +13,7 @@ import Embedded from '../../../../Model/Pet/Embedded'; import PetResponse from '../../../../Model/Pet/PetResponse'; import Vaccination from '../../../../Model/Pet/Vaccination'; import Link from '../../../../Model/Link'; +import PaginationProps from '../../../../Component/Partial/PaginationProps'; jest.mock('../../../../ApiClient/Pet'); @@ -22,13 +23,31 @@ jest.mock('../../../../Component/Form/PetFilterForm', () => { await submitPetFilter({ name: 'Bro' }); }; - return (); + return (); }; }); jest.mock('../../../../Component/Partial/HttpError', () => { return ({ httpError }: { httpError: HttpError; }) => { - return (
httpError: {httpError.title}
); + return (
httpError: {httpError.title}
); + }; +}); + +jest.mock('../../../../Component/Partial/Pagination', () => { + return ({ submitPage, currentPage, totalPages, maxPages }: PaginationProps) => { + const submit = () => { + submitPage(2); + }; + + return ( + + ); }; }); @@ -49,10 +68,10 @@ test('bad request', async () => { expect(container.outerHTML).toBe(`
-
-
httpError: title
-

List Pets

-
+
+
httpError: title
+

List Pets

+
`.replace(/\n {2,}/g, '')); }); @@ -130,18 +149,24 @@ test('default', async () => { expect(container.outerHTML).toBe(`
-
-

List Pets

- -
-
- +
+

List Pets

+
+ Create + +
- + @@ -154,23 +179,16 @@ test('default', async () => {
Id CreatedAt UpdatedAtName ( A-Z | Z-A | --- ) + Name ( + A-Z | + Z-A | + --- + ) + Tag Actions
Brownie 0001-000 - Read - Update - + Read + Update +
- +
-
+
`.replace(/\n {2,}/g, '')); }); @@ -214,17 +232,23 @@ test('no actions', async () => { expect(container.outerHTML).toBe(`
-
-

List Pets

-
-
- +
+

List Pets

+
+ +
- + @@ -240,16 +264,9 @@ test('no actions', async () => {
Id CreatedAt UpdatedAtName ( A-Z | Z-A | --- ) + Name ( + A-Z | + Z-A | + --- + ) + Tag Actions
- +
-
+
`.replace(/\n {2,}/g, '')); }); @@ -327,27 +344,33 @@ test('submit bad request', async () => { ); - const testButton = await findByTestId('test-button'); + const testButton = await findByTestId('test-filter-button'); fireEvent.click(testButton); - await findByTestId('test-button'); + await findByTestId('test-filter-button'); expect(container.outerHTML).toBe(`
-
-
httpError: title
-

List Pets

- -
-
- +
+
httpError: title
+

List Pets

+
+ Create + +
- + @@ -360,23 +383,16 @@ test('submit bad request', async () => {
Id CreatedAt UpdatedAtName ( A-Z | Z-A | --- ) + Name ( + A-Z | + Z-A | + --- + ) + Tag Actions
Brownie 0001-000 - Read - Update - + Read + Update +
- +
-
+
`.replace(/\n {2,}/g, '')); }); @@ -450,17 +466,17 @@ test('submit filter', async () => { ); - const testButton = await findByTestId('test-button'); + const testButton = await findByTestId('test-filter-button'); fireEvent.click(testButton); - await findByTestId('test-button'); + await findByTestId('test-filter-button'); expect(history.location.pathname).toBe('/pet'); expect(history.location.search).toBe('?filters%5Bname%5D=Bro'); }); -test('next', async () => { +test('sort', async () => { const petList = new PetList({ offset: 0, limit: 1, @@ -523,7 +539,7 @@ test('next', async () => { const history = createMemoryHistory(); - const { findByText } = render( + const { findByTestId } = render( @@ -531,17 +547,17 @@ test('next', async () => { expect(history.location.pathname).toBe('/'); - const nextButton = await findByText('»'); + const sortNameDescLink = await findByTestId('sort-pet-name-desc'); - fireEvent.click(nextButton); + fireEvent.click(sortNameDescLink); - await findByText('»'); + await findByTestId('sort-pet-name-desc'); expect(history.location.pathname).toBe('/pet'); - expect(history.location.search).toBe('?page=2'); + expect(history.location.search).toBe('?sort%5Bname%5D=desc'); }); -test('sort', async () => { +test('next', async () => { const petList = new PetList({ offset: 0, limit: 1, @@ -612,14 +628,14 @@ test('sort', async () => { expect(history.location.pathname).toBe('/'); - const sortNameDescLink = await findByTestId('sort-pet-name-desc'); + const testButton = await findByTestId('test-pagination-button'); - fireEvent.click(sortNameDescLink); + fireEvent.click(testButton); - await findByTestId('sort-pet-name-desc'); + await findByTestId('test-pagination-button'); expect(history.location.pathname).toBe('/pet'); - expect(history.location.search).toBe('?sort%5Bname%5D=desc'); + expect(history.location.search).toBe('?page=2'); }); test('delete not found', async () => { @@ -703,19 +719,25 @@ test('delete not found', async () => { expect(container.outerHTML).toBe(`
-
-
httpError: title
-

List Pets

- -
-
- +
+
httpError: title
+

List Pets

+
+ Create + +
- + @@ -728,23 +750,16 @@ test('delete not found', async () => {
Id CreatedAt UpdatedAtName ( A-Z | Z-A | --- ) + Name ( + A-Z | + Z-A | + --- + ) + Tag Actions
Brownie 0001-000 - Read - Update - + Read + Update +
- +
-
+
`.replace(/\n {2,}/g, '')); }); @@ -854,18 +869,24 @@ test('delete success', async () => { expect(container.outerHTML).toBe(`
-
-

List Pets

- -
-
- +
+

List Pets

+
+ Create + +
- + @@ -873,16 +894,9 @@ test('delete success', async () => {
Id CreatedAt UpdatedAtName ( A-Z | Z-A | --- ) + Name ( + A-Z | + Z-A | + --- + ) + Tag Actions
- +
-
+
`.replace(/\n {2,}/g, '')); }); diff --git a/src/__tests__/Component/Page/Pet/Read.test.tsx b/src/__tests__/Component/Page/Pet/Read.test.tsx index 483cf39..a398615 100644 --- a/src/__tests__/Component/Page/Pet/Read.test.tsx +++ b/src/__tests__/Component/Page/Pet/Read.test.tsx @@ -13,7 +13,7 @@ jest.mock('../../../../ApiClient/Pet'); jest.mock('../../../../Component/Partial/HttpError', () => { return ({ httpError }: { httpError: HttpError; }) => { - return (
httpError: {httpError.title}
); + return (
httpError: {httpError.title}
); }; }); @@ -40,11 +40,10 @@ test('not found', async () => { expect(container.outerHTML).toBe(`
-
-
httpError: title
-

Read Pet

- -
+
+
httpError: title
+

Read Pet

+
`.replace(/\n {2,}/g, '')); }); @@ -78,35 +77,26 @@ test('minimal', async () => { expect(container.outerHTML).toBe(`
-
-

Read Pet

-
-
-
-
Id
- 4d783b77-eb09-4603-b99b-f590b605eaa9 -
-
-
CreatedAt
- 15.08.2005 - 17:52:01 -
-
-
UpdatedAt
-
-
-
Name
- Brownie -
-
-
Tag
-
-
-
Vaccinations
-
-
+
+

Read Pet

+
+
+
Id
+
4d783b77-eb09-4603-b99b-f590b605eaa9
+
CreatedAt
+
15.08.2005 - 17:52:01
+
UpdatedAt
+
+
Name
+
Brownie
+
Tag
+
+
Vaccinations
+
+
+ List
- -
+
`.replace(/\n {2,}/g, '')); }); @@ -145,40 +135,30 @@ test('maximal', async () => { expect(container.outerHTML).toBe(`
-
-

Read Pet

-
-
-
-
Id
- 4d783b77-eb09-4603-b99b-f590b605eaa9 -
-
-
CreatedAt
- 15.08.2005 - 17:52:01 -
-
-
UpdatedAt
- 15.08.2005 - 17:55:01 -
-
-
Name
- Brownie -
-
-
Tag
- 0001-000 -
-
-
Vaccinations
+
+

Read Pet

+
+
+
Id
+
4d783b77-eb09-4603-b99b-f590b605eaa9
+
CreatedAt
+
15.08.2005 - 17:52:01
+
UpdatedAt
+
15.08.2005 - 17:55:01
+
Name
+
Brownie
+
Tag
+
0001-000
+
Vaccinations
+
  • Rabies
-
-
+ + + List
- -
+
`.replace(/\n {2,}/g, '')); }); diff --git a/src/__tests__/Component/Page/Pet/Update.test.tsx b/src/__tests__/Component/Page/Pet/Update.test.tsx index 0b8f2ae..d1c4ea0 100644 --- a/src/__tests__/Component/Page/Pet/Update.test.tsx +++ b/src/__tests__/Component/Page/Pet/Update.test.tsx @@ -25,7 +25,7 @@ jest.mock('../../../../Component/Form/PetForm', () => { jest.mock('../../../../Component/Partial/HttpError', () => { return ({ httpError }: { httpError: HttpError; }) => { - return (
httpError: {httpError.title}
); + return (
httpError: {httpError.title}
); }; }); @@ -52,11 +52,11 @@ test('not found', async () => { expect(container.outerHTML).toBe(`
-
-
httpError: title
-

Update Pet

- -
+
+
httpError: title
+

Update Pet

+ List +
`.replace(/\n {2,}/g, '')); }); @@ -90,15 +90,11 @@ test('minimal', async () => { expect(container.outerHTML).toBe(`
-
-

Update Pet

-
-
-
-
- List -
-
+
+

Update Pet

+ + List +
`.replace(/\n {2,}/g, '')); }); @@ -144,16 +140,12 @@ test('unprocessable entity', async () => { expect(container.outerHTML).toBe(`
-
-
httpError: title
-

Update Pet

-
-
-
-
- List -
-
+
+
httpError: title
+

Update Pet

+ + List +
`.replace(/\n {2,}/g, '')); }); diff --git a/src/__tests__/Component/Partial/HttpError.test.tsx b/src/__tests__/Component/Partial/HttpError.test.tsx index bc69539..328c20e 100644 --- a/src/__tests__/Component/Partial/HttpError.test.tsx +++ b/src/__tests__/Component/Partial/HttpError.test.tsx @@ -12,10 +12,8 @@ test('minimal', () => { expect(container.outerHTML).toBe(`
-
-
-
This is the title
-
+
+

This is the title

`.replace(/\n {2,}/g, '')); @@ -35,15 +33,13 @@ test('maximal', () => { expect(container.outerHTML).toBe(`
-
-
-
This is the title
-

This is the detail

-

This is the instance

-
    -
  • Invalid Parameter Name: Invalid Parameter Reason
  • -
-
+
+

This is the title

+

This is the detail

+

This is the instance

+
    +
  • Invalid Parameter Name: Invalid Parameter Reason
  • +
`.replace(/\n {2,}/g, '')); diff --git a/src/index.css b/src/index.css index 4614d92..8ef8570 100644 --- a/src/index.css +++ b/src/index.css @@ -1,70 +1,325 @@ -body { - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: grayscale; +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, +body, +#root { + @apply w-full; + @apply h-full; +} + +#wrapper { + @apply flex; + @apply flex-col; + @apply min-h-full; + @apply relative; + + &.displayMenu > #left-nav { + @apply block; + } + + &.displayMenu > #main { + @apply mt-0; + } +} + +#top-nav { + @apply absolute; + @apply bg-gray-900; + @apply font-semibold; + @apply px-4; + @apply py-3; + @apply text-gray-100; + @apply uppercase; + @apply text-2xl; + @apply w-full; + @apply h-16; + @apply leading-relaxed; + + & a:hover { + @apply text-gray-500; + } +} + +#toggle { + @apply block; + @apply border-2; + @apply float-right; + @apply p-2; + + & span { + @apply block; + @apply border-t-2; + @apply h-2; + @apply w-6; + + &:last-child { + @apply h-0; + } + } + + &:hover { + @apply border-gray-500; + + & span { + @apply border-gray-500; + } + } +} + +#left-nav { + @apply bg-gray-200; + @apply hidden; + @apply w-full; + @apply mt-16; + + & ul > li > a { + @apply bg-gray-300; + @apply block; + @apply leading-none; + @apply px-4; + @apply py-3; + @apply text-gray-900; + + &:hover { + @apply bg-gray-400; + } + + &.active { + @apply text-gray-100; + @apply bg-gray-700; + + &:hover { + @apply bg-gray-600; + } + } + } + + &.visible { + @apply block; + } +} + +#main { + @apply mt-16; + @apply px-6; + @apply py-8; + @apply w-full; +} + +#httpError { + @apply bg-red-300; + @apply px-5; + @apply py-4; + @apply mb-6; + + & p:first-child { + @apply font-bold; + } } -#sidebar { - position: fixed; - height: 100vh; - background-color: #f5f5f5; - padding-top: 68px; - padding-left: 0; - padding-right: 0; +h1 { + @apply font-black; + @apply leading-none; + @apply text-4xl; + @apply border-b-2; + @apply pb-2; + @apply mb-4; } -#sidebar .ui.menu > a.item { - padding: 10px 20px; - line-height: 20px; - color: #337ab7; - border-radius: 0 !important; - margin-top: 0; - margin-bottom: 0; +fieldset { + @apply border; + @apply px-4; + @apply py-3; + @apply mb-3; } -#sidebar .ui.menu > a.item.active { - background-color: #337ab7; - color: white; - border: none !important; +.form-field { + @apply mb-3; + + &.error input[type="text"] { + @apply border-red-600; + @apply bg-red-100; + } + + & ul { + @apply text-red-600; + } } -#sidebar .ui.menu > a.item:hover { - background-color: #eee; - color: #23527c; +.form-field label { + @apply block; + @apply leading-none; + @apply mb-3; } -#content { - padding-top: 56px; - padding-left: 20px; - padding-right: 20px; +.form-field input[type="text"] { + @apply block; + @apply border; + @apply mb-3; + @apply px-3; + @apply py-2; + @apply w-full; } -#content h1 { - font-size: 36px; +.btn { + @apply inline-block; + @apply leading-none; + @apply px-5; + @apply py-3; + @apply text-gray-100; } -#content .ui.dividing.header { - width: 100%; +.btn-blue { + @apply btn; + @apply bg-blue-600; + + &:hover { + @apply bg-blue-700; + } } -.ui.centered.small.circular.image { - margin-top: 14px; - margin-bottom: 14px; +.btn-gray { + @apply btn; + @apply bg-gray-600; + + &:hover { + @apply bg-gray-700; + } } -.ui.borderless.menu { - box-shadow: none; - flex-wrap: wrap; - border: none; - padding-left: 0; - padding-right: 0; +.btn-green { + @apply btn; + @apply bg-green-600; + + &:hover { + @apply bg-green-700; + } } -.ui.mobile.only.grid .ui.menu .ui.vertical.menu { - display: none; +.btn-red { + @apply btn; + @apply bg-red-600; + + &:hover { + @apply bg-red-700; + } +} + +ul.pagination { + @apply my-4; + + & li { + @apply inline-block; + + & button { + @apply px-3; + @apply py-2; + @apply border-t; + @apply border-b; + @apply border-l; + @apply border-gray-500; + + &.current { + @apply bg-gray-300; + } + } + + &:last-child button { + @apply border-r; + } + } +} + +table { + @apply w-full; +} + +tr { + @apply block; + @apply border; + @apply mb-5; + + & > th, + &:nth-child(even) > td { + @apply bg-gray-100; + } +} + +th { + @apply text-left; +} + +th, +td { + @apply block; + @apply px-4; + + &:first-child { + @apply pt-3; + } + + &:last-child { + @apply pb-3; + } +} + +dt { + @apply font-bold; +} + +dd { + @apply mb-4; +} + +@screen md { + #wrapper { + @apply flex-row; + } + + #toggle { + @apply hidden; + } + + #left-nav { + @apply block; + @apply w-1/3; + } + + #main { + @apply w-2/3; + } + + tr { + @apply table-row; + @apply m-0; + } + + th, + td { + @apply px-4; + @apply py-3; + @apply table-cell; + } +} + +@screen lg { + #left-nav { + @apply w-1/4; + } + + #main { + @apply w-3/4; + } } -/* custom */ +@screen xl { + #left-nav { + @apply w-1/5; + } -.ui.mobile.only.grid .ui.menu .ui.vertical.menu.visible { - display: block; + #main { + @apply w-4/5; + } } diff --git a/src/index.tsx b/src/index.tsx index f3a7256..395b749 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import 'semantic-ui-css/semantic.min.css'; import './index.css'; import App from './App'; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..af829e2 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,7 @@ +module.exports = { + theme: { + extend: {}, + }, + variants: {}, + plugins: [], +}