diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7a9dfa0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6ac579c..7492d7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3163,6 +3163,84 @@ "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz", "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==" }, + "@emotion/cache": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.6.0.tgz", + "integrity": "sha512-ElbsWY1KMwEowkv42vGo0UPuLgtPYfIs9BxxVrmvsaJVvktknsHYYlx5NQ5g6zLDcOTyamlDc7FkRg2TAcQDKQ==", + "requires": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "^4.0.10" + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "@emotion/react": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.7.0.tgz", + "integrity": "sha512-WL93hf9+/2s3cA1JVJlz8+Uy6p6QWukqQFOm2OZO5ki51hfucHMOmbSjiyC3t2Y4RI8XUmBoepoc/24ny/VBbA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@emotion/cache": "^11.6.0", + "@emotion/serialize": "^1.0.2", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz", + "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "@emotion/serialize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", + "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", + "requires": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@emotion/utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz", + "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -3376,6 +3454,11 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@popperjs/core": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz", + "integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==" + }, "@sheerun/mutationobserver-shim": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz", @@ -3577,6 +3660,8 @@ }, "@testing-library/jest-dom": { "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-4.2.4.tgz", + "integrity": "sha512-j31Bn0rQo12fhCWOUWy9fl7wtqkp7In/YP2p5ZFyRuiiB9Qs3g+hS4gAmDWONbAHcRmVooNJ5eOHQDCOmUFXHg==", "requires": { "@babel/runtime": "^7.5.1", "chalk": "^2.4.1", @@ -3601,6 +3686,8 @@ }, "@testing-library/react": { "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-9.5.0.tgz", + "integrity": "sha512-di1b+D0p+rfeboHO5W7gTVeZDIK5+maEgstrZbWZSSvxDyfDRkkyBE1AJR5Psd6doNldluXlCWqXriUfqu/9Qg==", "requires": { "@babel/runtime": "^7.8.4", "@testing-library/dom": "^6.15.0", @@ -3608,7 +3695,9 @@ } }, "@testing-library/user-event": { - "version": "7.2.1" + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz", + "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" }, "@types/babel__core": { "version": "7.1.10", @@ -3735,6 +3824,14 @@ "@types/react": "*" } }, + "@types/react-transition-group": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "requires": { + "@types/react": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -5017,6 +5114,11 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bootstrap": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz", + "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5472,6 +5574,11 @@ } } }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -6472,6 +6579,15 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -8116,6 +8232,14 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.1.0.tgz", + "integrity": "sha512-zPuQgPacm2vH2xdORvGGz1wQMuHSIB56yNAy5FnLuwOwgSYyPKptJtcMm6Ev+hRGeS+GzhbmRacHzvlESbFwDg==", + "requires": { + "@babel/runtime": "^7.7.6" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -9842,6 +9966,11 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -12214,6 +12343,8 @@ }, "react": { "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", + "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -12420,6 +12551,8 @@ }, "react-dom": { "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", + "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -12432,11 +12565,30 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz", "integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==" }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, + "react-hook-form": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.20.4.tgz", + "integrity": "sha512-Nvy6TnNMlBoR+qS8FpA8lrqtGJ4uoi/MRYEgMEdBMY0HwHVuC7wB1sk6wTjg7FjOUt7QqMAP2W/vOhTWbKrtkQ==" + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-popper": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", + "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==", + "requires": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + } + }, "react-redux": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz", @@ -12449,8 +12601,27 @@ "react-is": "^16.9.0" } }, + "react-router": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.0.2.tgz", + "integrity": "sha512-8/Wm3Ed8t7TuedXjAvV39+c8j0vwrI5qVsYqjFr5WkJjsJpEvNSoLRUbtqSEYzqaTUj1IV+sbPJxvO+accvU0Q==", + "requires": { + "history": "^5.1.0" + } + }, + "react-router-dom": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.0.2.tgz", + "integrity": "sha512-cOpJ4B6raFutr0EG8O/M2fEoyQmwvZWomf1c6W2YXBZuFBx8oTk/zqjXghwScyhfrtnt0lANXV2182NQblRxFA==", + "requires": { + "history": "^5.1.0", + "react-router": "6.0.2" + } + }, "react-scripts": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.3.tgz", + "integrity": "sha512-oSnoWmii/iKdeQiwaO6map1lUaZLmG0xIUyb/HwCVFLT7gNbj8JZ9RmpvMCZ4fB98ZUMRfNmp/ft8uy/xD1RLA==", "requires": { "@babel/core": "7.9.0", "@svgr/webpack": "4.3.3", @@ -12528,6 +12699,64 @@ } } }, + "react-select": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.2.1.tgz", + "integrity": "sha512-OOyNzfKrhOcw/BlembyGWgdlJ2ObZRaqmQppPFut1RptJO423j+Y+JIsmxkvsZ4D/3CpOmwIlCvWbbAWEdh12A==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.1.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^5.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz", + "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, + "reactstrap": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-9.0.1.tgz", + "integrity": "sha512-89VOv7SRlAlpS7RwXhzOQkSWkuhBR8LBsPGfNHifNL3WhtNP9y1sBdTcTYyH1ee2QtI8zRdwD0T5I/blHiwemg==", + "requires": { + "@babel/runtime": "^7.12.5", + "@popperjs/core": "^2.6.0", + "classnames": "^2.2.3", + "prop-types": "^15.5.8", + "react-popper": "^2.2.4", + "react-transition-group": "^4.4.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz", + "integrity": "sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -12880,6 +13109,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", + "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" + }, "resolve": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", @@ -14223,6 +14457,11 @@ } } }, + "stylis": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.10.tgz", + "integrity": "sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg==" + }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -14961,6 +15200,14 @@ "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.7.4", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", diff --git a/package.json b/package.json index e00a0d2..e8b578c 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,17 @@ "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "axios": "^0.20.0", + "bootstrap": "^5.1.3", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-hook-form": "^7.20.4", "react-redux": "^7.2.1", + "react-router-dom": "^6.0.2", "react-scripts": "3.4.3", - "redux": "^4.0.5" + "react-select": "^5.2.1", + "reactstrap": "^9.0.1", + "redux": "^4.0.5", + "reselect": "^4.1.5" }, "scripts": { "start": "react-scripts start", diff --git a/public/images/ecobel.png b/public/images/ecobel.png new file mode 100644 index 0000000..6c19e02 Binary files /dev/null and b/public/images/ecobel.png differ diff --git a/src/application/actions/collection.js b/src/application/actions/collection.js new file mode 100644 index 0000000..5fcd5ca --- /dev/null +++ b/src/application/actions/collection.js @@ -0,0 +1,49 @@ +export const LOAD_All = '[all] load'; +export const LOAD_ALL_SUCCESS = '[all] load success'; +export const LOAD_ITEM_SUCCESS = '[one item] load success'; +export const LOAD_ALL_FAILURE = '[all] load failure'; +export const LOAD_ITEM = '[one item] load'; +export const SAVE_ITEM ='[one item] save'; + +export const TOGGLE_TAB= '[toggle tab of project] toggle '; + + +export const loadAll = collection => ({ + type: LOAD_All, + payload:collection, +}); + +export const load = (items)=> ({ + type: LOAD_ITEM, + payload: {id:items.id, items:items.table}, +}); + +export const loadItemSuccess = item => ({ + type: LOAD_ITEM_SUCCESS, + payload: item, +}); + + +export const loadAllSuccess = items => ({ + type: LOAD_ALL_SUCCESS, + payload: items, +}); + +export const loadAllFailure = error => ({ + type: LOAD_ALL_FAILURE, + payload: error, +}); + +export const toggleTab = tabId => ({ + type: TOGGLE_TAB, + payload: tabId, +}); + + +export const save = data => ({ + type: SAVE_ITEM, + payload: data, +}); + + + diff --git a/src/application/actions/permitActions.js b/src/application/actions/permitActions.js new file mode 100644 index 0000000..e436dcb --- /dev/null +++ b/src/application/actions/permitActions.js @@ -0,0 +1,46 @@ +export const LOAD_PERMIT = '[load permit]'; +export const LOAD_PERMIT_SUCCESS = '[permit loaded successfully]'; +export const SPLIT_PERMIT_SUCCESS = '[permit splitted successfully]'; +export const SPLIT_PERMIT = '[split Permit]'; +export const SPLIT_AND_SAVE = '[split and save]'; +export const SPLIT_AND_SAVE_SUCCESS = '[splited and saved successfylly]'; +export const SAVE_PERMIT = '[save permit]'; + +export const TOGGLE_TAB = '[change permit tab]'; + +export const load = id => ({ + type: LOAD_PERMIT, + payload: id, +}); + + +export const loadPermitSuccess = permit=> ({ + type: LOAD_PERMIT_SUCCESS, + payload: permit, +}); + +export const split = payload => ({ + type: SPLIT_PERMIT, + payload: payload, +}); + +export const splitPermitSuccess = permitItems=> ({ + type: SPLIT_PERMIT_SUCCESS, + payload: permitItems, +}); + +export const splitAndSave = payload => ({ + type: SPLIT_AND_SAVE, + payload: payload, +}); + +export const splitAndSavePermitSuccess = permitItems=> ({ + type: SPLIT_AND_SAVE_SUCCESS, + payload: permitItems, +}); + +export const toggleTab = tabId => ({ + type: TOGGLE_TAB, + payload: tabId, +}); + diff --git a/src/application/actions/projectActions.js b/src/application/actions/projectActions.js new file mode 100644 index 0000000..1574733 --- /dev/null +++ b/src/application/actions/projectActions.js @@ -0,0 +1,13 @@ +export const CREATE_ENVIRONMENT_MODULE = '[create environment module]'; +export const CREATE_SECURITY_MODULE = '[create security module]'; + + +export const createEnvironmentModule = payload => ({ + type: CREATE_ENVIRONMENT_MODULE, + payload: payload, +}); + +export const createSecurityModule = payload => ({ + type: CREATE_SECURITY_MODULE, + payload: payload, +}); \ No newline at end of file diff --git a/src/application/actions/ricActions.js b/src/application/actions/ricActions.js new file mode 100644 index 0000000..1e29744 --- /dev/null +++ b/src/application/actions/ricActions.js @@ -0,0 +1,28 @@ +export const LOAD_RIC = '[load ric]'; +export const LOAD_RIC_SUCCESS = '[load ric success]'; + +export const UPDATE_RIC_STATUS = '[update ric status]'; +export const UPDATE_RIC_STATUS_SUCCESS = '[update ric status success]' + +export const loadRic = projectid => ({ + type: LOAD_RIC, + payload: projectid, +}); + +export const loadRicSuccess = ric=> ({ + type: LOAD_RIC_SUCCESS, + payload: ric, +}); + +export const updateRicStatus =ric=>({ + type: UPDATE_RIC_STATUS, + payload: ric, +}); + +export const updateRicStatusSuccess =ric=>({ + type: UPDATE_RIC_STATUS_SUCCESS, + payload: ric, +}); + + + diff --git a/src/application/actions/todos.js b/src/application/actions/todos.js deleted file mode 100644 index 2168a4e..0000000 --- a/src/application/actions/todos.js +++ /dev/null @@ -1,29 +0,0 @@ -export const LOAD_TODOS = '[todos] load'; -export const LOAD_TODOS_SUCCESS = '[todos] load success'; -export const LOAD_TODOS_FAILURE = '[todos] load failure'; -export const SET_TODOS = '[todos] set'; -export const PUT_TODO = '[todos] put'; - -export const loadTodos = { - type: LOAD_TODOS, -}; - -export const loadTodosSuccess = todos => ({ - type: LOAD_TODOS_SUCCESS, - payload: todos, -}); - -export const loadTodosFailure = error => ({ - type: LOAD_TODOS_FAILURE, - payload: error, -}); - -export const setTodos = todos => ({ - type: SET_TODOS, - payload: todos, -}); - -export const putTodo = todo => ({ - type: PUT_TODO, - payload: todo, -}); \ No newline at end of file diff --git a/src/application/actions/ui.js b/src/application/actions/ui.js index 497d866..b8f7392 100644 --- a/src/application/actions/ui.js +++ b/src/application/actions/ui.js @@ -9,4 +9,4 @@ export const pageLoaded = { export const setLoading = isLoading => ({ type: isLoading ? SET_LOADING_ON : SET_LOADING_OFF, payload: isLoading, -}); \ No newline at end of file +}); diff --git a/src/application/middleware/collection.js b/src/application/middleware/collection.js new file mode 100644 index 0000000..46844c1 --- /dev/null +++ b/src/application/middleware/collection.js @@ -0,0 +1,64 @@ +import { loadAllFailure, loadAllSuccess,loadItemSuccess, LOAD_All, SAVE_ITEM, LOAD_ITEM, } from "../actions/collection"; +import * as uiActions from '../actions/ui'; + +const loadFlow = ({ api }) => ({ dispatch }) => next => async (action) => { + next(action); + +const loadAll = async ()=>{ + try { + //log('blabla'); + dispatch(uiActions.setLoading(true)); + const items = await api[action.payload].getAll(); + dispatch(loadAllSuccess(items)); + dispatch(uiActions.setLoading(false)); + } catch (error) { + dispatch(loadAllFailure(error)); + } +} + +const load = async ()=>{ + try { + dispatch(uiActions.setLoading(true)); + const item = await api[action.payload.items].get(action.payload.id); + dispatch(loadItemSuccess(item)); + dispatch(uiActions.setLoading(false)); + } catch (error) { + dispatch(loadAllFailure(error)); + } +} + +const save = async ()=>{ + try { + await api[action.payload.items].save(action.payload.data); + //dispatch(saveSuccess) + } catch (error) { + dispatch(loadAllFailure(error)); + } +} + + +switch(action.type) { + case LOAD_All: + loadAll(); + break; + case LOAD_ITEM: + load(); + break; + case SAVE_ITEM: + save(); + break; + default: + break; + } +} + + +/*const putProjectsFlow = () => ({ dispatch, getState }) => next => action => { + next(action); +}*/ + + + +export default [ + loadFlow, +] \ No newline at end of file diff --git a/src/application/middleware/companies.test.js b/src/application/middleware/companies.test.js new file mode 100644 index 0000000..264fda9 --- /dev/null +++ b/src/application/middleware/companies.test.js @@ -0,0 +1,43 @@ +// import { loadCompaniesSuccess, LOAD_COMPANIES } from '../actions/collection'; +// import companiesMiddleware from './companies'; + +// describe('companies middleware', () => { +// describe('load companies flow', () => { +// const [ loadCompaniesFlow ] = companiesMiddleware; + +// const dummyCompany = { +// id: '1', +// title: 'Dummy company', +// completed: true, +// }; +// const api = { +// companies: { +// getAll: jest.fn().mockImplementationOnce(() => new Promise((resolve) => resolve([dummyCompany]))) +// } +// } +// const dispatch = jest.fn(); +// const next = jest.fn(); +// const action = { +// type: LOAD_COMPANIES +// } + + +// it('passes action to next middleware', async () => { +// await loadCompaniesFlow({ api })({ dispatch })(next)(action); + +// expect(next).toHaveBeenCalledWith(action); +// }); + +// it('calls api.companies.getAll at least once', async () => { +// await loadCompaniesFlow({ api })({ dispatch })(next)(action); + +// expect(api.companies.getAll).toHaveBeenCalled(); +// });c + +// it('calls api.companies.getAll at least once', async () => { +// await loadCompaniesFlow({ api })({ dispatch })(next)(action); + +// expect(dispatch).toHaveBeenCalledWith(loadCompaniesSuccess([dummyCompany])); +// }); +// }); +// }); \ No newline at end of file diff --git a/src/application/middleware/index.js b/src/application/middleware/index.js index fcce8f7..35c1f04 100644 --- a/src/application/middleware/index.js +++ b/src/application/middleware/index.js @@ -1,7 +1,11 @@ import ui from './ui'; -import todos from './todos'; +import collection from './collection'; +import permit from './permitMiddleware'; +import ric from './ricMiddleware' export default [ ...ui, - ...todos, + ...collection, + ...permit, + ...ric ] \ No newline at end of file diff --git a/src/application/middleware/permitMiddleware.js b/src/application/middleware/permitMiddleware.js new file mode 100644 index 0000000..ea5db51 --- /dev/null +++ b/src/application/middleware/permitMiddleware.js @@ -0,0 +1,71 @@ +import * as uiActions from '../actions/ui'; +import { loadPermitSuccess, splitPermitSuccess,splitAndSavePermitSuccess, + LOAD_PERMIT,SPLIT_PERMIT, SAVE_PERMIT, SPLIT_AND_SAVE } from "../actions/permitActions"; + + + +const permitFlow = ({ api }) => ({ dispatch }) => next => async (action) => { + next(action); + +const load = async ()=>{ + try { + dispatch(uiActions.setLoading(true)) + const permit = await api.permits.get(action.payload); + dispatch(loadPermitSuccess(permit)); + dispatch(uiActions.setLoading(false)); + } catch (error) { + //dispatch(loadAllFailure(error)); + } +} + +const save = async ()=>{ + try { + await api.permits.save(action.payload.data); + //dispatch (Saved) + } catch (error) { + // dispatch(loadAllFailure(error)); + } +} + +const split = async ()=>{ + try { + const permitItems= await api.permits.split(action.payload); + dispatch(splitPermitSuccess(permitItems)); + + } catch (error) { + // dispatch(loadAllFailure(error)); + } +} + +const splitAndSave = async ()=>{ + try { + const permitItems= await api.permits.splitAndSave(action.payload); + dispatch(splitAndSavePermitSuccess(permitItems)); + + } catch (error) { + // dispatch(loadAllFailure(error)); + } +} + + +switch(action.type) { + case LOAD_PERMIT: + load(); + break; + case SPLIT_PERMIT: + split(); + break; + case SPLIT_AND_SAVE: + splitAndSave(); + break; + case SAVE_PERMIT: + save(); + break; + default: + break; + } +} + +export default [ + permitFlow +] \ No newline at end of file diff --git a/src/application/middleware/ricMiddleware.js b/src/application/middleware/ricMiddleware.js new file mode 100644 index 0000000..688219c --- /dev/null +++ b/src/application/middleware/ricMiddleware.js @@ -0,0 +1,48 @@ + +import { loadRicSuccess, updateRicStatusSuccess, LOAD_RIC, UPDATE_RIC_STATUS } from '../actions/ricActions'; +import * as uiActions from '../actions/ui'; + + + +const ricFlow = ({ api }) => ({ dispatch }) => next => async (action) => { + next(action); + + const loadRic = async ()=>{ + try { + dispatch(uiActions.setLoading(true)) + const ric = await api.projects.getRic(action.payload); + dispatch(loadRicSuccess(ric)); + dispatch(uiActions.setLoading(false)); + } catch (error) { + //dispatch(loadAllFailure(error)); + } + } + + const updateStatus = async()=>{ + try{ + await api.ric.updateStatus(action.payload); + dispatch(updateRicStatusSuccess(action.payload)); + } + catch (error) { + //dispatch(loadAllFailure(error)); + } + } + + switch(action.type) { + case LOAD_RIC: + loadRic(); + break; + case UPDATE_RIC_STATUS: + updateStatus(); + break; + default: + break; + } + + + +} + +export default [ + ricFlow +] \ No newline at end of file diff --git a/src/application/middleware/todos.js b/src/application/middleware/todos.js deleted file mode 100644 index 4f1e5cb..0000000 --- a/src/application/middleware/todos.js +++ /dev/null @@ -1,39 +0,0 @@ -import { loadTodosFailure, loadTodosSuccess, LOAD_TODOS, PUT_TODO, setTodos } from "../actions/todos"; -import * as uiActions from '../actions/ui'; - -const loadTodosFlow = ({ api }) => ({ dispatch }) => next => async (action) => { - next(action); - - if (action.type === LOAD_TODOS) { - try { - dispatch(uiActions.setLoading(true)); - const todos = await api.todos.getAll(); - dispatch(loadTodosSuccess(todos)); - dispatch(uiActions.setLoading(false)); - } catch (error) { - dispatch(loadTodosFailure(error)); - } - } -} - -const putTodoFlow = () => ({ dispatch, getState }) => next => action => { - - if (action.type === PUT_TODO) { - const oldTodosClone = getState().todos.allTodos.map(todo => ({...todo})); - - const newTodo = action.payload; - - const index = oldTodosClone.findIndex(todo => todo.id === newTodo.id); - - oldTodosClone[index] = newTodo; - - dispatch(setTodos(oldTodosClone)); - } - - next(action); -} - -export default [ - loadTodosFlow, - putTodoFlow, -] \ No newline at end of file diff --git a/src/application/middleware/todos.test.js b/src/application/middleware/todos.test.js deleted file mode 100644 index 3ff7717..0000000 --- a/src/application/middleware/todos.test.js +++ /dev/null @@ -1,43 +0,0 @@ -import { loadTodosSuccess, LOAD_TODOS } from '../actions/todos'; -import todosMiddleware from './todos'; - -describe('todos middleware', () => { - describe('load todos flow', () => { - const [ loadTodosFlow ] = todosMiddleware; - - const dummyTodo = { - id: '1', - title: 'Dummy todo', - completed: true, - }; - const api = { - todos: { - getAll: jest.fn().mockImplementationOnce(() => new Promise((resolve) => resolve([dummyTodo]))) - } - } - const dispatch = jest.fn(); - const next = jest.fn(); - const action = { - type: LOAD_TODOS - } - - - it('passes action to next middleware', async () => { - await loadTodosFlow({ api })({ dispatch })(next)(action); - - expect(next).toHaveBeenCalledWith(action); - }); - - it('calls api.todos.getAll at least once', async () => { - await loadTodosFlow({ api })({ dispatch })(next)(action); - - expect(api.todos.getAll).toHaveBeenCalled(); - }); - - it('calls api.todos.getAll at least once', async () => { - await loadTodosFlow({ api })({ dispatch })(next)(action); - - expect(dispatch).toHaveBeenCalledWith(loadTodosSuccess([dummyTodo])); - }); - }); -}); \ No newline at end of file diff --git a/src/application/middleware/ui.js b/src/application/middleware/ui.js index d5a3a4e..a23492f 100644 --- a/src/application/middleware/ui.js +++ b/src/application/middleware/ui.js @@ -1,12 +1,11 @@ import { PAGE_LOADED } from "../actions/ui"; -import * as todosActions from '../actions/todos'; + const pageLoadedFlow = ({ log }) => ({ dispatch }) => next => action => { next(action); if (action.type === PAGE_LOADED) { log('page loaded'); - dispatch(todosActions.loadTodos); } } diff --git a/src/application/reducers/collectionReducer.js b/src/application/reducers/collectionReducer.js new file mode 100644 index 0000000..511fc8c --- /dev/null +++ b/src/application/reducers/collectionReducer.js @@ -0,0 +1,23 @@ +import { LOAD_ALL_SUCCESS,LOAD_ITEM_SUCCESS, TOGGLE_TAB } from "../actions/collection"; + +const initialState = { + all: [], + selected:null, + activeTab:"general", + error: null +}; + +const reducer = (state = initialState, action) => { + switch (action.type) { + case LOAD_ALL_SUCCESS: + return {...state, all: action.payload, error: null, selected:null }; + case LOAD_ITEM_SUCCESS: + return {...state, selected: action.payload, error: null, activeTab:"general"}; + case TOGGLE_TAB: + return {...state,activeTab:action.payload}; + default: + return state; + } +} + +export default reducer; \ No newline at end of file diff --git a/src/application/reducers/index.js b/src/application/reducers/index.js index a916dd1..290896c 100644 --- a/src/application/reducers/index.js +++ b/src/application/reducers/index.js @@ -1,8 +1,12 @@ import { combineReducers } from 'redux'; import ui from './ui'; -import todos from './todos'; +import collectionReducer from './collectionReducer'; +import permitReducer from './permitReducer'; +import ricReducer from './ricReducer'; export default combineReducers({ ui, - todos, + collectionReducer, + permitReducer, + ricReducer, }) \ No newline at end of file diff --git a/src/application/reducers/permitReducer.js b/src/application/reducers/permitReducer.js new file mode 100644 index 0000000..26946ee --- /dev/null +++ b/src/application/reducers/permitReducer.js @@ -0,0 +1,36 @@ +import { LOAD_PERMIT_SUCCESS, TOGGLE_TAB,SPLIT_PERMIT_SUCCESS, SPLIT_AND_SAVE_SUCCESS } from "../actions/permitActions"; + +const initialState = { + permit:null, + contextOptions:null, + contexts:null, + authorities:null, + + activeTab:"general", + error: null, + items:null +}; + +const reducer = (state = initialState, action) => { + switch (action.type) { + case LOAD_PERMIT_SUCCESS: + return {...state, + permit: action.payload.permit, + contextOptions:action.payload.contextOptions, + contexts:action.payload.contexts, + authorities:action.payload.authorities, + items : action.payload.permitItems, + + error: null, activeTab:"general"}; + case SPLIT_PERMIT_SUCCESS: + return {...state, error: null,items:action.payload.permitItems, activeTab:"detail"}; + case SPLIT_AND_SAVE_SUCCESS: + return {...state, error: null,items:action.payload, activeTab:"detail"}; + case TOGGLE_TAB: + return {...state,activeTab:action.payload}; + default: + return state; + } +} + +export default reducer; \ No newline at end of file diff --git a/src/application/reducers/ricReducer.js b/src/application/reducers/ricReducer.js new file mode 100644 index 0000000..3eec09e --- /dev/null +++ b/src/application/reducers/ricReducer.js @@ -0,0 +1,33 @@ + +import {LOAD_RIC_SUCCESS, UPDATE_RIC_STATUS_SUCCESS} from '../actions/ricActions' + +const initialState = { + ric:[], + statusOptions:null, + error: null, +}; + + +const reducer = (state = initialState, action) => { + switch (action.type) { + case LOAD_RIC_SUCCESS: + return {...state, + ric: action.payload.ric, + statusOptions:action.payload.statusOptions, + //error: null, + } + case UPDATE_RIC_STATUS_SUCCESS: + const newRic = [...state.ric] + const item = newRic.find(s => s.codeId == action.payload.codeId); + if(item.statusId !==action.payload.statusId) + { + item.statusId=action.payload.statusId; + return {...state, ric:newRic} + } + return state; + default: + return state; + } +} + +export default reducer; \ No newline at end of file diff --git a/src/application/reducers/todos.js b/src/application/reducers/todos.js deleted file mode 100644 index ccb0f50..0000000 --- a/src/application/reducers/todos.js +++ /dev/null @@ -1,19 +0,0 @@ -import { LOAD_TODOS_SUCCESS, SET_TODOS } from "../actions/todos"; - -const initialState = { - allTodos: [], - error: null -}; - -const reducer = (state = initialState, action) => { - switch (action.type) { - case LOAD_TODOS_SUCCESS: - return { allTodos: action.payload, error: null }; - case SET_TODOS: - return { allTodos: action.payload, error: null }; - default: - return state; - } -} - -export default reducer; \ No newline at end of file diff --git a/src/application/reducers/ui.js b/src/application/reducers/ui.js index b761b02..e14455f 100644 --- a/src/application/reducers/ui.js +++ b/src/application/reducers/ui.js @@ -10,6 +10,6 @@ export default (state = initialState, action) => { case (uiActions.SET_LOADING_OFF): return { ...state, loading: action.payload }; default: - return state; + return state } } \ No newline at end of file diff --git a/src/application/selectors/collection.js b/src/application/selectors/collection.js new file mode 100644 index 0000000..abe7402 --- /dev/null +++ b/src/application/selectors/collection.js @@ -0,0 +1,3 @@ +export const getItemsSelector = state => state.collectionReducer.all; +export const getItemSelector = state => state.collectionReducer.selected; +export const getActiveTabSelector = state => state.collectionReducer.activeTab; \ No newline at end of file diff --git a/src/application/selectors/permits.js b/src/application/selectors/permits.js new file mode 100644 index 0000000..c53eb56 --- /dev/null +++ b/src/application/selectors/permits.js @@ -0,0 +1,8 @@ +export const getPermitItems = state => state.permitReducer.items; +export const getPermit = state => state.permitReducer.permit; +export const getActiveTabSelector= state=> state.permitReducer.activeTab; +export const getAuthorities = state => state.permitReducer.authorities; +export const getContextOptions = state => state.permitReducer.contextOptions; +export const getContexts = state => state.permitReducer.contexts; + + diff --git a/src/application/selectors/ricSelector.js b/src/application/selectors/ricSelector.js new file mode 100644 index 0000000..0c298f1 --- /dev/null +++ b/src/application/selectors/ricSelector.js @@ -0,0 +1,15 @@ + +import { createSelector } from 'reselect' + +export const getStatusOptions = state => state.ricReducer.statusOptions; +export const getRic = state => state.ricReducer.ric; +export const getError = state => state.ricReducer.error; + +const selectItems = state => state.ricReducer.ric; +const selectItemId = (_,itemId) => itemId + + +export const selectItemById= createSelector( + selectItems, selectItemId, + (items, id) => {return items[id];} + ) \ No newline at end of file diff --git a/src/application/selectors/todos.js b/src/application/selectors/todos.js deleted file mode 100644 index d43f6f0..0000000 --- a/src/application/selectors/todos.js +++ /dev/null @@ -1 +0,0 @@ -export const getTodos = state => state.todos.allTodos; \ No newline at end of file diff --git a/src/assets/env.png b/src/assets/env.png new file mode 100644 index 0000000..6bc10b0 Binary files /dev/null and b/src/assets/env.png differ diff --git a/src/assets/secu.png b/src/assets/secu.png new file mode 100644 index 0000000..450d542 Binary files /dev/null and b/src/assets/secu.png differ diff --git a/src/components/Permit/Detail.js b/src/components/Permit/Detail.js new file mode 100644 index 0000000..091febc --- /dev/null +++ b/src/components/Permit/Detail.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { Table } from 'reactstrap'; +import './Detail.module.css'; + +export default (props)=>{ + +const {permitItems} = props + const Head = () => ( + Sequence + Description + Comment + Aspect + Codes + ); + return (permitItems !== undefined &&
+ + + + + + {permitItems.map((item, index) => { + return ( + + + + + + + ) + })} + +
{item.sequence} + + {item.headers.map((header, key) => { + return ( + React.createElement("h"+ (header.level +1),'',header.content) + + ) + })} + + +

{item.description}

+
{item.comment}{item.aspect}
+
+ ); +} diff --git a/src/components/Permit/Detail.module.css b/src/components/Permit/Detail.module.css new file mode 100644 index 0000000..2edfed5 --- /dev/null +++ b/src/components/Permit/Detail.module.css @@ -0,0 +1,6 @@ +h1 { + color: rgba(4, 83, 15, 0.959); + font-size: 10px; +} + + diff --git a/src/components/Permit/General.js b/src/components/Permit/General.js new file mode 100644 index 0000000..bd96097 --- /dev/null +++ b/src/components/Permit/General.js @@ -0,0 +1,130 @@ +import React, {useEffect} from 'react' +import { DropDown } from '../../components/boxes/DropDown'; +import Multiselect from "../../components/boxes/MultiSelect"; +import * as itemsActions from '../../application/actions/collection'; +import * as permitActions from '../../application/actions/permitActions'; + +export default (props)=> { + + const {dispatch, + permit, + authorities, + contextOptions, + contexts, + register, + handleSubmit, + setValue, + getValues, + control }= props; + + const onSubmit = data => { + dispatch(itemsActions.save({data:data, items:'permits'})); + } + + const onSplit = data => { + dispatch(permitActions.split(data)); + } + + const onSplitAndSave = data =>{ + dispatch(permitActions.splitAndSave(data)); + } + + useEffect(()=>{ + if(permit!==null) + { + //use this: + // reset(permit); + //or this, but not both!! + setValue('description', permit.description, ) + setValue('contexts', contexts.map(p=>p.value)) + setValue('authorityId', permit.authorityId) + setValue('subject', permit.subject) + setValue('projectId',permit.projectId) + setValue('permitId',permit.id) + setValue('rawContent', permit.rawContent) + }; + },[setValue,permit, contexts]); + + + return(<> +
+
+
+ +